SQL 递归部分求和

Posted

技术标签:

【中文标题】SQL 递归部分求和【英文标题】:SQL Recursive partial sum 【发布时间】:2016-11-22 10:35:30 【问题描述】:

我有两张桌子:

主表

...
startSubNr
endSubNr
...

步骤

...
nrFrom
nrTo
value
...

MasterTable 包含例如:

startSubNr: 2
endSubNr: 16

步骤包含例如:

nrFrom: 2
nrTo: 19
value: 20

nrFrom: 1
nrTo: 2
value: 10

nrFrom: 19
nrTo: 5
value: 100

nrFrom: 5
nrTo: 16
value: 200

nrFrom: 4
nrTo: 5
value: 50

我需要的是一个 sql 查询(它应该在 SQL-Server 和 sqlite 上工作)来计算从 startnr 到 endnr 的总和,其中步骤数可能会有所不同。步骤(从到到)是独一无二的。

在这个例子中,它必须总结 20 (2-19), 100 (19-5 em>) 和 200 (5-16),而忽略 1-2 和 4-5 的值。

有没有办法在 sql 中做到这一点而不必使用多个查询?

【问题讨论】:

为什么忽略其他两个值..? 因为在 Mastertable 中我有 startSubNr= 2 和 endSubNr= 16。在 Steps 表中,我搜索以 nrFrom 2 开头的步骤(nrTo 为 19,值为 20)。然后我搜索 nrFrom 19 的步骤(nrTo 为 5,值为 100),依此类推。我这样做直到达到 endNr 16 的 Step 并总结所有步骤的值。 【参考方案1】:
    CREATE TABLE #Steps(nrFrom INT,nrTo INT ,value INT) DECLARE @Start INT = 2,@End INT = 16

    INSERT INTO #Steps(nrFrom ,nrTo ,value ) SELECT 2,19,20 UNION ALL SELECT 1,2,10 UNION ALL SELECT 19,5,100 UNION ALL SELECT 5,16,200 UNION ALL SELECT 4,5,50

    ;WITH _SumCTE (_From , _To , _Value )AS ( SELECT nrFrom ,nrTo,value FROM #Steps WHERE nrFrom = @Start UNION ALL SELECT _To , nrTo , value FROM #Steps JOIN _SumCTE ON _To = nrFrom and nrTo != @End

    )

    SELECT SUM(_Value) FROM _SumCTE

【讨论】:

这不处理终点 - 如果您将 UNION ALL SELECT 16,4,500 添加到您的数据中,它会以最大递归方式爆炸 检查到底是不是真的不见了。否则它工作正常。谢谢!【参考方案2】:

这个递归查询做你想做的事,但有一些附加条件

如果无法到达所需的端点(例如 @end 为 1000),它将引发最大递归错误 它假定 nrFrom 是唯一的;如果给定的 nrFrom 有多个“路径”,你会得到奇怪的结果 循环路径会导致最大递归错误 sql 可能不是做这个逻辑的地方!

创建表#step(nrFrom int, nrTo int, value int);

insert into #step values(2,19,20);
insert into #step values(1,2,10);
insert into #step values(19,5,100);
insert into #step values(5,16,200);
insert into #step values(4,5,50);
insert into #step values(16,4,500); -- add this to check we dont go further once we reach 16

declare @start int = 2;
declare @end int = 16;

with cte(nrTo, val) as
(
    select nrTo, value
    from #step
    where nrFrom = @start

    union all

    select #step.nrTo, value
    from cte
    inner join #step on #step.nrFrom = cte.nrTo
    and #step.nrFrom != @end 
) 
select sum(val)
from cte

【讨论】:

需要关卡吗?您只需要终点的值。

以上是关于SQL 递归部分求和的主要内容,如果未能解决你的问题,请参考以下文章

递归:数组分治求和

递归求和函数,我如何限制总和?

递归:单链表求和

递归:单链表求和

java递归阶乘求和,附小技巧

锚和递归查询“CTE”列“ColumnName”中的递归部分之间的类型不匹配