示例表:
drop table if exists my_table;
create table my_table(id int primary key, title text);
insert into my_table values
(1, 'lorem ipsum'),
(2, 'IPSUM LOREM'),
(3, 'lorem dolor ipsum');
为每个 id 选择有序的不区分大小写的单词数组:
select id, title, array_agg(word order by word) as words
from (
select id, lower(regexp_split_to_table(title, '\s+')) word
from my_table
) s
join my_table using(id)
group by 1, 2;
id | title | words
----+-------------------+---------------------
1 | lorem ipsum | {ipsum,lorem}
2 | IPSUM LOREM | {ipsum,lorem}
3 | lorem dolor ipsum | {dolor,ipsum,lorem}
(3 rows)
使用此结果通过简单的相等运算符查找匹配对:
with ordered_words as (
select id, title, array_agg(word order by word) as words
from (
select id, lower(regexp_split_to_table(title, '\s+')) word
from my_table
) s
join my_table using(id)
group by 1, 2
)
select t1.title, t1.id, t2.title, t2.id
from ordered_words t1
join ordered_words t2 on t1.id < t2.id and t1.words = t2.words;
title | id | title | id
-------------+----+-------------+----
lorem ipsum | 1 | IPSUM LOREM | 2
(1 row)
注意,在连接条件中,我使用< 代替ids 而不是!=,以按相反顺序消除重复项。
替代解决方案 - 在您的查询中添加 lower() 和 对称 比较:
select t1.title, t1.id, t2.title, t2.id
from my_table t1
join my_table t2
on t1.id < t2.id
and string_to_array(lower(t1.title), ' ') <@ string_to_array(lower(t2.title), ' ')
and string_to_array(lower(t1.title), ' ') @> string_to_array(lower(t2.title), ' ');
这个查询看起来比上一个更简单,但实际上效率要低得多。