@NealB's solution is faster (!) See PostgreSQL implementation example here .
Below is an example of another “brute force algorithm”, just for curiosity!
As suggested by @ peter.petrov and @RBarryYoung, some performance problems can be avoided by abandoning CTE recursion ... I will make some problems on the base shortcut , and, abover I add a restriction for grouping to a super-set label. This new transgroup1_loop() function works!
PS: this solution still has performance limitations, please write your answer better or with some adaptation of this.
-- DROP table transgroup1; CREATE TABLE transgroup1 ( id serial NOT NULL PRIMARY KEY, items integer[], -- two or more items in the transitive relationship ssg_label varchar(12), -- the super-set gropuping label dels integer[] DEFAULT array[]::integer[] ); INSERT INTO transgroup1(items,ssg_label) values (array[1, 2],'1'), (array[1, 5],'1'), (array[4, 7],'1'), (array[7, 8],'1'), (array[9, 1],'1'), (array[10, 11],'2'); -- or SELECT array[id1, id2],ssg_label FROM t1, with 10000 items
with these two functions we can solve the problem,
CREATE FUNCTION transgroup1_loop(p_ssg varchar, p_max_i integer DEFAULT 100) RETURNS integer AS $funcBody$ DECLARE cp_dels integer[]; i integer; BEGIN i:=1; LOOP UPDATE transgroup1 SET items = array_uunion(transgroup1.items,t2.items), dels = transgroup1.dels || t2.id FROM transgroup1 AS t1, transgroup1 AS t2 WHERE transgroup1.id=t1.id AND t1.ssg_label=$1 AND t1.id>t2.id AND t1.items && t2.items; cp_dels := array( SELECT DISTINCT unnest(dels) FROM transgroup1 );
to run and view the results, you can use
SELECT transgroup1_loop('1'); -- run with ssg-1 items only SELECT transgroup1_loop('2'); -- run with ssg-2 items only -- show all with a sequential group label: SELECT *, dense_rank() over (ORDER BY id) AS group_label from transgroup1;
results:
id | items | ssg_label | dels | group_label ----+-----------+-----------+------+------------- 4 | {8,7,4} | 1 | {} | 1 5 | {9,5,2,1} | 1 | {} | 2 6 | {11,10} | 2 | {} | 3
PS: the array_uunion() function is the same as the original ,
CREATE FUNCTION array_uunion(anyarray,anyarray) RETURNS anyarray AS $$