SUM()OVER具有基于当前总和值的条件

时间:2014-08-23 14:36:54

标签: sql sql-server-2012

我有一张桌子(TableA),有点像这样:

Id  Type    TimeBlock   Value
1   1       1           100
2   1       1           150
3   2       1           100
4   1       1           1000
5   1       1           100
6   1       2           50
6   1       2           50

我希望能够通过TimeBlock对Value列进行SUM分区,但是根据某些条件我只想SUM行。如果当前总和值,则条件仅为SUM行 大于或等于值列

我假设查询将从以下内容开始:

DECLARE @Amount int = 500;
SELECT *, @Amount - SUM (Value) OVER (PARTITION BY TimeBlock ORDER BY Id) AS Sum
FROM TableA

我希望结果如下:

Id  Type    TimeBlock   Value   Sum
1   1       1           100     400     (500 - 100)
2   1       1           150     250     (400 - 150)
3   2       1           1000    NULL    (This does not count since its of type = 2 and 250 < 1000)
4   1       1           1000    0       (250 - 1000 = -750 there its filled the @Amount so we'll leave it at 0)
5   1       1           100     NULL    (Since @Amount has been filled anything that comes after in this time block is NULL)
6   1       2           50      450     (500 - 50)
6   1       2           50      400     (450 - 50)

正如您所看到的,我需要能够获取SUM函数的当前值,以便能够将其与Value列进行比较,而我不确定该如何操作。我希望能够做一些像

这样的事情
DECLARE @Amount int = 500;
SELECT *, @Amount - SUM (CASE WHEN Type = 2 AND SUM(Value) OVER (PARTITION BY TimeBlock ORDER BY Id) < Value THEN 0 ELSE Value END) OVER (PARTITION BY TimeBlock ORDER BY Id) AS Sum
FROM TableA

修改 Type = 1 - 无论如何,将Value列相加 Type = 2 - 如果当前总和值大于或等于Value

,则仅对行中的Value列求和

1 个答案:

答案 0 :(得分:0)

虽然它是基于有争议的运行总和古怪更新(由Jeff Moden here更详细地描述),但以下代码将起作用:

-- prepare temporary table with required clustered index to control processing order
create table #t (
     Id         int not null primary key nonclustered
    ,Type       int not null
    ,TimeBlock  int not null
    ,Value      int not null

    ,RunningSum int null

    ,unique clustered (TimeBlock,Id)
);

-- load temporary table from data source, 
-- hard-coded data used for this example.
insert #t(Id, Type,TimeBlock,Value)
values
 (1, 1,  1,    100)
,(2, 1,  1,    150)
,(3, 2,  1,    100)
,(4, 1,  1,   1000)
,(5, 1,  1,    100)
,(6, 1,  2,     50)
,(7, 1,  2,     50);

go

declare @sum        int = 0
       ,@TimeBlock  int = -1;

update #t
    set @sum = case when TimeBlock <> @TimeBlock then 500 - Value
                    when Value > @sum            then @sum

                    else @sum - Value
                end
       ,@TimeBlock = TimeBlock
       ,RunningSum = @sum
from #t with (TABLOCKX)
where Type = 1
option (MAXDOP 1)
;

-- display results
select * from #t

drop table #t;
go

输出:

Id          Type        TimeBlock   Value       RunningSum
----------- ----------- ----------- ----------- -----------
1           1           1           100         400
2           1           1           150         250
3           2           1           100         NULL
4           1           1           1000        250
5           1           1           100         150
6           1           2           50          450
7           1           2           50          400

特别注意,这要求聚簇索引与排序相同,并确保其他管理员不会修改此数据,将数据复制到具有所需聚簇索引的临时表中。此外,选项(MAXDOP 1)设置为确保优化程序不会尝试查询的并行化,并且进行EXCLUSIVE锁定以便(如果不需要临时表)不进行修改在处理过程中可能会出现表格。

更新 Quirky Update 是有争议的,因为虽然它已知自Sybase SQL Server早期起作用,但它依赖于SQL Server的未记录功能不保证在将来的版本中支持。