Puede simplificar en varios lugares (suponiendo que acct_id
y parent_id
son 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;
- Las columnas
acct_id
,depth
,cycle
son solo ruido en su consulta. - El
WHERE
la condición tiene que salir de la recursividad un paso antes, antes la entrada duplicada del nodo superior está en el resultado. Eso fue un "off-by-one" en su original.
El resto es formatear.
Si sabes el único círculo posible en su gráfico es una autorreferencia, podemos tener eso más 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;
Violín SQL.
Tenga en cuenta que habría problemas (al menos hasta pg v9.4) para los tipos de datos con un modificador (como varchar(5)
) porque la concatenación de matrices pierde el modificador pero el rCTE insiste en que los tipos coincidan exactamente:
- Resultados sorprendentes para tipos de datos con modificador de tipo