【问题标题】:T-SQL - Data Islands and Gaps - How do I summarise transactional data by month?T-SQL - 数据孤岛和差距 - 如何按月汇总交易数据?
【发布时间】:2014-04-05 19:51:06
【问题描述】:

我正在尝试查询一些交易数据,以确定每个报告在每个月底CurrentProductionHours 值。

假设每个月的每个报告都有一个事务,这很简单...我可以使用下面代码行中的一些东西来按月划分事务,然后选择TransactionByMonth 所在的行= 1(实际上是每个月每个报告的最后一笔交易)。

SELECT
    ReportId,
    TransactionId,
    CurrentProductionHours,
    ROW_NUMBER() OVER (PARTITION BY [ReportId], [CalendarYear], [MonthOfYear]
                       ORDER BY TransactionTimestamp desc
                      ) AS TransactionByMonth
FROM
    tblSource

我遇到的问题每个报告每个月不一定会有交易...... ,我需要将 last known 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

目标结果:

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

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

** 2014 年 5 月 3 日更新 **

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

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

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

【问题讨论】:

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


    【解决方案1】:

    试试这个:

    ;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
    

    【讨论】:

    • 我应该提到我的答案最适合 TransactionTimestamp 上的索引
    【解决方案2】:

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

        ;
    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
    

    【讨论】:

    • 我测试了你的解决方案,但它没有给出正确的结果与更多的测试行
    • 哎呀,太糟糕了;可以给我你用的测试集吗?我可以尝试修复我的查询。谢谢。
    • 您所要做的就是创建一个像问题中一样的表格并向其中添加行。它经常失败。
    • 我在连接中添加了一个不同的和报告 id 条件,以防时间戳重复
    • no... 修复失败的查询很少使用 distinct。上次我检查它仍然是错误的。而且我已经在reportid上测试过加入。 Distinct 不会修复它。
    猜你喜欢
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    相关资源
    最近更新 更多