2017-08-11 41 views
0

給定一個包含整數數組的表,應該合併數組,以便所有具有重疊條目的數組最終成爲一個整數。包含重疊值的數組的高效合併

鑑於表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 

這留下了兩個問題:

  1. 它是不是遞歸(它結合了最多2個陣列)。
    這可能可以通過遞歸CTE來解決。
  2. 合併數組在輸出中重新出現。

任何輸入是非常歡迎。

+0

這不是關係型的任務,所以SQL是不好的語言。簡單的C代碼排序數組應該是最好的解決方案。這個C擴展應該非常簡單。 –

+0

因爲我一直對postgres C擴展的工作方式感興趣,所以如果沒有其他的東西出現在這裏,我會試試這個:-) –

回答

1
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; 
+0

最後,基於你的想法的解決方案實現了這個訣竅。謝謝! –

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