您不需要将根存储在每条记录中,您可以通过递归查询轻松找到它。
追逐爷爷的小示范。(这里的约定是任何根都有一个 parent_id = NULL;另一个约定可以是 parent_id=id;YMMV)
set search_path='tmp';
DROP TABLE categories;
CREATE TABLE categories
( id INTEGER NOT NULL PRIMARY KEY
, parent_id INTEGER references categories(id)
, zname text
);
-- Generate some data
INSERT INTO categories (id) SELECT * FROM generate_series (1,33);
UPDATE categories SET parent_id = 1 + id/4 WHERE id > 1;
-- uncomment the next line (and comment the previous) if you want a forest.
-- UPDATE categories SET parent_id = 1 + id/4 WHERE id > 3;
UPDATE categories SET zname = 'Zzz'::text || id::text;
-- SELECT * FROM categories;
WITH RECURSIVE tr AS (
SELECT ca0.id as root
, ca0.parent_id AS parent_id
, ca0.id AS id
, ca0.zname AS zname
FROM categories ca0
WHERE ca0.parent_id IS NULL
UNION
SELECT tr.root as root
, ca1.parent_id AS parent_id
, ca1.id AS id
, ca1.zname AS zname
FROM categories ca1, tr
WHERE ca1.parent_id = tr.id
)
SELECT * FROM tr;
结果:
root | parent_id | id | zname
------+-----------+----+-------
1 | | 1 | Zzz1
1 | 1 | 2 | Zzz2
1 | 1 | 3 | Zzz3
1 | 2 | 4 | Zzz4
1 | 2 | 5 | Zzz5
1 | 2 | 6 | Zzz6
1 | 2 | 7 | Zzz7
1 | 3 | 8 | Zzz8
1 | 3 | 9 | Zzz9
1 | 3 | 10 | Zzz10
1 | 3 | 11 | Zzz11
1 | 4 | 12 | Zzz12
1 | 4 | 13 | Zzz13
1 | 4 | 14 | Zzz14
1 | 4 | 15 | Zzz15
1 | 5 | 16 | Zzz16
1 | 5 | 17 | Zzz17
1 | 5 | 18 | Zzz18
1 | 5 | 19 | Zzz19
1 | 6 | 20 | Zzz20
1 | 6 | 21 | Zzz21
1 | 6 | 22 | Zzz22
1 | 6 | 23 | Zzz23
1 | 7 | 24 | Zzz24
1 | 7 | 25 | Zzz25
1 | 7 | 26 | Zzz26
1 | 7 | 27 | Zzz27
1 | 8 | 28 | Zzz28
1 | 8 | 29 | Zzz29
1 | 8 | 30 | Zzz30
1 | 8 | 31 | Zzz31
1 | 9 | 32 | Zzz32
1 | 9 | 33 | Zzz33
(33 rows)