如何编写 CTE 来聚合分层值
How to write a CTE to aggregate hierarchical values
我想在 sqlite 中编写表达式来处理项目树,从叶节点(底部)开始,然后返回到它们的 parents 一直到根节点(顶部) ,这样每个 parent 节点都会根据其 children 的内容进行更新。我已经能够编写一个 CTE 来做类似的事情,但还不完全正确。
我有一个简单的 table "test1" 包含一些嵌套值:
id | parent | value | total
---+--------+--------------
1 | NULL | NULL | NULL
2 | 1 | NULL | NULL
3 | 2 | NULL | NULL
4 | 3 | 50 | NULL
5 | 3 | 50 | NULL
6 | 2 | 60 | NULL
7 | 6 | 90 | NULL
8 | 6 | 60 | NULL
行可能有 child人通过 parent
字段引用他们的 parent。行可能有它们自己的值以及 child 行,或者它们可能只是 parent 没有值(即 "wrappers")。叶子将是没有任何 children.
的行
对于每一行,我想计算 total
,作为平均值或该行的 value
(如果不为空)及其 children 的 total
秒。这应该从叶节点开始,然后沿着树向上移动到它们的 parents,一直到数据层次结构顶部的根节点。
我已经尝试了多种 CTE 的变体,但我很难编写一个能够自下而上递归计算这些总数的变体。
目前,我有:
UPDATE test1 SET total = (
WITH RECURSIVE cte(cte_id,cte_parent,cte_value,cte_total) AS (
SELECT test1.id, test1.parent, test1.value, test1.total
UNION ALL
select t.id, t.parent, t.value, t.total from test1 t, cte
WHERE cte.cte_id=t.parent
) SELECT AVG(cte_value) FROM cte
);
产生:
id | parent | value | total
---+--------+-------+------
1 | NULL | NULL | 62
2 | 1 | NULL | 62
3 | 2 | NULL | 50
4 | 3 | 50 | 50
5 | 3 | 50 | 50
6 | 2 | 60 | 70
7 | 6 | 90 | 90
8 | 6 | 60 | 60
查看 top-most 行,这不太正确,因为它不仅取该行直接 children 的平均值,而且取 all[=37] 的平均值=] 该行的后代。例如,这会导致第 2 行的 total
为 62 而不是 60。预期结果应将第 2 行的总数设置为 60,作为其直接 child 第 3 行和第 6 行的平均值。第 1 行的总数也将是 60。
我如何根据行值的平均值及其直接 children 的值计算每行的 "total" 值,同时确保层次结构的上层是根据 children?
的计算总数正确填充
原来在这里发布了一个非常相似的问题和解决方案:
由于 sqlite3 不允许您创建函数,因此适用使用递归 CTE 的示例:
with recursive cte(id, parent, value, level, total) as (
select
t.id, t.parent, t.value,
0,
t.value as total
from test1 t
where not exists (
select id
from test1
where parent = t.id)
union all
select
t.id, t.parent, t.value,
c.level+1,
case when t.value is null then c.total else t.value end
from test1 t
join cte c on t.id=c.parent
)
select id, parent, value, avg(total) total from (
select
id, parent, value, level, avg(total) total
from cte
group by id,parent,level
)
group by id, parent
order by id
我想在 sqlite 中编写表达式来处理项目树,从叶节点(底部)开始,然后返回到它们的 parents 一直到根节点(顶部) ,这样每个 parent 节点都会根据其 children 的内容进行更新。我已经能够编写一个 CTE 来做类似的事情,但还不完全正确。
我有一个简单的 table "test1" 包含一些嵌套值:
id | parent | value | total
---+--------+--------------
1 | NULL | NULL | NULL
2 | 1 | NULL | NULL
3 | 2 | NULL | NULL
4 | 3 | 50 | NULL
5 | 3 | 50 | NULL
6 | 2 | 60 | NULL
7 | 6 | 90 | NULL
8 | 6 | 60 | NULL
行可能有 child人通过 parent
字段引用他们的 parent。行可能有它们自己的值以及 child 行,或者它们可能只是 parent 没有值(即 "wrappers")。叶子将是没有任何 children.
对于每一行,我想计算 total
,作为平均值或该行的 value
(如果不为空)及其 children 的 total
秒。这应该从叶节点开始,然后沿着树向上移动到它们的 parents,一直到数据层次结构顶部的根节点。
我已经尝试了多种 CTE 的变体,但我很难编写一个能够自下而上递归计算这些总数的变体。
目前,我有:
UPDATE test1 SET total = (
WITH RECURSIVE cte(cte_id,cte_parent,cte_value,cte_total) AS (
SELECT test1.id, test1.parent, test1.value, test1.total
UNION ALL
select t.id, t.parent, t.value, t.total from test1 t, cte
WHERE cte.cte_id=t.parent
) SELECT AVG(cte_value) FROM cte
);
产生:
id | parent | value | total
---+--------+-------+------
1 | NULL | NULL | 62
2 | 1 | NULL | 62
3 | 2 | NULL | 50
4 | 3 | 50 | 50
5 | 3 | 50 | 50
6 | 2 | 60 | 70
7 | 6 | 90 | 90
8 | 6 | 60 | 60
查看 top-most 行,这不太正确,因为它不仅取该行直接 children 的平均值,而且取 all[=37] 的平均值=] 该行的后代。例如,这会导致第 2 行的 total
为 62 而不是 60。预期结果应将第 2 行的总数设置为 60,作为其直接 child 第 3 行和第 6 行的平均值。第 1 行的总数也将是 60。
我如何根据行值的平均值及其直接 children 的值计算每行的 "total" 值,同时确保层次结构的上层是根据 children?
的计算总数正确填充原来在这里发布了一个非常相似的问题和解决方案:
由于 sqlite3 不允许您创建函数,因此适用使用递归 CTE 的示例:
with recursive cte(id, parent, value, level, total) as (
select
t.id, t.parent, t.value,
0,
t.value as total
from test1 t
where not exists (
select id
from test1
where parent = t.id)
union all
select
t.id, t.parent, t.value,
c.level+1,
case when t.value is null then c.total else t.value end
from test1 t
join cte c on t.id=c.parent
)
select id, parent, value, avg(total) total from (
select
id, parent, value, level, avg(total) total
from cte
group by id,parent,level
)
group by id, parent
order by id