Postgres самосоединение рекурсивной цепочки предков CTE - PullRequest
0 голосов
/ 03 мая 2018

У меня есть таблица pilates_bill, представляющая прямое происхождение (не древовидная структура)

bill_id (pk) | previous_bill_id (self-join fk)
=============+================================
1               2
2               3
3               4
5               NULL

Необходимо создать список (родитель / дедушка / бабушка и т. Д.) Всех предков для любой данной строки (приведенные ниже примеры начинаются с 1).

Получение списка bill_ids с цепочкой предков с использованием рекурсивного 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;

Результат 1,2,3,4,5 как и ожидалось

Но теперь, когда я пытаюсь создать строки таблицы в порядке происхождения, результат не получается

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
)

Порядок строк 5,1,2,3,4

Что я тут не так делаю?

1 Ответ

0 голосов
/ 03 мая 2018

Строки, возвращаемые запросом SQL, располагаются в случайном порядке, если вы не укажете order by.

Вы можете рассчитать глубину, отслеживая ее в рекурсивном 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
...