Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL:在三级树中持久化根目录id?_Sql_Postgresql_Self Join_Adjacency List - Fatal编程技术网

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。