DBMSのツリーの場合、WITH RECURSIVE cte-idiomを使用して、適切な再帰レベルでクリップできます(==指定されたノードの再帰レベル。おそらく別の再帰副選択が必要になります)
編集:(追加されたコード)
-- the test table
DROP table tree CASCADE;
CREATE table tree
( id CHAR(1) NOT NULL PRIMARY KEY
, pa CHAR(1) REFERENCES tree(id)
, le CHAR(1) REFERENCES tree(id)
, ri CHAR(1) REFERENCES tree(id)
);
-- generate some data
INSERT INTO tree (id, pa, le, ri) VALUES
( 'a', NULL, 'b', 'c' )
, ( 'b', 'a', 'd', 'e' )
, ( 'c', 'a', 'f', NULL )
, ( 'd', 'b', 'g', NULL )
, ( 'e', 'b', NULL, 'h' )
, ( 'f', 'c', NULL, 'i' )
, ( 'g', 'd', NULL, NULL )
, ( 'h', 'e', NULL, NULL )
, ( 'i', 'f', NULL, NULL )
;
-- a room with a view
CREATE VIEW reteview AS (
WITH RECURSIVE re AS (
SELECT 0 AS lev,id, pa, le, ri FROM tree
WHERE pa IS NULL
UNION
SELECT 1+re.lev AS lev
, tr.id, tr.pa, tr.le, tr.ri
FROM tree tr, re
WHERE re.id = tr.pa
)
SELECT * FROM re
);
/* EXPLAIN ANALYZE */ -- SELECT * FROM reteview ;
/* EXPLAIN ANALYZE */ SELECT re0.*
FROM reteview re0
, reteview re1
WHERE re1.id = 'f'
AND re0.lev <= re1.lev
;
結果:
lev | id | pa | le | ri
-----+----+----+----+----
0 | a | | b | c
1 | b | a | d | e
1 | c | a | f |
2 | d | b | g |
2 | e | b | | h
2 | f | c | | i
(6 rows)
クエリプラン(Postgres 9.01)
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=949.93..2773.55 rows=35167 width=36) (actual time=0.159..0.337 rows=6 loops=1)
Join Filter: (re.lev <= re1.lev)
-> CTE Scan on re (cost=474.97..566.71 rows=4587 width=36) (actual time=0.034..0.151 rows=9 loops=1)
CTE re
-> Recursive Union (cost=0.00..474.97 rows=4587 width=36) (actual time=0.021..0.129 rows=9 loops=1)
-> Seq Scan on tree (cost=0.00..23.10 rows=7 width=32) (actual time=0.012..0.014 rows=1 loops=1)
Filter: (pa IS NULL)
-> Hash Join (cost=2.28..36.01 rows=458 width=36) (actual time=0.018..0.022 rows=2 loops=4)
Hash Cond: (tr.pa = re.id)
-> Seq Scan on tree tr (cost=0.00..23.10 rows=1310 width=32) (actual time=0.001..0.003 rows=9 loops=4)
-> Hash (cost=1.40..1.40 rows=70 width=12) (actual time=0.003..0.003 rows=2 loops=4)
Buckets: 1024 Batches: 1 Memory Usage: 1kB
-> WorkTable Scan on re (cost=0.00..1.40 rows=70 width=12) (actual time=0.001..0.002 rows=2 loops=4)
-> Materialize (cost=474.97..578.52 rows=23 width=4) (actual time=0.013..0.018 rows=1 loops=9)
-> Subquery Scan on re1 (cost=474.97..578.40 rows=23 width=4) (actual time=0.111..0.157 rows=1 loops=1)
-> CTE Scan on re (cost=474.97..578.17 rows=23 width=36) (actual time=0.110..0.156 rows=1 loops=1)
Filter: (id = 'f'::bpchar)
CTE re
-> Recursive Union (cost=0.00..474.97 rows=4587 width=36) (actual time=0.008..0.135 rows=9 loops=1)
-> Seq Scan on tree (cost=0.00..23.10 rows=7 width=32) (actual time=0.002..0.008 rows=1 loops=1)
Filter: (pa IS NULL)
-> Hash Join (cost=2.28..36.01 rows=458 width=36) (actual time=0.021..0.024 rows=2 loops=4)
Hash Cond: (tr.pa = re.id)
-> Seq Scan on tree tr (cost=0.00..23.10 rows=1310 width=32) (actual time=0.001..0.004 rows=9 loops=4)
-> Hash (cost=1.40..1.40 rows=70 width=12) (actual time=0.004..0.004 rows=2 loops=4)
Buckets: 1024 Batches: 1 Memory Usage: 1kB
-> WorkTable Scan on re (cost=0.00..1.40 rows=70 width=12) (actual time=0.001..0.001 rows=2 loops=4)
Total runtime: 0.764 ms
(28 rows)