GROUP BY和聚合日期范围

时间:2015-04-16 20:56:59

标签: sql sql-server tsql

SELECT IsConfirmed, IsNetConfirmed, d.FullDate FROM Final.FactApplication f 
INNER JOIN final.DimOfferedDate d on f.OfferedDateKey= d.OfferedDateKey
WHERE d.CalendarYear in ('2013','2014','2015')

上面的代码返回以下示例数据。

IsConfirmed IsNetConfirmed  FullDate
----------------------------------------------  
1           0               2013-01-04 00:00:00.000   
1           1               2013-02-04 00:00:00.000
0           1               2013-03-04 00:00:00.000
1           0               2013-04-04 00:00:00.000

我希望每年每天和每月汇总IsConfirmed和IsNetConfirmed的总和,以便最终获得以下结果。我需要汇总每年,以便2012年4月31日的总和包括1/1 / 2012-4 / 31/2012之间的数据。 enter image description here

到目前为止,这是我的代码 - 但我无法围绕所有分组。求助。

SELECT sum(IsConfirmed) AS ConfirmCount
    ,sum(IsNetConfirmed) AS NetConfirmCount
    ,year(d.fulldate) AS cyear
    ,month(d.fulldate) AS cmonth
    ,day(d.fulldate) AS cday
FROM final.FactApplicationHistory f
INNER JOIN final.DimOfferedDate d ON f.OfferedDateKey = d.OfferedDateKey
WHERE d.CalendarYear IN ('2013','2014','2015')
GROUP BY year(d.fulldate)
    ,month(d.fulldate)
    ,day(d.fulldate)
ORDER BY year(d.fulldate)

2 个答案:

答案 0 :(得分:1)

运行总和很棘手。你只能通过一组来实现它们。有几种方法可以做到这一点。一种方法是将数据表与其自身连接在与当前记录的值小于或等于的所有记录上,并对数据点求和。由于您还想转动数据,因此您的查询尤其复杂。以下是使用表连接方法的方法:

;with temp (IsConfirmed, IsNetConfirmed, FullDate) AS
(
SELECT IsConfirmed, IsNetConfirmed, FullDate
FROM final.FactApplicationHistory f
INNER JOIN final.DimOfferedDate d 
ON f.OfferedDateKey = d.OfferedDateKey
WHERE d.CalendarYear IN ('2013','2014','2015')
)
, pivottable (cmonthday,cmonth,cday,ConfirmCount2013,NetConfirmCount2013,ConfirmCount2014,NetConfirmCount2014,ConfirmCount2015,NetConfirmCount2015) AS
(
    SELECT
        dateadd(day,cday,(DATEADD(month, cmonth, 0))) cmonthday,
        cmonth,
        cday,
        sum(isnull([2013],0)) ConfirmCount2013, 
        sum(isnull([2016],0)) NetConfirmCount2013, 
        sum(isnull([2014],0)) ConfirmCount2014, 
        sum(isnull([2017],0)) NetConfirmCount2014, 
        sum(isnull([2015],0)) ConfirmCount2015, 
        sum(isnull([2018],0)) NetConfirmCount2015
    FROM 
        (SELECT sum(IsConfirmed) AS ConfirmCount
            ,sum(IsNetConfirmed) AS NetConfirmCount
            ,year(d.FullDate) AS cyear
            ,year(d.FullDate)+3 AS cyear2
            ,month(d.FullDate) AS cmonth
            ,day(d.FullDate) AS cday
        FROM #temp d
        WHERE year(FullDate) IN ('2013','2014','2015')
        GROUP BY year(d.FullDate)
            ,month(d.FullDate)
            ,day(d.FullDate)
        ) ps
    PIVOT
    (
    SUM (ConfirmCount)
    FOR cyear IN
    ( [2013],[2014],[2015])
    ) AS pvt
    PIVOT
    (
    SUM (NetConfirmCount)
    FOR cyear2 IN
    ( [2016],[2017],[2018])
    ) AS pvt
    Group by cmonth,
        cday
)
select
    pivottable.cmonth,
    pivottable.cday,
    sum(RunningSums.ConfirmCount2013) ConfirmCount2013, 
    sum(RunningSums.NetConfirmCount2013) NetConfirmCount2013, 
    sum(RunningSums.ConfirmCount2014) ConfirmCount2014, 
    sum(RunningSums.NetConfirmCount2014) NetConfirmCount2014, 
    sum(RunningSums.ConfirmCount2015) ConfirmCount2015, 
    sum(RunningSums.NetConfirmCount2015) NetConfirmCount2015
from pivottable
join pivottable RunningSums
on RunningSums.cmonthday <= pivottable.cmonthday
group by pivottable.cmonth,pivottable.cday
order by pivottable.cmonth, pivottable.cday

我认为这甚至可能是光标实际上是个好主意的情况。您可以将输出数据透视表数据创建到表中,然后迭代每个记录并使用运行总和更新每个值。对于包含数百万条记录的非常大的表,这可能比我的自联接方法更有效。

答案 1 :(得分:1)

首先,您需要生成所有可能的月 - 日和年组合。例如,2013年您的日期为1月1日至1月5日,2014年1月3日至1月6日。您应该在2013年1月至2014年1月1日至1月6日期间。获取所有日期后,使用原始查询JOIN,以便每个新生成的日期都具有IsConfirmedIsNetConfirmed的值。从那里,你获得了总计。最后,您需要PIVOT运行总计来获得所需的结果。

这是使用交叉表的动态方法。您可以阅读此article以供参考。

SQL Fiddle

DECLARE @sql1 VARCHAR(4000) = '',
        @sql2 VARCHAR(4000) = '',
        @sql3 VARCHAR(4000) = ''

SELECT @sql1 =
';WITH SampleData AS( -- Replace this CTE with the original query
    SELECT * FROM Data
)
,CrossDates AS( -- Generate date combinations
    SELECT
        YY, MM, DD,
        FullDate = DATEADD(DAY, DD - 1, DATEADD(MONTH, MM - 1, DATEADD(YEAR, YY - 1900, 0)))        
    FROM (
        SELECT DISTINCT
            MM = MONTH(FullDate),
            DD = DAY(FullDate)
        FROM SampleData
    )DM
    CROSS JOIN(
        SELECT DISTINCT YY = YEAR(FullDate) FROM SampleData
    )Y
)
,CteAllDates AS( -- Assign value for each newly generated date
    SELECT
        c.*,
        IsConfirmed = ISNULL(s.IsConfirmed, 0),
        IsNetConfirmed = ISNULL(s.IsNetConfirmed, 0)
    FROM CrossDates c
    LEFT JOIN SampleData s
        ON s.FullDate = c.FullDate
)
,RunningTotal AS( -- Compute running total
    SELECT
        YY = YEAR(FullDate),
        MM = MONTH(FullDate),
        DD = DAY(FullDate),
        Confirm = SUM(CAST(IsConfirmed AS INT)) OVER(PARTITION BY YEAR(FullDate) ORDER BY MONTH(FullDate), DAY(FullDate)),
        NetConfirm = SUM(CAST(IsNetConfirmed AS INT)) OVER(PARTITION BY YEAR(FullDate) ORDER BY MONTH(FullDate), DAY(FullDate))
    FROM CteAllDates
)
SELECT
      MM
    , DD
'

SELECT @sql2 = @sql2 +
'   , MAX(CASE WHEN YY = ' + CONVERT(VARCHAR(4), YY) + ' THEN Confirm ELSE 0 END) AS [' + CONVERT(VARCHAR(4), YY) + ' Confirm]' + CHAR(10) +
'   , MAX(CASE WHEN YY = ' + CONVERT(VARCHAR(4), YY) + ' THEN NetConfirm ELSE 0 END) AS [' + CONVERT(VARCHAR(4), YY) + ' NetConfirm]' + CHAR(10)
FROM(
    SELECT DISTINCT YY = YEAR(FullDate)
    FROM(
        SELECT * FROM Data -- Replace this with the original query
    )d
)t

SELECT @sql3 = 
'FROM RunningTotal
GROUP BY MM, DD'

PRINT(@sql1 + @sql2 + @sql3)
EXEC(@sql1 + @sql2 + @sql3)

注意:

1。将SampleData替换为原始查询。

2。 SUM() OVER()用于获取运行总计。

3。基本上,用您的oqriginal查询替换SELECT * FROM Data


示例数据

IsConfirmed IsNetConfirmed FullDate
----------- -------------- -----------------------
1           0              2013-04-01 00:00:00.000
1           1              2013-04-02 00:00:00.000
0           1              2013-04-03 00:00:00.000
1           0              2013-04-04 00:00:00.000
1           0              2014-04-01 00:00:00.000
1           1              2014-04-02 00:00:00.000
0           1              2014-04-03 00:00:00.000
1           0              2014-04-05 00:00:00.000

<强>结果

|----|----|--------------|-----------------|--------------|-----------------|
| MM | DD | 2013 Confirm | 2013 NetConfirm | 2014 Confirm | 2014 NetConfirm |
|----|----|--------------|-----------------|--------------|-----------------|
|  4 |  1 |            1 |               0 |            1 |               0 |
|  4 |  2 |            2 |               1 |            2 |               1 |
|  4 |  3 |            2 |               2 |            2 |               2 |
|  4 |  4 |            3 |               2 |            2 |               2 |
|  4 |  5 |            3 |               2 |            3 |               2 |