Рекурсивно найти всех дочерних объектов n-поколения в postgresql - PullRequest
0 голосов
/ 07 августа 2020

Существует сущность, называемая категорией, с точки зрения пользователя она может рассматриваться как каталог, этот каталог может содержать произвольное количество подкаталогов, которые, в свою очередь, могут иметь свои собственные подкаталоги и так далее, и тому подобное. Так что это простое дерево каталогов. Что мне нужно, так это с учетом идентификатора dirs (категории) найти всех его дочерних элементов, то есть все те подкатегории n-го уровня, содержащиеся в данной категории.

id|name                 |parentCategoryId|userId|
--|---------------------|----------------|------|
85|ToDo                 |                |     7|
95|plans for the weekend|              85|     7|
96|things to buy        |              95|     7|

Учитывая id = 85, результат будет 95 и 96.

Я пробовал сделать это с помощью рекурсивного подхода, но это не сработало.

EDIT:

with recursive subcategories as (
    select id, "name", "parentCategoryId"
    from category c2 
    where id = 85
    union
        select c3.id, c3."name", c3."parentCategoryId"
        from category c3
        inner join subcategories subs on subs."id" = subs."parentCategoryId"
) select * from subcategories

Я пробовал это, но я, кажется, не понимаю, как именно работает эта функция ... теперь она просто возвращает это:

id|name|parentCategoryId|
--|----|----------------|
85|ToDo|                |

Ответы [ 2 ]

1 голос
/ 07 августа 2020

Вы почти у цели, просто исправьте где условие и добавьте уровень вложенности.

with recursive subcategories as (
    select id, "name", "parentCategoryId", 0 as level
    from category c2 
    where id = 85
    union
        select c3.id, c3."name", c3."parentCategoryId", subs.level + 1
        from category c3
        inner join subcategories subs on subs."id" = c3."parentCategoryId"
        where subs.level < YOUR_LIMIT
) select * from subcategories
1 голос
/ 07 августа 2020

Я всегда выполнял этот тип запросов с RECURSIVE CTE. Вот пример использования функции:

CREATE OR REPLACE FUNCTION func_findAllDescendants(startid INTEGER)
RETURNS SETOF test
AS $$
DECLARE
BEGIN
    RETURN QUERY
    WITH RECURSIVE cte AS
    (
        SELECT *
          FROM test t
         WHERE t.id = startid
         UNION
        SELECT descendant.*
          FROM cte parent
          JOIN test descendant ON (parent.id = descendant.parentCategoryID)
    ) SELECT * FROM cte; -- If you don't want the root record add WHERE id <> startid to this query
END;
$$  LANGUAGE PLPGSQL;

Здесь - это DBFiddle, показывающий его в действии.

Идея здесь состоит в том, чтобы начать создание CTE (общая таблица выражение) с одной записью ... стартовой записью, а затем рекурсивно построить остальную часть CTE.

  1. Выберите начальную точку. id = 85
  2. Найдите записи в реальной таблице (путем объединения с CTE), которые имеют идентификатор начальной точки в качестве его parentID.
  3. Найдите записи в реальной таблице, которые имеют идентификатор из шага 2 в качестве его parentID.
  4. Повторяйте, пока родительский идентификатор записи не будет найден.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...