比较PostgreSQL中两个逗号分隔的列

时间:2019-03-19 10:07:46

标签: sql arrays postgresql

我有两个表,其中的一列包含逗号分隔的数据。我需要比较两个列。逗号分隔的字段可以按任何顺序排列,但顺序无关紧要。

# stubs for FactoryGirl's magic methods for Rubymine
def create(*_args) end
def create_list(*_args) end
def build(*_args) end
def build_stubbed(*_args) end

我在下面的查询中使用了它,但是它没有返回任何输出:

create table x_a (id1 integer, shared text);
create table x_b (id1 integer, shared text);

insert into x_a values 
  (1, 'A,B,C,D,E')
, (2, 'A,B,C,D,E');

insert into x_b values 
  (1, 'B,A,C,E,D')
, (2, 'B,A,C,E');

我无法使用运算符select a.id1,b.id1, a.shared, b.shared from x_a a ,x_b b where a.id1 = b.id1 and regexp_split_to_array(LOWER(a.shared),',') = regexp_split_to_array(LOWER(b.shared),',') ,因为它将返回&&,这是错误的,因为“共享”列不是确切的副本。

2 个答案:

答案 0 :(得分:2)

  

我无法使用运算符&&,因为它将返回id=2,这是错误的...

但是您可以像这样使用array operators @> and <@

SELECT id1, a.shared AS a_shared, b.shared AS b_shared
FROM   x_a a
JOIN   x_b b USING (id1)
WHERE  string_to_array(a.shared, ',') @> string_to_array(b.shared, ',')
AND    string_to_array(a.shared, ',') <@ string_to_array(b.shared, ',');

如果A包含B,而B包含A,则两者都是等于-忽略重复项。

您可能想存储(排序的)数组开头-或通过1:n关系规范化数据库设计。

如果您的元素是integer数字,请考虑使用附加的intarray模块以获得更好的性能。参见:

答案 1 :(得分:0)

数组=取决于元素的顺序,因此在将元素变成数组时需要对元素进行排序。我认为最简单的方法是使用自己的功能。

create function string_to_array_sorted(p_input text)
  returns text[]
as
$$
  select array_agg(t.x order by t.x)
  from unnest(string_to_array(lower(p_input), ',')) as t(x);
$$
language sql
immutable;

请注意,如果不需要正则表达式,string_to_array()的效率要比regexp_split_to_array()高。

使用上述功能,您的查询可以写为:

select a.id1,b.id1, a.shared, b.shared
from x_a a 
  join x_b b on a.id1 = b.id1 
where string_to_array_sorted(a.shared) = string_to_array_sorted(b.shared);

请注意,我用一个“现代”(已有30年历史)的显式JOIN运算符替换了古老,过时且脆弱的隐式连接。

您可以创建索引来加快速度:

create index on x_a (id1, string_to_array_sorted(shared));
create index on x_b (id1, string_to_array_sorted(shared));