Reputation: 103
I have a pilates_bill table representing direct ancestry (not a tree structure)
bill_id (pk) | previous_bill_id (self-join fk)
=============+================================
1 2
2 3
3 4
5 NULL
Need to produce a list (parent / grandparent / etc) of all ancestors for any given row (below examples start with 1).
Obtaining a list of bill_ids with ancestor chain using recursive CTE
WITH RECURSIVE chain(from_id, to_id) AS (
SELECT NULL::integer, 1 -- starting id
UNION
SELECT c.to_id, pilates_bill.previous_bill_id
FROM chain c
LEFT OUTER JOIN pilates_bill ON (pilates_bill.bill_id = to_id)
WHERE c.to_id IS NOT NULL
)
SELECT from_id FROM chain WHERE from_id IS NOT NULL;
Result 1,2,3,4,5 as expected
But now when I try to produce table rows in order of ancestry the result is broken
SELECT * FROM pilates_bill WHERE bill_id IN
(
WITH RECURSIVE chain(from_id, to_id) AS (
SELECT NULL::integer, 1
UNION
SELECT c.to_id, pilates_bill.previous_bill_id
FROM chain c
LEFT OUTER JOIN pilates_bill ON (pilates_bill.bill_id = to_id)
WHERE c.to_id IS NOT NULL
)
SELECT from_id FROM chain WHERE from_id IS NOT NULL
)
Row order is 5,1,2,3,4
What a I doing wrong here ?
Upvotes: 0
Views: 964
Reputation: 238096
The rows returned by a SQL query are in random order unless you specify an order by
.
You can calculate depth by keeping track of it in the recursive CTE:
WITH RECURSIVE chain(from_id, to_id, depth) AS
(
SELECT NULL::integer
, 1
, 1
UNION
SELECT c.to_id
, pb.previous_bill_id
, depth + 1
FROM chain c
LEFT JOIN
pilates_bill pb
ON pb.bill_id = c.to_id
WHERE c.to_id IS NOT NULL
)
SELECT *
FROM chain
ORDER BY
depth
Upvotes: 2