sql >> Databasteknik >  >> RDS >> PostgreSQL

hur kan jag få alla id från ett givet id rekursivt i en postgresql-tabell som refererar till sig själv?

Använd rekursivt vanligt tabelluttryck . Börja alltid från roten, använd en array av id för att få sökvägar för ett givet id i WHERE klausul.

För 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)

För 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)    

Dubbelriktad fråga

Frågan är verkligen intressant. Ovanstående fråga fungerar bra men är ineffektiv eftersom den analyserar alla trädnoder även när vi frågar efter ett löv. Den mer kraftfulla lösningen är en dubbelriktad rekursiv fråga. Den inre frågan går från en given nod till toppen, medan den yttre går från noden till botten.

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. SQL UPPDATERING

  2. CRON och SQLPLUS

  3. Hur kan jag identifiera raderna som är involverade i ett Oracle-låsläge?

  4. MySQL TEXT vs BLOB vs CLOB