Суммарная работа SQL Server с dbmail, когда общая сумма достигнута или превышена

Я могу получить промежуточную сумму с помощью скрипта, но то, что я не могу сделать, это изолировать строку, в которой я встретил или превысил определенное значение...

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

В конечном счете, я хотел бы создать триггер для отправки dbmail, когда сумма столбца 1 соответствует или превышает (n)... помогите мне obi-wan


person Nick    schedule 21.03.2017    source источник
comment
Вы используете sql-сервер? Если да, то какое издание?   -  person McNets    schedule 21.03.2017
comment
да, sql-server 2008 r2 - я думал о том, чтобы создать это как представление, а затем отправить dbmail ... но будет ли это возможно автоматически или необходимо будет создать SP   -  person Nick    schedule 21.03.2017


Ответы (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 здесь

Хотя это решение работает хорошо, оно не рекомендуется с точки зрения производительности.

В этом случае лучше всего использовать КУРСОР.

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 здесь

Следующий ответ можно использовать в SQL-SERVER 2012 и более поздних версиях

Вы можете использовать кумулятивную сумму, используя функцию WINDOW и SUM() ROWS UNBOUNDED PRECEDING.

Просмотрите документы MS.

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 здесь

person McNets    schedule 21.03.2017
comment
Прошло некоторое время, но sum() закончилась в 2008 году? - person John Cappelletti; 21.03.2017
comment
@JohnCappelletti Я знаю, что документы MS не всегда верны, однако согласно MS это так. Но я подтвержу это. - person McNets; 21.03.2017
comment
Если нет, возможно, ПЕРЕКРЕСТНОЕ ПРИМЕНЕНИЕ - person John Cappelletti; 21.03.2017
comment
@JohnCappelletti это не принято в 2008 году. Я попробую с CROSS APPLY, спасибо. - person McNets; 21.03.2017
comment
@McNets... спасибо за вопросы... Что, если я хочу определить, какой идентификатор из cumTotal соответствует или превышает пороговое значение 300, и можно ли создать для этого триггер и запустить dbmail? Например, 300 — это цель, и отправляется уведомление или предупреждение о том, что это произошло. - person Nick; 22.03.2017
comment
@Nick, это должно быть по другому вопросу (добавьте ссылку на этот, если вы опубликуете его) - person ypercubeᵀᴹ; 22.03.2017