sql - 按月计算的值总和,其中数据包含开始日期和结束日期

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

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

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

我想创建一个 View ,每个月/项目呈现一条记录,显示该月“值”列的总和。示例:

+----+-------+---------+-------+
| 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 显示项目 AAA 从 2018 年 4 月 12 日起获得额外值 50。这意味着 4 月及以后的 SUM 应为 150。

对于项目 BBB,您会看到一个项目已于 2018 年 3 月 1 日结束。这意味着截至 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);

最佳答案

您只需要构建一个介于 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)) 函数用于生成指定日期的月初。

关于sql - 按月计算的值总和,其中数据包含开始日期和结束日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53517897/

相关文章:

mysql - 在mysql中一行显示来自一个ID的单词

sql-server - 如何解码 D7 中的 XML Blob 字段

mysql - 从日期格式中删除字母并保存在 sql 表的下一列中

mysql - 使用when子句设置行数据

sql - Like 从句的模式匹配

sql-server - 通过 ODBC 调用 SQL Server 存储过程失败,留下空表

sql - 查找并删除表中允许多次出现记录的重复行

c# - 从 FormView 中的 TextBox 获取日期时间值

python - pandas to_timedelta 忽略单位参数?

mysql - 根据最大值删除一行