PostgreSQL поиск ближайшего родительского значения определенного уровня

#sql #postgresql #common-table-expression #hierarchical-data #recursive-query

#sql #postgresql #common-table-expression #иерархический-данные #рекурсивный запрос

Вопрос:

* Прошу прощения, мои таблицы отображались правильно, когда я писал этот вопрос, и после публикации форматирование выглядит отключенным. пытаясь исправить это, сейчас
я пытаюсь написать запрос в postgresql, который возвращал бы для любого заданного дочернего значения ближайшее родительское значение, достигшее определенного ранга. В настоящее время у меня есть этот запрос, который отображает весь иерархический путь для любого заданного дочернего значения-

 WITH RECURSIVE tree AS ( 
   SELECT "ChildDisplayID", 
          "ParentID",
          "Rank",
          1 as level 
   FROM table1
   WHERE "ChildDisplayID" = {{some ChildID}}

   UNION ALL 

   SELECT t1."ChildDisplayID",
          t1."ParentID", 
          t1."Rank",
          t.level   1
   FROM table1 t1
     JOIN tree t ON t."ParentID" = t1."ChildDisplayID"
)
SELECT *
FROM tree
 

То, что я хочу сделать, это иметь в одной строке идентификатор дочернего элемента и идентификатор родителя ближайшего родителя, ранг которого равен «Партнер». Например, вот результат, который я получаю в настоящее время:

 | ChildID | ParentID | Rank | Level |   
|---------|----------|------|-------|  
|   6     |     5    |Associate Manager| 1    |  
|   5     |     4    |Manager| 2    |  
|   4     |     3    |Associate Partner| 3    |  
|   3     |     2    |Partner| 4    |  
|   2     |     1    |Partner| 5    |  
|   1     |         |CEO| 6    |  
 

Вот результат, который я хочу:

 |ChildID | Nearest Partner | Rank |
|--------|----------|------|
|6       |3         | Partner |
 

Каков наилучший способ сделать это?

Ответ №1:

Вы можете поставить условие остановки для первого соответствующего партнера в рекурсии, а затем отфильтровать результат:

 WITH RECURSIVE tree AS ( 
   SELECT "ChildDisplayID" as initialid, "ChildDisplayID", "ParentID", "Rank", 1 as level 
   FROM table1
   WHERE "ChildDisplayID" = {{some ChildID}}
   UNION ALL 
   SELECT t.initialid, t1."ChildDisplayID", t1."ParentID", t1."Rank", t.level   1
   FROM table1 t1
   INNER JOIN tree t ON t."ParentID" = t1."ChildDisplayID"
   WHERE t."Rank" <> 'Partner'
)
SELECT *
FROM tree
WHERE "Rank" = 'Partner'
 

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

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

1. Когда я делаю это, возвращаемая строка является 4-й строкой моего исходного вывода, где указанный дочерний идентификатор является ближайшим партнером. Я хочу, чтобы в моем выводе был идентификатор дочернего элемента, который я вставляю в первое предложение where, за которым следует идентификатор ближайшего партнера к этому дочернему элементу

2. @ekeckeisen: вы это id уже знаете, поскольку это входные данные для запроса. Вы можете select сделать это в последней части запроса, если хотите.

3. Да, это имеет смысл. Но в конечном итоге я мог бы создать запрос для извлечения каждого дочернего элемента и ближайшего партнера каждого из этих дочерних элементов, и в этом случае это был бы не просто один дочерний идентификатор, который я ищу. Имеет ли это смысл?

4. @ekeckeisen. Если это так, мы можем сохранить значение, с которого мы начинаем, используя другой столбец в CTE. Выполнено.