Anda dapat menyederhanakan di beberapa tempat (dengan asumsi acct_id
dan parent_id
adalah NOT NULL
):
WITH RECURSIVE search_graph AS (
SELECT parent_id, ARRAY[acct_id] AS path
FROM account
UNION ALL
SELECT g.parent_id, sg.path || g.acct_id
FROM search_graph sg
JOIN account g ON g.acct_id = sg.parent_id
WHERE g.acct_id <> ALL(sg.path)
)
SELECT path[1] AS child
, path[array_upper(path,1)] AS parent
, path
FROM search_graph
ORDER BY path;
- Kolom
acct_id
,depth
,cycle
hanyalah kebisingan dalam kueri Anda. WHERE
kondisi harus keluar dari rekursi satu langkah lebih awal, sebelum entri duplikat dari simpul teratas ada di hasil. Itu adalah "off-by-one" dalam versi asli Anda.
Sisanya sedang memformat.
Jika Anda tahu satu-satunya lingkaran yang mungkin dalam grafik Anda adalah referensi sendiri, kami dapat memilikinya dengan lebih murah:
WITH RECURSIVE search_graph AS (
SELECT parent_id, ARRAY[acct_id] AS path, acct_id <> parent_id AS keep_going
FROM account
UNION ALL
SELECT g.parent_id, sg.path || g.acct_id, g.acct_id <> g.parent_id
FROM search_graph sg
JOIN account g ON g.acct_id = sg.parent_id
WHERE sg.keep_going
)
SELECT path[1] AS child
, path[array_upper(path,1)] AS parent
, path
FROM search_graph
ORDER BY path;
SQL Fiddle.
Perhatikan akan ada masalah (setidaknya hingga pg v9.4) untuk tipe data dengan pengubah (seperti varchar(5)
) karena rangkaian array kehilangan pengubah tetapi rCTE bersikeras pada jenis yang sama persis:
- Hasil yang mengejutkan untuk tipe data dengan pengubah tipe