Home > Software engineering >  Postgres: grouping array by common element
Postgres: grouping array by common element

Time:12-10

I have a table containing an id and an array of related id

 id  | related_id  
----- -------------
 712 | {1116}
 837 | {1116,1127}
1116 | {712,837}
1127 | {837}

I want to group / merge all related id having a common element

 id  | related_id  |      full_ids       
----- ------------- ---------------------
 712 | {1116}      | {712,1116,837,1127}
 837 | {1116,1127} | {837,1116,712,1127}
1116 | {712,837}   | {712,1116,837,1127}
1127 | {837}       | {1127,837,1116,712}

I try to do it with a recursive SQL but for now some row have missing element

 WITH RECURSIVE 
 un AS (SELECT id,unnest(related_id) as parent FROM my_table),
 rec (id) as
 (
   SELECT id,parent,array[id] as ids from un
     UNION ALL
   SELECT rec.id,un.parent,ids || un.id FROM rec JOIN un ON rec.parent = un.id where un.id <> all(ids)
 ),
 j AS (SELECT distinct on (id) ids,id FROM rec order by id, cardinality(ids) desc)                                                           
 SELECT ops.*,j.ids as full_ids FROM my_table ops LEFT JOIN j ON ops.id=j.id;

Result of this query

  id  | related_id  |      full_ids       
------ ------------- ---------------------
  712 | {1116}      | {712,1116,837,1127}
  837 | {1116,1127} | {837,1116,712}
 1116 | {712,837}   | {1116,837,1127}
 1127 | {837}       | {1127,837,1116,712}

What I am missing ?

CodePudding user response:

I propose you the following solution :

WITH RECURSIVE list (id, related_id, parent, full_ids) AS
(
SELECT id, related_id, related_id, id || related_id
  FROM my_table
UNION ALL
SELECT l.id, l.related_id, array_remove (l.parent, t.id) || t.related_id, l.full_ids || t.sub_id
  FROM list AS l
 INNER JOIN
     ( my_table AS m
       CROSS JOIN LATERAL unnest(m.related_id) AS sub_id
     ) AS t
    ON array[t.id] <@ l.parent
   AND NOT array[t.sub_id] <@ l.full_ids
)
SELECT DISTINCT ON (id) id, related_id, full_ids
  FROM list
 ORDER BY id, array_length(full_ids, 1) DESC

result :

id      related_id      full_ids
712     {1116}          {712,1116,837,1127}
837     {1116,1127}     {837,1116,1127,712}
1116    {712,837}       {1116,712,837,1127}
1127    {837}           {1127,837,1116,712}

See the test in dbfiddle

  • Related