给定一个包含整数数组的表,应该合并数组,以便所有具有重叠条目的数组最终都是一个。
给出表arrays
a
------------
{1,2,3}
{1,4,7}
{4,7,9}
{15,17,18}
{18,16,15}
{20}
结果应如下所示
{1,2,3,4,7,9}
{15,17,18,16}
{20}
正如您所看到的,可能会删除合并数组中的重复值,并且数组中结果条目的顺序并不重要。数组是整数数组,因此可以使用intarray
模块中的函数。
这将在一个非常大的表上完成,因此性能至关重要。
我的第一个天真的方法是在&&
运算符上自行加入表格。像这样:
SELECT DISTINCT uniq(sort(t1.a || t2.a))
FROM arrays t1
JOIN arrays t2 ON t1.a && t2.a
这留下了两个问题:
非常欢迎任何意见。
答案 0 :(得分:2)
do $$
declare
arr int[];
arr_id int := 0;
tmp_id int;
begin
create temporary table tmp (v int primary key, id int not null);
for arr in select a from t loop
select id into tmp_id from tmp where v = any(arr) limit 1;
if tmp_id is NULL then
tmp_id = arr_id;
arr_id = arr_id+1;
end if;
insert into tmp
select unnest(arr), tmp_id
on conflict do nothing;
end loop;
end
$$;
select array_agg(v) from tmp group by id;
答案 1 :(得分:1)
纯SQL版本:
WITH RECURSIVE x (a) AS (VALUES ('{1,2,3}'::int2[]),
('{1,4,7}'),
('{4,7,9}'),
('{15,17,18}'),
('{18,16,15}'),
('{20}')
), y AS (
SELECT 1::int AS lvl,
ARRAY [ a::text ] AS a,
a AS res
FROM x
UNION ALL
SELECT lvl + 1,
t1.a || ARRAY [ t2.a::text ],
(SELECT array_agg(DISTINCT unnest ORDER BY unnest)
FROM (SELECT unnest(t1.res) UNION SELECT unnest(t2.a)) AS a)
FROM y AS t1
JOIN x AS t2 ON (t2.a && t1.res) AND NOT t2.a::text = ANY(t1.a)
WHERE lvl < 10
)
SELECT DISTINCT res
FROM x
JOIN LATERAL (SELECT res FROM y WHERE x.a && y.res ORDER BY lvl DESC LIMIT 1) AS z ON true