T-SQL - 数据岛和差距 - 如何按月汇总交易数据?

时间:2014-03-04 10:25:21

标签: tsql date grouping transactional gaps-and-islands

我正在尝试查询某些交易数据,以便在每月末为每个报告建立CurrentProductionHours值。

假设每个月每个报告都有一个交易,这非常简单......我可以使用下面代码中的某些内容按月对事务进行分区,然后选择{{1 }} = 1(实际上,每个月每个报告的最后一笔交易)。

TransactionByMonth

我遇到的问题是每个月份每个报告不一定会有交易...当这是个案时,我需要将最后一次已知的 SELECT ReportId, TransactionId, CurrentProductionHours, ROW_NUMBER() OVER (PARTITION BY [ReportId], [CalendarYear], [MonthOfYear] ORDER BY TransactionTimestamp desc ) AS TransactionByMonth FROM tblSource 值继续到没有交易的月份,因为这表明没有变化。潜在地,这个值可能需要多次结转。

来源数据:

CurrentProductionHours

目标结果:

ReportId       TransactionTimestamp     CurrentProductionHours
1              2014-01-05 13:37:00      14.50
1              2014-01-20 09:15:00      15.00
1              2014-01-21 10:20:00      10.00
2              2014-01-22 09:43:00      22.00 
1              2014-02-02 08:50:00      12.00

我还应该提一下,我有一个可用的日期表,如果需要可以参考。

** 更新05/03/2014 **

我现在有查询正在生成结果,如下面的例子所示,但我留下了数据孤岛(当月存在交易)和两者之间的差距...我的问题仍然类似,但在一些更通用的方法 - 如果您将以下数据集作为起点,填补数据岛之间间隙的最佳方法是什么?

ReportId     Month     Year     ProductionHours
1            1         2014     10.00
2            1         2014     22.00
1            2         2014     12.00
2            2         2014     22.00

任何有关如何解决这个问题的建议都将不胜感激!

2 个答案:

答案 0 :(得分:0)

试试这个:

;with a as
(
select dateadd(m, datediff(m, 0, min(TransactionTimestamp))+1,0) minTransactionTimestamp, 
max(TransactionTimestamp) maxTransactionTimestamp from tblSource
), b as
(
select minTransactionTimestamp TT, maxTransactionTimestamp
from a
union all
select dateadd(m, 1, TT), maxTransactionTimestamp
from b
where tt < maxTransactionTimestamp
), c as
(
select distinct t.ReportId, b.TT from tblSource t
cross apply b
)
select c.ReportId, 
       month(dateadd(m, -1, c.TT)) Month, 
       year(dateadd(m, -1, c.TT)) Year, 
       x.CurrentProductionHours 
from c
cross apply
(select top 1 CurrentProductionHours from tblSource 
where TransactionTimestamp < c.TT 
and ReportId = c.ReportId
order by TransactionTimestamp desc) x

答案 1 :(得分:0)

类似的方法,但使用笛卡尔来获得报告ID /月的所有组合。 在第一步。 第二步是向该笛卡尔添加源表中的最大时间戳,其中月份小于或等于当前行中的月份。 最后,它通过报告ID /时间戳将源表连接到临时表,以获取每个报告ID /月的最新源表行。

    ;
WITH    allcombinations -- Cartesian (reportid X yearmonth) 
      AS ( SELECT   reportid ,
                    yearmonth
           FROM     ( SELECT DISTINCT
                                reportid
                      FROM      tblSource
                    ) a
                    JOIN ( SELECT DISTINCT
                                    DATEPART(yy, transactionTimestamp)
                                    * 100 + DATEPART(MM,
                                                     transactionTimestamp) yearmonth
                           FROM     tblSource
                         ) b ON 1 = 1
         ),
    maxdates --add correlated max timestamp where the month is less or equal to the month in current record
      AS ( SELECT   a.* ,
                    ( SELECT    MAX(transactionTimestamp)
                      FROM      tblSource t
                      WHERE     t.reportid = a.reportid
                                AND DATEPART(yy, t.transactionTimestamp)
                                * 100 + DATEPART(MM,
                                                 t.transactionTimestamp) <= a.yearmonth
                    ) maxtstamp
           FROM     allcombinations a
         )
-- join previous data to the source table by reportid and timestamp 
SELECT  distinct m.reportid ,
        m.yearmonth ,
        t.CurrentProductionHours
FROM    maxdates m
        JOIN tblSource t ON t.transactionTimestamp = m.maxtstamp and t.reportid=m.reportid
ORDER BY m.reportid ,
        m.yearmonth