I am going to assume that your initial data is equal to all of the results with dist = 1, and that the total collection of nodes of interest is the union of all parent and child node IDs.
I see a few things wrong with your original query.
- First I do not see where you are generating a complete list of starting nodes. The input data might have some nodes that exist only as a parent, some only as a child, and some that will be present as both. A complete list can be obtained by querying the
UNION of all parent_id and child_id values. (The union will also de-dup them as a side effect.)
- Next, your initial
dist = 0 part of your recursive CTE seems flawed. Typically, you would not have a join at this point, and for this problem, you would want to list the same ID as both parent and child for dist = 0.
- The recursive part of your CTE also has issues. Your join condition
d4.id = d3.id is matching child to child. This is also the cause of the infinite recursion. You should be matching the existing CTE child to the parent in the joined table.
The following is a rewrite of the query that included fixes to all of the above:
;WITH Nodes AS (
SELECT child_id AS id FROM Parent
UNION
SELECT parent_id AS id FROM Parent
),
Hier AS (
SELECT N.id AS parent_id, N.id AS child_id, 0 AS dist
FROM Nodes N
UNION ALL
SELECT H.parent_id, P.child_id, H.dist + 1 AS dist
FROM Hier H
JOIN Parent P ON P.parent_id = H.child_id
)
SELECT *
FROM Hier
ORDER BY parent_id, child_id
The results match your requested post.
See this db<>fiddle for a working demo.
<database>.<schema>.<table>identifiers.