Możesz uprościć w kilku miejscach (zakładając, że acct_id
i parent_id
są 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;
- Kolumny
acct_id
,depth
,cycle
to tylko szum w zapytaniu. WHERE
warunek musi wyjść z rekurencji o krok wcześniej, przed w wyniku znajduje się zduplikowany wpis z górnego węzła. W oryginale było to „przegranie”.
Reszta to formatowanie.
Jeśli wiesz jedyne możliwe kółko na wykresie to samoodniesienie, możemy to zrobić taniej:
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;
Skrzypce SQL.
Zauważ, że wystąpiłyby problemy (przynajmniej do pg v9.4) dla typów danych z modyfikatorem (takim jak varchar(5)
), ponieważ konkatenacja tablic traci modyfikator, ale rCTE nalega na dokładne dopasowanie typów:
- Zaskakujące wyniki dla typów danych z modyfikatorem typu