Сумма значений по месяцам, где данные содержат даты начала и окончания - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть простая таблица, содержащая проекты с определенным значением, которые активны между начальной и конечной датой.Это выглядит так:

+----+---------+------------+------------+-------+
| Id | Project | StartDate  |  EndDate   | Value |
+----+---------+------------+------------+-------+
|  1 | AAA     | 2018-01-01 | NULL       |   100 |
|  2 | AAA     | 2018-04-12 | NULL       |   50  |
|  3 | BBB     | 2018-01-01 | 2018-03-01 |   20  |
|  4 | BBB     | 2018-01-01 | NULL       |   200 |
+----+---------+------------+------------+-------+

Я хочу создать представление, которое отображает одну запись в месяц / проект, отображающую сумму столбца Значение в этом месяце.Пример:

+----+-------+---------+-------+
| Id | Month | Project | Value |
+----+-------+---------+-------+
|  1 | JAN   | AAA     |   100 |
|  2 | FEB   | AAA     |   100 |
|  3 | MAR   | AAA     |   100 |
|  4 | APR   | AAA     |   150 |
|  5 | MAY   | AAA     |   150 |
|  6 | JUN   | AAA     |   150 |
|  7 | JAN   | BBB     |   220 |
|  8 | FEB   | BBB     |   220 |
|  9 | MAR   | BBB     |   220 |
| 10 | APR   | BBB     |   200 |
| 11 | MAY   | BBB     |   200 |
| 12 | JUN   | BBB     |   200 |
+----+-------+---------+-------+

День месяца не имеет значения.Например, идентификатор 2 из таблицы проектов показывает, что проект AAA получает дополнительное значение 50 по состоянию на 2018-04-12.Это означает, что СУММА апреля и последующих должна быть 150.

Для проекта BBB вы видите, что проект завершен в 2018-03-01.Это означает, что сумма BBB должна быть уменьшена с 20 на АПРЕЛЬ (не март!), Потому что проект все еще был активным в марте.

Я хочу сделать месяцы до текущего месяца (дата выполнения запроса)).Так что в моем примере я выполнил этот запрос где-то в июне 2018 года.

Это должно быть выполнено на SQL Server 2012.

Вот сценарии для таблицы и некоторые фиктивные данные:

CREATE TABLE [TestProject] (
    [Id] INT IDENTITY(1,1) PRIMARY KEY,
    [Project] NVARCHAR(50) NOT NULL,
    [StartDate] DATE NOT NULL,
    [EndDate] DATE NULL,
    [Value] INT NOT NULL
)

INSERT INTO [TestProject] ([Project], [StartDate], [EndDate], [Value])
VALUES
('AAA','2018-01-01',NULL,100),
('AAA','2018-04-12',NULL,50),
('BBB','2018-01-01','2018-03-01',200),
('BBB','2018-01-01',NULL,20);

1 Ответ

0 голосов
/ 28 ноября 2018

Вам просто нужно построить список дат между MIN (StartDate) и сегодняшним днем, остальное просто:

DECLARE @TestProject TABLE (Id INT IDENTITY(1, 1) PRIMARY KEY, Project NVARCHAR(50) NOT NULL, StartDate DATE NOT NULL, EndDate DATE NULL, Value INT NOT NULL);
INSERT INTO @TestProject VALUES
('AAA', '2018-01-01', NULL, 100),
('AAA', '2018-04-12', NULL, 50),
('BBB', '2018-01-01', '2018-03-01', 200),
('BBB', '2018-01-01', NULL, 20);

WITH cte AS (
    SELECT DATEADD(DAY, 1, EOMONTH((SELECT MIN(StartDate) FROM @TestProject), -1)) AS ym
    UNION ALL
    SELECT DATEADD(MONTH, 1, ym)
    FROM cte
    WHERE DATEADD(MONTH, 1, ym) <= CURRENT_TIMESTAMP
)

SELECT ym, Project, SUM(Value)
FROM cte
LEFT JOIN @TestProject ON DATEADD(DAY, 1, EOMONTH(StartDate, -1)) <= ym AND (
    EndDate IS NULL OR ym <= DATEADD(DAY, 1, EOMONTH(EndDate, -1))
)
GROUP BY ym, Project

В приведенном выше примере функция DATEADD(DAY, 1, EOMONTH(expr, -1)) используется для генерации начала месяцана указанную дату.

...