Есть ли в Postrgre эквивалент от 1000 * до go вверх по дереву? - PullRequest
1 голос
/ 19 апреля 2020

Я учусь работать с деревьями в postgresql12 и нашел хорошую функцию connectby.

Например:

SELECT * FROM connectby('descriptor_value', 'descriptor_value_id', 
    'parent_value_id', '1', 0, '->') 

Дает следующий вывод:

enter image description here

Однако я не хочу строить все дерево, начиная с root, я хочу получить ответвление к root, начиная с узла (производительность ). Например, я хочу передать в качестве аргумента 87 и получить 1->86->87. Есть ли такая функция?

Ответы [ 2 ]

3 голосов
/ 19 апреля 2020

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

with recursive cte as (
  select descriptor_value_id, parent_value_id, 1 as level
  from descriptor_value
  where descriptor_value_id = 87
  union all
  select p.descriptor_value_id, p.parent_value_id, c.level + 1
  from descriptor_value p 
    join cte c on c.parent_value_id = p.descriptor_value_id
)
select * 
from cte;

Функция connectby() в значительной степени устарела с момента введения рекурсивных CTE в Postgres 8.4

2 голосов
/ 19 апреля 2020

Я думаю, что вы хотите:

with recursive cte as (
    select descriptor_value_id, parent_value_id, 1 lvl 
    from descriptor_value 
    where descriptor_value_id = 87
    union all
    select dv.descriptor_value_id, dv.parent_value_id, lvl + 1
    from descriptor_value dv
    inner join cte c on c.parent_value_id = dv.descriptor_value_id
)
select string_agg(descriptor_value_id::text, '->' order by lvl desc) full_path from cte

Рекурсивный запрос поднимается вверх по дереву, начиная с заданного descriptor_value_id. Затем внешний запрос генерирует полный путь путем объединения идентификаторов, найденных в обратном порядке, по мере их обнаружения.

Это дает вам результат с одной строкой и одним столбцом, который содержит полный путь к данному узлу.

Вы можете изменить начальный узел, изменив предложение where якоря рекурсивного запроса.


Если вы хотите использовать один и тот же лог c, чтобы получить путь к каждому узлу сразу, все еще обходя дерево вверх, вы можете сделать:

with recursive cte as (
    select descriptor_value_id starting_id, descriptor_value_id, parent_value_id, 1 lvl 
    from descriptor_value 
    union all
    select c.starting_id, dv.descriptor_value_id, dv.parent_value_id, lvl + 1
    from descriptor_value dv
    inner join cte c on c.parent_value_id = dv.descriptor_value_id
)
select 
    starting_id, 
    string_agg(descriptor_value_id::text, '->' order by lvl desc) full_path 
from cte
group by starting_id

Однако в этом случае может быть проще и эффективнее ходить по дереву вниз.

...