sql >> Database >  >> RDS >> PostgreSQL

hoe kan ik alle id's recursief vanaf een bepaalde id krijgen in een postgresql-tabel die naar zichzelf verwijst?

Gebruik recursieve algemene tabeluitdrukking . Begin altijd bij de root en gebruik een array van id's om paden te krijgen voor een gegeven id in de WHERE clausule.

Voor id = 1 :

with recursive cte(id, parent, name, ids) as (
    select id, parent, name, array[id]
    from my_table
    where parent is null
union all
    select t.id, t.parent, concat(c.name, t.name, '/'), ids || t.id
    from cte c
    join my_table t on c.id = t.parent
)
select id, name 
from cte
where 1 = any(ids) and id <> 1

 id |         name          
----+-----------------------
  2 | /home/
  5 | /usr/
  6 | /usr/local/
  3 | /home/user/
  4 | /home/user/bin/
(5 rows)

Voor id = 2 :

with recursive cte(id, parent, name, ids) as (
    select id, parent, name, array[id]
    from my_table
    where parent is null
union all
    select t.id, t.parent, concat(c.name, t.name, '/'), ids || t.id
    from cte c
    join my_table t on c.id = t.parent
)
select id, name 
from cte
where 2 = any(ids) and id <> 2

 id |         name          
----+-----------------------
  3 | /home/user/
  4 | /home/user/bin/
(2 rows)    

Bidirectionele zoekopdracht

De vraag is echt interessant. De bovenstaande query werkt goed, maar is inefficiënt omdat alle boomknooppunten worden geparseerd, zelfs als we om een ​​blad vragen. De krachtigere oplossing is een recursieve bidirectionele query. De binnenste query loopt van een bepaald knooppunt naar boven, terwijl de buitenste van het knooppunt naar beneden gaat.

with recursive outer_query(id, parent, name) as (
    with recursive inner_query(qid, id, parent, name) as (
        select id, id, parent, name
        from my_table
        where id = 2        -- parameter
    union all
        select qid, t.id, t.parent, concat(t.name, '/', q.name)
        from inner_query q
        join my_table t on q.parent = t.id
    )
    select qid, null::int, right(name, -1)
    from inner_query
    where parent is null
union all
    select t.id, t.parent, concat(q.name, '/', t.name)
    from outer_query q
    join my_table t on q.id = t.parent
)
select id, name
from outer_query
where id <> 2;          -- parameter



  1. Hoe kan ik deze query sneller laten lopen?

  2. Statische versus dynamische sql

  3. De beste manier om te voorkomen dat een waarde negatief wordt in mysql

  4. krijg een fout bij het definiëren van de gebeurtenisnaam op mysqlworkbench 5.5