我想使用下表来计算z:
项目 | 价值 |
---|---|
a | 6 |
b | 8 |
组 | 来源_项目 | 加权 |
---|---|---|
x | a | 1 |
x | b | 0.25 |
y | a | 1 |
组 | 来源_组 | 加权 |
---|---|---|
y | x | 0.5 |
z | x | 1 |
z | y | 1 |
作为人类,我会通过计算来解决:
x = 1a + 0.25b = 8
y = 1a + 0.5x = 10
z = 1x + 1y = 18
然而,我正在努力寻找一种在 SQL 中执行此操作的干净方法。
通过使用递归 CTE,我可以相当轻松且(我希望)干净地获得操作顺序 - 如下:
WITH RECURSIVE
iterations AS (
--start by getting the groups that aren't dependent on other groups
SELECT
g.group
, 1 AS iteration
FROM
groups AS g
LEFT JOIN groups_groups AS gg
ON gg.source_group = g.group
WHERE
gg.source_group IS NULL
--traverse dependencies upwards
UNION ALL
SELECT
gg.group
, i.iteration + 1 AS iteration
FROM
iterations AS i
LEFT JOIN groups_groups AS gg
ON gg.source_group = i.group
)
--filter to max iteration
SELECT DISTINCT
i.group
, MAX(i.iteration) OVER (PARTITION BY i.group) AS iteration
FROM
iterations AS i
ORDER BY
iteration
这将返回订单如下:
组 | 迭代 |
---|---|
x | 1 |
y | 2 |
z | 3 |
从这里开始,我计划使用另一个递归树来进行迭代并计算值。但是,由于您只能加入最后一个递归,因此当您到达 z 时,x 的值将无法访问。我可能可以通过每次递归提取所有值,并在
iteration + 1
上进行一些连接,以确保循环适当结束,但我开始感觉到这不可能是“正确”的做事方式。
有没有更简单、更干净等的方法来解决这个问题?
我觉得你想多了。您不需要知道操作顺序(除非涉及括号)。
首先计算
groups_items
和 items
的总和,然后递归 groups_groups
,最后将总和加到 group
。
WITH RECURSIVE cte AS (
SELECT
gi."group",
SUM(i.value * gi.weighting) AS total
FROM groups_items gi
JOIN items i ON i.item = gi.source_item
GROUP BY
gi."group"
UNION ALL
SELECT
gg."group",
cte.total * gg.weighting AS total
FROM cte
JOIN groups_groups gg ON gg.source_group = cte."group"
)
SELECT
cte."group",
SUM(cte.total) AS total
FROM cte
GROUP BY
cte."group";