你好,我已经为此苦苦挣扎了大约一天:/。我想要完成的是在同一个查询中返回月份值和该季度之前 11 个月的值。
所以我有一张 table
CREATE TABLE Test
(
Id INT,
Date DATETIME2,
Value DECIMAL(15,4)
)
我正在尝试获取如下数据:
This Month Previous_11_Months
January 100 1100
February 123 1123
March 211 2123
我的实际Sql:
DECLARE @endDate DATETIME2 = '6-30-2017',
@plantId INT = 1
DECLARE @endDateMinusYear DATETIME2 = DATEADD(YEAR,-1,@endDate),
@firstDayOfThisQuarter DATETIME2,
@firstDayOfThisQuarterLastYear DATETIME2
SELECT @firstDayOfThisQuarter = DATEADD(QQ, DATEDIFF(QQ , 0, @endDate), 0)
SELECT @firstDayOfThisQuarterLastYear = DATEADD(QQ, DATEDIFF(QQ , 0, @endDateMinusYear), 0)
SELECT
DATENAME(MONTH, PlantPollutions.Date) AS MONTH,
SUM(PlantPollutions.BurnerNaturalGas + PlantPollutions.OilHeaterNaturalGas) AS THIS_MONTH,
(
SELECT
SUM(SubPlantPollutions.BurnerNaturalGas + SubPlantPollutions.OilHeaterNaturalGas)
FROM PlantPollutions AS SubPlantPollutions
WHERE SubPlantPollutions.Date >= DATEADD(MONTH, -11, PlantPollutions.Date)
GROUP BY SubPlantPollutions.Date
) AS PREVIOUS_11_MONTHS
FROM PlantPollutions
WHERE PlantPollutions.PlantId = @plantId
AND PlantPollutions.Date >= @firstDayOfThisQuarter
GROUP BY DATENAME(MONTH, PlantPollutions.Date)
当我在子查询中注释掉WHERE SubPlantPollutions.Date >= DATEADD(MONTH, -11, PlantPollutions.Date)
GROUP BY SubPlantPollutions.Date
它有效
最佳答案
窗口函数通常用于获取上一行或下一行值,例如使用 lead()
和 lag()
,或者聚合 的值分区
,或按指定的顺序
对行进行排名(row_number()
、rank()
、dense_rank()
)。这利用了 12 行(前 11 行和当前行)的特定窗口框架,并带有以下代码段:sum(ThisMonth) over (order by Month rows 11 previous)
。
窗口函数作用于查询的结果集,这就是使用按月聚合的派生表的原因。由于您只需要给定季度的行,因此再次嵌套查询(通过将前两个放在 common table expression (cte) 中),以便当 sum 时,您不需要的行中的值仍包含在窗口框架中()
进行计算。
有关窗口函数,特别是窗口框架的更多信息: Window Functions in SQL Server: Part 2-The Frame - Fabiano Amorim
更新问题的更新代码:
declare @EndDate datetime2(0) = '20170630';
;with cte as (
select
Month
, ThisMonth
, Previous_11_Months = sum(ThisMonth) over (order by Month rows 11 preceding)
from (
select
Month = dateadd(month, datediff(month, 0, t.Date), 0) -- truncate date to month
, ThisMonth = sum(Value)
from dbo.Test t
where t.Date >= dateadd(year, -1, dateadd(quarter, datediff(quarter, 0, @EndDate), 0))
group by dateadd(month, datediff(month, 0, t.Date), 0) -- truncate date to month
) s
)
select
MonthName = datename(Month,Month)
, ThisMonth
, Previous_11_Months
from cte
where month >= dateadd(quarter, datediff(quarter, 0, @EndDate), 0)
rextester 演示:http://rextester.com/OBVR79198
+-----------+-----------+--------------------+
| MonthName | ThisMonth | Previous_11_Months |
+-----------+-----------+--------------------+
| April | 218 | 2291 |
| May | 202 | 2312 |
| June | 189 | 2357 |
| July | 207 | 2335 |
+-----------+-----------+--------------------+
在 SQL Server 2012+ 中,您可以使用窗口函数对当前月份和之前 11 个月进行求和,并使用派生表/子查询/cte 对 Value
按 Month
求和> 像这样:
select
Month = convert(char(7),Month,120)
, ThisMonth
, RollingSum = sum(ThisMonth) over (order by Month rows 11 preceding)
from (
select
Month = dateadd(month, datediff(month, 0, t.Date), 0) -- truncate date to month
, ThisMonth = sum(Value)
from dbo.Test t
group by dateadd(month, datediff(month, 0, t.Date), 0) -- truncate date to month
) s
rextester 演示:http://rextester.com/UTLDP89935
返回:
+---------+-----------+------------+
| Month | ThisMonth | RollingSum |
+---------+-----------+------------+
| 2015-07 | 214 | 214 |
| 2015-08 | 195 | 409 |
| 2015-09 | 182 | 591 |
| 2015-10 | 168 | 759 |
| 2015-11 | 185 | 944 |
| 2015-12 | 152 | 1096 |
| 2016-01 | 165 | 1261 |
| 2016-02 | 186 | 1447 |
| 2016-03 | 212 | 1659 |
| 2016-04 | 232 | 1891 |
| 2016-05 | 193 | 2084 |
| 2016-06 | 168 | 2252 |
| 2016-07 | 174 | 2212 |
| 2016-08 | 213 | 2230 |
| 2016-09 | 195 | 2243 |
| 2016-10 | 217 | 2292 |
| 2016-11 | 200 | 2307 |
| 2016-12 | 200 | 2355 |
| 2017-01 | 225 | 2415 |
| 2017-02 | 202 | 2431 |
| 2017-03 | 192 | 2411 |
| 2017-04 | 175 | 2354 |
| 2017-05 | 220 | 2381 |
| 2017-06 | 186 | 2399 |
| 2017-07 | 205 | 2430 |
+---------+-----------+------------+
关于sql - 按月和季度分组并汇总前 11 个月,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45399595/