【问题标题】:Collapse multiple rows of arrays if the arrays overlap如果数组重叠,则折叠多行数组
【发布时间】:2025-12-12 08:25:01
【问题描述】:

我在 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 函数的“递归”查询,但无法找出正确的查询。

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 }');

【问题讨论】:

  • 对于这类问题,如果您提供sqlfiddle.com 并提供可用的示例表,那就太好了。
  • @CraigRinger 这是一个整洁的网站。我想不通,但这里有一个可用的表:sqlfiddle.com/#!15/b05d8/3/0。继续并将其添加到问题中。
  • @TrevorSenior 嗯,有趣的查询。您不能自行加入with recursive 或在递归术语上使用子查询,我认为您不能使用聚合来执行此操作,除非您有办法group by 重叠术语,我不相信这是可能的。您可能必须使用递归 SQL 函数。一次通过是SELECT uniq(array_cat(a.arr, b.arr)) FROM test a INNER JOIN test b ON (b.arr > a.arr AND a.arr && b.arr),但这并没有多大帮助。
  • 如果表足够小,你可以用python之类的编程语言来做吗?

标签: sql arrays postgresql


【解决方案1】:

好的,这很难。请看一下这个查询:

;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,以了解我是如何提出解决方案的。这里的关键是使用运算符 |合并数组,如a.arr | b.arr

有一个名为cte 的递归查询可以计算不同集合中每个集合的出现次数。您可以将最后一行替换为select * from cte order by grp, counter,以查看递归构建集合时countergrp 的变化

【讨论】: