I suggest a single SELECT in a plain SQL function:
CREATE OR REPLACE FUNCTION strings_equivalent(a text, b text)
RETURNS bool AS
$func$
SELECT a1 = b1
FROM (
SELECT string_agg(w, ' ') AS a1
FROM (
SELECT w
FROM unnest(string_to_array(a, ' ')) w
ORDER BY w
) a1
) a2
, (
SELECT string_agg(w, ' ') AS b1
FROM (
SELECT w
FROM unnest(string_to_array(b, ' ')) w
ORDER BY w
) b1
) b2
WHERE length(a) = length(b)
UNION ALL
SELECT FALSE
LIMIT 1; -- for clarity, not needed
$func$ LANGUAGE sql IMMUTABLE;
Call:
SELECT strings_equivalent('this is a test number 01', 'number this is 01 a test');
This is assuming:
- Duplicate words count like any other words
- Separator is a single space
- No leading or trailing spaces
The function returns NULL for any empty string or NULL input.
The UNION ALL
construct is a shortcut to return FALSE
immediately if the input strings don't have the same length and avoid more expensive processing. Related:
LIMIT 1
is not needed because the function only returns the first column of the first row anyway and ignores the rest if there are more rows.
IMMUTABLE
(since the result never changes for the same input) helps performance with repeated evaluation and allows indexes on functional expressions.
You could use regexp_split_to_table(a, ' ')
instead of unnest(string_to_array(a, ' '))
, but regular expression functions are typically more expensive. (You can cover more sophisticated separator characters with the regex, though, like '\s+'
for any white space). Related:
BTW, your simple function sort_text()
looks good. But use string_agg()
instead of array_to_string(ARRAY(...))
in a simple SQL function. No variable assignment needed:
CREATE OR REPLACE FUNCTION sort_text(a text)
RETURNS text AS
$$
SELECT string_agg(w, ' ')
FROM (
SELECT w
FROM unnest(string_to_array(a, ' ')) w
ORDER BY 1
) sub
$$ LANGUAGE sql IMMUTABLE;
This has been fixed in version 10, as seen in the docs, Type Conversions:
SELECT
Output Columns
The rules given in the preceding sections will result in assignment of non-unknown data types to all expressions in a SQL query, except for unspecified-type literals that appear as simple output columns of a SELECT
command. For example, in
SELECT 'Hello World';
there is nothing to identify what type the string literal should be taken as. In this situation PostgreSQL will fall back to resolving the literal's type as text
.
...
Note
Prior to PostgreSQL 10, this rule did not exist, and unspecified-type literals in a SELECT
output list were left as type unknown
. That had assorted bad consequences, so it's been changed.
The solutions for you are pretty straight forward:
Either cast the values to text
or upgrade to version 10.
Best Answer
Considering your table has some ID column, you can get it this way:
db<>fiddle here