【问题标题】:postgres find all rows with the same words in a columnpostgres 在列中查找所有具有相同单词的行
【发布时间】:2017-03-27 16:44:59
【问题描述】:

尝试查找列中具有相同单词的所有行(及其计数)。匹配的标准是字符串B的所有单词中是否存在字符串A中的所有单词(不注意大小写和单词顺序)。例如。 'lorem ipsum' == 'ipsum LOrem'。我尝试了下一个查询:

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(t1.title, ' ') <@ string_to_array(t2.title, ' ');

但它只包括部分匹配,例如'lorem dolor ipsum' == 'ipsum LOrem' 转化为结果。

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    示例表:

    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) 
    

    注意,在连接条件中,我使用&lt; 代替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), ' ');
    

    这个查询看起来比上一个更简单,但实际上效率要低得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-18
      相关资源
      最近更新 更多