Условные агрегаты в T-SQL
134Работа с базами данных в .NET Framework --- Оконные функции T-SQL --- Условные агрегаты
Исходник базы данныхНаша следующая задача — вычисление нарастающих итогов, которые всегда возвращают неотрицательное значение. То есть, если нарастающий итог становится отрицательным, надо возвращать нуль. Далее, при переходе с следующему элементу последовательности, отсчет начинается с нуля. Вот код создания тестовой таблицы T1 и наполнения ее тестовыми данными:
USE TSQL2012;
IF OBJECT_ID('dbo.T1') IS NOT NULL DROP TABLE dbo.T1;
GO
CREATE TABLE dbo.T1
(
ordcol INT NOT NULL PRIMARY KEY,
datacol INT NOT NULL
);
INSERT INTO dbo.T1 VALUES
(1, 10),
(4, -15),
(5, 5),
(6, -10),
(8, -15),
(10, 20),
(17, 10),
(18, -10),
(20, -30),
(31, 20);
Вот требуемый результат, в котором вычисляется неотрицательная сумма значений datacol на основе упорядочения по ordcol:

Я покажу элегантное решение с применением оконных функций, разработанное Гордоном Линофф. Вот код готового решения и результат его работы (промежуточные операции по вычислению partsum и adjust представлены для удобства понимания):
WITH C1 AS
(
SELECT ordcol, datacol,
SUM(datacol) OVER (ORDER BY ordcol
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS partsum
FROM dbo.T1
),
C2 AS
(
SELECT *,
MIN(partsum) OVER (ORDER BY ordcol
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as adjust
FROM C1
)
SELECT *,
partsum - CASE WHEN adjust < 0 THEN adjust ELSE 0 END
AS nonnegativesum
FROM C2;
Код CTE-выражения C1 создает атрибут по имени partsum, содержащий простой нарастающий итог datacol с применением упорядочения по ordcol. Атрибут partsum может принимать негативное значение, потому что значения в datacol могут быть отрицательными. Затем код CTE-выражения C2 запрашивает C1, создавая атрибут по имени adjust, в котором вычисляется минимальное значение partsum вплоть до текущего момента. Наконец, внешний запрос проверяет, требуется ли корректировка partsum для вычисления неотрицательной суммы. Если adjust (на данный момент минимум partsum) неотрицательный, корректировка не требуется. При отрицательном же значении adjust этот атрибут нужно вычесть из partsum.
Может потребоваться несколько раз изучить результат работы, чтобы понять логику, но, уверяю вас, все работает, как надо!