【问题标题】:Sum of value by month where data contains start and end dates按月计算的值总和,其中数据包含开始日期和结束日期
【发布时间】:2019-04-30 06:28:03
【问题描述】:

我有一个简单的表格,其中包含在开始日期和结束日期之间处于活动状态的具有特定值的项目。它看起来像这样:

+----+---------+------------+------------+-------+
| 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 |
+----+---------+------------+------------+-------+

我想创建一个视图,该视图每月/项目呈现一条记录,显示该月 Value 列的总和。示例:

+----+-------+---------+-------+
| 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 |
+----+-------+---------+-------+

月份中的哪一天无关紧要。例如,项目表中的 ID 2 显示,截至 2018 年 4 月 12 日,项目 AAA 获得了 50 的附加值。这意味着 4 月及以后的 SUM 应为 150。

对于 BBB 项目,您会看到一个项目于 2018-03-01 结束。这意味着截至 4 月(不是 3 月!),BBB 的总和应该减少 20,因为该项目在 3 月仍处于活动状态。

我想呈现到当前月份(查询执行日期)之前的月份。 所以在我的例子中,我在 2018 年 6 月的某个地方执行了这个查询。

这必须在 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);

【问题讨论】:

  • 为什么项目结束时BBB会减少20?怎么200还在,项目结束后判断一个值是否不再包含的规则是什么?
  • 我的错,应该是 20 的值才结束。当到达结束日期时,该值不再包含在接下来的几个月中。编辑了帖子。
  • 您使用的是什么版本的 SQL Server?
  • 这必须在 SQL Server 2012 上运行

标签: sql sql-server datetime sql-server-2012


【解决方案1】:

你只需要在 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)) 函数用于生成指定日期的月初。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-21
    • 2023-03-17
    • 1970-01-01
    • 2022-07-13
    • 2021-09-26
    相关资源
    最近更新 更多