Группа извлекаемых записей из РЕКУРСИВНОГО запроса, которые имеют одних и тех же родителей, бабушек и дедушек

#postgresql #postgresql-10

#postgresql #postgresql-10

Вопрос:

У меня есть таблица с элементами, которые находятся в отношениях ManyToMany с Category.

Элемент

 id  |  name 
 1     name1
 2     name2
 3     name3 
  

ItemCategory

 id | category_id | item_id
  1     4            1
  2     5            1
  3     7            1
  4     8            1
  

Категория (внешний ключ parent_id для себя)

   id | parent_id | name     
   1     Null       A1
   2      1         B1
   3      1         B2 
   4      2         C1
   5      3         C2
   6      1         D1
   7      6         DE
   8      1         DT
  

Я пытаюсь получить категории элементов, от дочерних к родительским, для элемента, поэтому я использую:

  WITH RECURSIVE descendants(name, id, slug, parent_id, bread_order) AS (
 SELECT  name, id, slug, parent_id, 0
 FROM categories
 where id in (
 SELECT c.id FROM items AS p
 INNER JOIN items_categories AS pc ON p.id=pc.item_id 
 INNER JOIN categories AS c ON pc.category_id = c.id
     WHERE p.id = 10
 )   
 UNION ALL
 SELECT c2.name, c2.id, c2.slug, c2.parent_id, bread_order 1
 FROM categories AS c2
 INNER JOIN descendants AS d ON c2.id=d.parent_id
) SELECT id, name, parent_id, bread_order FROM descendants 
ORDER by bread_order DESC
  

Проблема в том, что две дочерние категории могут иметь одного и того же родителя, или родитель для одной из них является великим родителем для другой.

 C1 -> B1 -> A1
C2 ->B1  -> A1
C3 ->B2  -> A1
DE -> D1 -> A1
DT  -> A1
  

Я попытался сгруппировать их, но, поскольку у них одинаковые родители, grand_parents — это не то, что мне нужно, мне нужно, когда я извлекаю информацию из базы данных, знать, как создать путь (см. Выше).

Есть ли какой-либо способ, например, использовать CASE с идентификаторами, которые возвращаются из подзапроса?

Ответ №1:

Вы можете агрегировать путь во время запроса:

 WITH RECURSIVE descendants(name, id, parent_id, bread_order, path) AS (
  SELECT  name, id, parent_id, 0, array[id] as path
  FROM categories
  where id in (SELECT c.id
               FROM items AS p
                 JOIN items_categories AS pc ON p.id=pc.item_id 
                 JOIN categories AS c ON pc.category_id = c.id
               WHERE p.id = 1)   
  UNION ALL

  SELECT c2.name, c2.id, c2.parent_id, bread_order 1, d.path||c2.id
  FROM categories AS c2
    JOIN descendants AS d ON c2.id=d.parent_id
) 
SELECT id, name, parent_id, path, bread_order
FROM descendants 
ORDER by path
  

Комментарии:

1. все в порядке, используя path, единственная проблема заключается в том, что правильный путь находится на верхнем родительском элементе, а не на начальном дочернем элементе