按月份和季度分组,并汇总前 11 个月

  • 本文关键字:个月 季度 sql sql-server
  • 更新时间 :
  • 英文 :


你好,我已经为此苦苦挣扎了大约一天了:/。我试图完成的是在同一查询中返回月份值和该季度的前 11 个月。

所以我有一张桌子

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(),或聚合partition的值,或对具有指定order by(row_number()rank()dense_rank()(的行进行排名。这利用了 12 行的特定窗口框架(前面的 11 行和当前行(以及以下代码段:sum(ThisMonth) over (order by Month rows 11 preceding).

窗口函数处理查询的结果集,这就是使用按月聚合的派生表的原因。由于您只需要给定季度中的行,因此请再次嵌套查询(通过将前两个行放在公用表表达式 (cte( 中(,以便在计算sum()时,不需要的行中的值仍包含在窗口框架中。

有关窗口功能的更多信息,特别是窗口框架: SQL Server 中的窗口函数:第 2 部分 - 框架 - Fabiano Amorim(英语: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求和,该表/子查询/cte 按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 |
+---------+-----------+------------+

您可以非常轻松地获得前两列:

select datename(month, date) as mon,
sum(case when dateadd(year, 1, date) > getdate()
then value else 0 
end) as this_month
from test t
group by datename(month, date)
order by min(date);

注意:如果您希望一切都基于月初,"本月"的确切定义可能会有所不同,但这就是想法。

对于第三列,可以使用apply或相关的子查询:

select datename(month, date) as mon,
sum(value) as this_month,
(select sum(t2.value)
from test t2
where t2.value >= dateadd(month, -11, min(t.date))
) as prev_11_months
from test t
where date >= dateadd(year, 1, getdate() )
group by datename(month, date)
order by min(date);

相关内容

最新更新