再帰的 CTE (これは Postgres 用です。Oracle ではマイナーな変更が必要になります) 注: 対策を講じないと、いくつかのループが回避されず、無限再帰につながります。
CREATE TABLE pairs
( e1 varchar NOT NULL
, e2 varchar NOT NULL
, PRIMARY KEY (e1,e2)
);
INSERT INTO pairs(e1,e2) VALUES
('A' , 'B' )
, ('B','C' )
, ('C','D' )
, ('C','G' )
, ('E','F' )
, ('I','E' )
, ('H','G' )
, ('J','K' )
, ('K','L' )
;
WITH RECURSIVE tree AS (
WITH dpairs AS (
SELECT e1 AS one, e2 AS two FROM pairs WHERE e1 < e2
UNION ALL
SELECT e2 AS one, e1 AS two FROM pairs WHERE e1 > e2
)
SELECT dp.one AS opa
, dp.one AS one
, dp.two AS two
FROM dpairs dp
WHERE NOT EXISTS ( SELECT *
FROM dpairs nx
WHERE nx.two = dp.one
AND nx.one < dp.one
)
UNION ALL
SELECT tr.opa AS opa
, dp.one AS one
, dp.two AS two
FROM tree tr
JOIN dpairs dp ON dp.one = tr.two AND dp.two <> tr.opa AND dp.two <> tr.one
)
SELECT opa,one,two
, dense_rank() OVER (ORDER BY opa) AS rnk
FROM tree
ORDER BY opa, one,two
;
結果:
opa | one | two | rnk
-----+-----+-----+-----
A | A | B | 1
A | B | C | 1
A | C | D | 1
A | C | G | 1
A | G | H | 1
E | E | F | 2
E | E | I | 2
J | J | K | 3
J | K | L | 3
(9 rows)