SQL:在三级树中持久化根目录id?
我有一个简单的三级树,当前存储为邻接列表:SQL:在三级树中持久化根目录id?,sql,postgresql,self-join,adjacency-list,Sql,Postgresql,Self Join,Adjacency List,我有一个简单的三级树,当前存储为邻接列表: CREATE TABLE categories ( id int, name text, parent_id int); 它是只读的,我经常需要知道任何给定类别的根类别。因此,我想添加一个root_id列并将其持久化,以避免混乱的WHERE子句、cte等 我的第一次尝试是: update categories set root_id = parent.id from categories as child join categories
CREATE TABLE categories (
id int,
name text,
parent_id int);
它是只读的,我经常需要知道任何给定类别的根类别。因此,我想添加一个root_id列并将其持久化,以避免混乱的WHERE子句、cte等
我的第一次尝试是:
update categories set root_id = parent.id
from categories as child
join categories as parent
on child.parent_id = parent.id
and parent.parent_id is null;
但是UPDATE
无法处理连接。(此查询仅针对2级类别;我将针对第三级类别执行类似的查询。)
我知道答案包括将联接转换为子查询,但我不能同时考虑自联接和子查询。我们使用的是PostgreSQL 9.0,所以我没有可写的CTE(尽管我很好奇这个CTE看起来如何)
正确的方法是什么?您不需要在每个记录中存储根,您可以通过递归查询轻松找到它 追爷爷的小示范。(这里的约定是任何根都有一个parent_id=NULL;另一个约定可以是parent_id=id;YMMV) 结果:
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)
您不需要在每个记录中存储根,您可以通过递归查询轻松找到它 追爷爷的小示范。(这里的约定是任何根都有一个parent_id=NULL;另一个约定可以是parent_id=id;YMMV) 结果:
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)
我认为这很理想,但他明确表示,他不想或不能使用CTEWell,我不想在真正的查询中使用CTE(Rails/ActiveRecord不知道如何使用它们),但我不介意在更新中使用CTE,这非常有效-将编辑答案。如果您只想要“右值”(CTE),您可以在更新(或删除,或存在)查询的最右侧使用递归查询。您可以围绕它构建一个视图,生成给定id的祖父母。只是为了证明CTE不一定是乱七八糟的……是的,这正是我所做的(在更新的最右边使用它)。因为我还没有权限,所以有一个编辑待审核。。谢谢你教我CTE。我认为这很理想,但他明确表示他不想或不能使用CTEWell,我不想在真正的查询中使用CTE(Rails/ActiveRecord不知道如何使用它们),但我不介意在更新中使用CTE,这非常有效-将编辑答案。如果你只想要“右值”(CTE),您可以在更新(或删除,或存在)查询的最右侧使用递归查询。您可以围绕它构建一个视图,生成给定id的祖父母。只是为了证明CTE不一定是乱七八糟的……是的,这正是我所做的(在更新的最右边使用它)。因为我还没有权限,所以有一个编辑待审核。。谢谢你教我CTEs。