Я хочу запросить с заданным идентификатором, получить все связанные дочерние, а также родительские записи.

Вот пример набора данных;

id    |    name    |    parent     |
 1          ab            null
 21         aa             1
 33         dd             21   
 55         ee            null
 66         bb             55
 77         cc             33 

Для id = 33 я хочу получить;

id    |    name    |    parent     |
 1          ab            null
 21         aa             1
 33         dd             21   
 77         cc             33 

И для id = 21 также будут возвращены те же записи, поскольку они имеют общие родительские и дочерние записи. Я пытался использовать внутреннее соединение, но не знаю, как установить условие id.

SELECT t.* FROM table t INNER JOIN table tl ON t.id = tl.parent
0
hellzone 15 Сен 2021 в 14:04

2 ответа

Лучший ответ

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

with recursive cte
  as (select id,name,parent,cast(id as varchar(50)) as concat_val,id as root,cast(1 as int)  as lvl
        from t
       where id=33
       union all
       select a.id,a.name,a.parent,cast(concat(a.id,'/',b.concat_val) as varchar(50)),b.root,cast(b.lvl+1 as int)
         from t a
         join cte b
           on b.parent=a.id
        )
  ,cte2
  as (select id,name,parent,cast(id as varchar(50)) as concat_val,id as root,cast(1 as int)  as lvl
        from t
       where id=33
       union all
       select a.id,a.name,a.parent,cast(concat(a.id,'/',b.concat_val) as varchar(50)),b.root,cast(b.lvl-1 as int)
         from t a
         join cte2 b
           on b.id=a.parent
        ) 
select distinct * from (        
select * 
  from cte
union all  
select * 
  from cte2
)x
order by lvl desc

+----+------+--------+------------+------+-----+
| id | name | parent | concat_val | root | lvl |
+----+------+--------+------------+------+-----+
|  1 | ab   | null   | 1/21/33    |   33 |   3 |
| 21 | aa   | 1      | 21/33      |   33 |   2 |
| 33 | dd   | 21     | 33         |   33 |   1 |
| 77 | cc   | 33     | 77/33      |   33 |   0 |
+----+------+--------+------------+------+-----+

https://dbfiddle.uk/?rdbms=postgres_10&fiddle=963f0522a3dd3d3d9f945e56ce746203

1
George Joseph 15 Сен 2021 в 12:00

Вы должны сделать это

select 
    t.id,
    t.name,
    t.parent,
    tl.id,
    tl.name,
    tl.parent,   
from
    table t left join table tl 
    on t.id = tl.parent
where
   t.id = 33
   

Если вы знаете, сколько десендансов, скажем, 3, вы можете сделать

select
    p1.id,
    p1.name,
    p1.parent,
    p2.id,
    p2.name,
    p2.parent,        
    p3.id,
    p3.name,
    p3.parent,
from
    data as p1 left join data as p2 
      on (p1.id = p2.parent) 
    left join data as p3
      on (p2.id = p3.parent)
where 
    p1.id = 33

Хорошая документация здесь https://learnsql.com/blog / do-it-in-sql-recursive-tree-traversal /

Во многих случаях модель вложенного множества предпочтительнее древовидной структуры. см. также https://en.wikipedia.org/wiki/Nested_set_model

0
Zeppi 15 Сен 2021 в 11:37