Você pode simplificar em vários lugares (assumindo
acct_id
e parent_id
são 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;
- As colunas
acct_id
,depth
,cycle
são apenas ruídos em sua consulta. - O
WHERE
condição tem que sair da recursão um passo antes, antes a entrada duplicada do nó superior está no resultado. Isso foi um "off-by-one" em seu original.
O resto é formatação.
Se você sabe o único círculo possível em seu gráfico é uma auto-referência, podemos ter isso mais barato:
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.
Observe que haveria problemas (pelo menos até pg v9.4) para tipos de dados com um modificador (como
varchar(5)
) porque a concatenação de array perde o modificador, mas o rCTE insiste em que os tipos correspondam exatamente:- Resultados surpreendentes para tipos de dados com modificador de tipo