У меня есть очень простая иерархия parent-child/tree и рекурсивный запрос, который также добавляет depth
и загружает все идеально ... почти. Когда я пытаюсь загрузить несколько узлов, где один из них является дочерним по отношению к другому, я получаю повторяющиеся строки (потому что depth
получает обновление, а строки больше не идентичны).Обеспечение уникальности в рекурсивном запросе
Я прочитал documentation, я не использую UNION ALL
, я сделал попробовать NOT cycle
трюк из документации, я знаю о типе ltree данных, но я не могу его использовать. Это что-то другое, рассмотрим следующее дерево:
5
├─9
│ └─15
├─10
│ └─16
└─11
└─17
И запрос:
WITH RECURSIVE "CTE" AS
(
SELECT "id", 0 AS "depth"
FROM "Node" WHERE "id" IN (5, 9, 15)
UNION
SELECT "Node"."id", "CTE"."depth" + 1
FROM "CTE" JOIN "Node" ON "Node"."parentId" = "CTE"."id"
)
SELECT *
FROM "CTE"
ORDER BY "id";
что приводит:
id depth
5 0
9 0
9 1
10 1
11 1
15 0
15 1
15 2
16 2
17 2
Вместо желаемого результата:
id depth
5 0
9 0
10 1
11 1
15 0
16 2
17 2
Выполнение того же qu чень с WHERE "id" = 5
производит (обратите внимание, как глубина отличается, потому что выбор сделан прямо от корня):
id depth
5 0
9 1
10 1
11 1
15 2
16 2
17 2
Решение это было бы изменить присоединиться стать:
FROM "CTE" JOIN "Node" ON
"Node"."parentId" = "CTE"."id" AND
"Node"."id" NOT IN (SELECT "id" FROM "CTE")
Но Postgres не позволяет ссылаться на «CTE» из подзапроса. Я хочу знать, есть ли подходящий подход к этой проблеме?
Кстати,, я придумал решение, которое работает, я попробовал его в нескольких разных сценариях, но я не уверен на 100%, что он будет работать во всех случаях. Он в основном устраняет первоначально выбранные значения, гарантируя, что итерация не будет «вводить» их. Я на правой ноге с ним/есть ли какие-то подводные камни с этим подходом?
WITH RECURSIVE "CTE" AS
(
SELECT "id", 0 AS "depth"
FROM "Node" WHERE "id" IN (5, 9, 15)
UNION
SELECT "Node"."id", "CTE"."depth" + 1
FROM "CTE" JOIN "Node" ON
"Node"."parentId" = "CTE"."id"
AND NOT IN (5, 9, 15)
)
SELECT *
FROM "CTE"
ORDER BY "id";
Что именно вы ищете? –
И что особенного в '' id 'IN (5, 9, 15) '? Они представляют собой только один возможный путь в дереве. – wildplasser
Ваш запрос делает то, что вы спросили: он возвращает лес с тремя корневыми узлами (5, 9, 15). Но, глядя на вашу иерархию, эти узлы не находятся на одном уровне (поэтому существуют дубликаты: по одному для каждого дерева в лесу). Если вы хотите запросить только дерево примеров, вам нужно только «WHERE» id «= 5». – pozs