如果数组重叠,则折叠多行数组

时间:2014-02-11 23:57:30

标签: sql arrays postgresql

我在PostgreSQL 9.3中有一个包含单个列的表 每行包含一个数组。我试图找到一种崩溃的方法 共享相同元素的数组行。

实施例

简单重叠

给出以下两行数组:

{ 1, 2, 3 }
{ -5, 3, 6, 9 }

结果将是一行包含:

{ -5, 1, 2, 3, 6, 9 }

这是因为两个数组中都存在“3”。注意,不重复“3”。

多重叠

相同的重叠概念也可以应用于表中任何位置的多行:

{ 1, 2, 3 }
{ 100, 200, 300 }
{ 3, 4, 5 }
{ 5, 6, 7 }

,所需的输出将是两行:

{ 1, 2, 3, 4, 5, 6, 7}
{ 100, 200, 300 }

从结果返回的数组应该是唯一的,并且彼此不共享任何元素。

我尝试了什么

我在array union函数中使用了“with recursive”查询,但无法确定正确的查询。

提供了一个可以使用的示例表here on SQL fiddle(它模仿第二个示例),或者它可以使用以下内容构建:

create table test ( 
  arr integer[] 
); 

insert into test (arr) values ('{ 1, 2, 3 }');
insert into test (arr) values ('{ 100, 200, 300 }');
insert into test (arr) values ('{ 3, 4, 5 }');
insert into test (arr) values ('{ 5, 6, 7 }');

1 个答案:

答案 0 :(得分:3)

好的,这很难。请查看此查询:

;with recursive minelem AS(
select arr, MIN(unnest) minel from (select arr, unnest(arr) from test) a group by arr),
testwithrn as(
select arr, row_number() over (order by minel) rn from minelem
),
cte(arr, rn, counter, grp) as(
  select arr, rn, 1, 1 from testwithrn where rn = 1
union all 
  select 
    case when array_length(a.arr & b.arr, 1) > 0 then a.arr | b.arr else b.arr end, 
    b.rn, 
    case when array_length(a.arr & b.arr, 1) > 0 then a.counter + 1 else 1 end,
    case when array_length(a.arr & b.arr, 1) > 0 then a.grp else a.grp + 1 end
    from cte a inner join testwithrn b 
    on b.rn > a.rn
),
grouped as(
  SELECT arr, counter, grp,
  row_number() over (partition by grp order by counter desc) rn from cte)
select distinct arr from grouped where rn = 1

SQL Fiddle

您可以在上面的查询中测试不同的CTE,以了解我如何提出解决方案。这里的关键是使用operator |合并数组,如a.arr | b.arr

有一个名为cte的递归查询,它计算不同组内每组的出现次数。您可以将最后一行替换为select * from cte order by grp, counter,以查看在递归构建集时如何更改countergrp