当达到或超过总数时,SQL Server使用dbmail运行总计

时间:2017-03-21 19:41:23

标签: sql-server tsql sql-server-2008-r2 running-total dbmail

我可以通过脚本获得一个总计 - 但我似乎无法做到的是隔离我遇到或超过某个值的行......

SELECT 
    column1, 
    (SELECT SUM(column1) FROM table WHERE column2 <= t1.column2)
FROM 
    table  t1 

最终我想要做的是创建一个触发器,当column1的sum达到或超过(n)时发送dbmail ...帮助我obi-wan

1 个答案:

答案 0 :(得分:1)

在SQL-Server 2008上,您可以使用下一个解决方案:

DECLARE @TBL TABLE(id int, amount int);
INSERT INTO @TBL VALUES
(1, 100), (2, 100), (3, 60), (4, 200), (5, 100);

SELECT     t1.ID, t1.amount, SUM(t2.amount) as CumTotal
FROM       @TBL t1
CROSS APPLY (SELECT *
       FROM @TBL
       WHERE ID <= t1.id) t2
GROUP BY   t1.ID, t1.amount
HAVING     SUM(t1.amount) < 300
ORDER BY   t1.ID
;

结果如下:

ID | amount | CumTotal
-: | -----: | -------:
 1 |    100 |      100
 2 |    100 |      200
 3 |     60 |      260

dbfiddle here

虽然此解决方案效果很好,但在性能方面并不值得推荐。

在这种情况下,最好的选择是使用CURSOR。

DECLARE @CS table (id int, amount int, total int);
DECLARE @id int, @amount int;
DECLARE @CumSum int = 0;
DECLARE c CURSOR
    LOCAL STATIC FORWARD_ONLY READ_ONLY
    FOR SELECT ID, amount
        FROM @TBL
        ORDER BY [id];

OPEN c;
FETCH NEXT FROM c INTO @id, @amount

WHILE @@FETCH_STATUS = 0 AND @CumSum + @amount < 300 
BEGIN
    SET @CumSum = @CumSum + @amount;
    INSERT @CS (id, amount,  total)
    SELECT @id, @amount, @CumSum;
    FETCH NEXT FROM c INTO @id, @amount
END

CLOSE c;
DEALLOCATE c;

SELECT   id, amount, total
FROM     @CS
ORDER BY id;
     

GO

id | amount | total
-: | -----: | ----:
 1 |    100 |   100
 2 |    100 |   200
 3 |     60 |   260

dbfiddle here

下一个答案可用于SQL-SERVER 2012及更高版本

您可以使用WINDOW函数和SUM()ROWS UNBOUNDED PRECEDING来使用累积和。

查看MS docs

DECLARE @TBL TABLE(id int, amount int);
INSERT INTO @TBL VALUES
(1, 100), (2, 100), (3, 60), (4, 200), (5, 100);

下一个查询返回累计总和:

SELECT ID, 
       SUM(amount) OVER (ORDER BY ID ROWS UNBOUNDED PRECEDING) AS CumTotal
FROM   @TBL
;
ID | CumTotal
-: | -------:
 1 |      100
 2 |      200
 3 |      260
 4 |      460
 5 |      560

问题是您无法阻止它,您需要计算所有记录,然后您可以应用where子句来过滤记录。

WITH CSum As
(
    SELECT ID, 
           SUM(amount) OVER (ORDER BY ID ROWS UNBOUNDED PRECEDING) AS CumTotal
    FROM   @TBL
)
SELECT   ID, CumTotal
FROM     CSum
WHERE    CumTotal < 300
ORDER BY ID
;

这是最终结果:

 
ID | CumTotal
-: | -------:
 1 |      100
 2 |      200
 3 |      260

dbfiddle here