PostgreSQL选择逗号分隔值列的不同值,不包括子集

时间:2018-05-28 22:45:59

标签: sql postgresql

假设有一个表 foo ,列 bar 带有逗号分隔值('a,b',           'a,b,c',           'A B C D' ,           'd,E')  如何选择最大的组合并排除该组合中包含的所有子集(最大的一个):

上述数据集的示例,结果应为:

('a,b,c,d','d,e')和前两个实体('a,b','a,b,c') 被排除在外,因为它们是('a,b,c,d')的子集。

考虑到逗号分隔字符串中的所有值都按字母顺序排序

我尝试了以下查询,但结果似乎与我的需求相差甚远:

select distinct a.bar from foo a   inner join foo b
on a.bar like '%'|| b.bar||'%' 
and a.bar != b.bar

2 个答案:

答案 0 :(得分:1)

您可以使用string_to_array()将字符串拆分为数组。使用包含运算符@>,您可以检查数组是否包含另一个。 (见"9.18. Array Functions and Operators"。)

NOT EXISTS子句中使用它。 fi.ctid <> fo.ctid用于确保比较的行对的物理地址不相等,当然,一行的数组将包含与同一行相比的数组。

SELECT fo.bar
       FROM foo fo
       WHERE NOT EXISTS (SELECT *
                                FROM foo fi
                                WHERE fi.ctid <> fo.ctid
                                      AND string_to_array(fi.bar, ',') @> string_to_array(fo.bar, ','));

SQL Fiddle

但是我无法抗拒:不要在关系数据库中使用逗号分隔的字符串。你有更好的方法。它被称为“桌子”。

答案 1 :(得分:0)

首先将字符串处理成字符集,然后将字符集与自身交叉连接,排除两边字符集相同的行。

接下来,聚合&amp;在BOOL_OR子句中使用HAVING来过滤掉任何其他字符集子集的任何字符集

使用cte中显示的样本表,查询变为:

WITH foo(bar) AS (SELECT '("a,b" , "a,b,c" , "a,b,c,d" , "d,e")'::TEXT)
SELECT bar, string_to_array(elems[1], ',') not_subset
FROM foo
CROSS JOIN regexp_matches(bar, '[\w|,]+', 'g') elems 
CROSS JOIN regexp_matches(bar, '[\w|,]+', 'g') elems2
WHERE elems2[1] != elems[1] 
  -- my regex also matches the ',' between sets which need to be ignored
  -- alternatively, i have to refine the regex
  AND elems2[1] != ','
  AND elems[1] != ','
GROUP BY 1, 2
HAVING NOT BOOL_OR(string_to_array(elems[1], ',') <@ string_to_array(elems2[1], ','))

产生输出

bar                                     not_subset
'("a,b" , "a,b,c" , "a,b,c,d" , "d,e")' {'d','e'}
'("a,b" , "a,b,c" , "a,b,c,d" , "d,e")' {'a','b','c','d'}

example in sql fiddle