Условные агрегаты в T-SQL

134 Исходник базы данных

Наша следующая задача — вычисление нарастающих итогов, которые всегда возвращают неотрицательное значение. То есть, если нарастающий итог становится отрицательным, надо возвращать нуль. Далее, при переходе с следующему элементу последовательности, отсчет начинается с нуля. Вот код создания тестовой таблицы 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.

Может потребоваться несколько раз изучить результат работы, чтобы понять логику, но, уверяю вас, все работает, как надо!

Пройди тесты
Лучший чат для C# программистов