【问题标题】:Splitting rows to bin by datetimes / recursive CTE?按日期时间/递归 CTE 将行拆分为 bin?
【发布时间】:2017-06-21 07:29:03
【问题描述】:

我需要每天使用 SQL 查询对数据进行分箱,以便我可以将其放入分箱中,以便在 SSRS 中用于报告,即上午 12 点至上午 12 点。我的行的时间间隔延伸到上午 12 点,可能持续多天。我想将延长一个或多个上午 12 点时间边界的行拆分为多行,以便我可以按天分组进行一些汇总。例如这里有 3 行:

StateName   StartDT LastDT  IntervalMin FullName
RUN_PARTS   2017-01-24 23:09:29.46  2017-01-25 02:19:32.29  190.04 SPECTOR4            
IDLE    2017-01-25 02:19:32.29  2017-01-25 03:11:32.91  52.01   SPECTOR4            
MAINTENANCE_GENERAL 2017-01-25 03:11:32.91  2017-01-25 18:31:44.26  920.18  SPECTOR4

我想获取这些数据(第一行在上午 12 点拆分,IntervalMin 更新为新的开始、停止时间):

StateName   StartDT LastDT  IntervalMin FullName
RUN_PARTS   2017-01-24 23:09:29.46  2017-01-25 00:00:00.00  50.30 SPECTOR4 
RUN_PARTS   2017-01-25 00:00:00.00  2017-01-25 02:19:32.29  139.28 SPECTOR4 
IDLE    2017-01-25 02:19:32.29  2017-01-25 03:11:32.91  52.01   SPECTOR4            
MAINTENANCE_GENERAL 2017-01-25 03:11:32.91  2017-01-25 18:31:44.26  920.18  SPECTOR4

这有意义吗?我需要处理第一行跨越多个上午 12 点边界(即时间间隔超过 24 小时)的情况。

在阅读了一堆东西之后,看起来递归 CTE 应该能够做到这一点,但是,我无法理解这一点。

我特指这个例子,因为它接近我想要做的:

Split row based on start end date SQL Server

为了更清楚,这里是生成我尝试拆分的数据的原因:

declare @STARTDT as datetime2
declare @STOPDT as datetime2
declare @CNAME as VARCHAR(70) 

SET @STARTDT = DATEADD(d, -30, CURRENT_TIMESTAMP)
SET @STOPDT = CURRENT_TIMESTAMP
SET @CNAME = 'Spector4'

SELECT
CoatingChamberStates.Name
,CCSL.StartDT as StartDT
,CCSL.LastDT as LastDT
,CCSL.IntervalMin
,CoatingChambers.FullName

FROM CoatingChamberStateLogs as CCSL
INNER JOIN CoatingChamberStates on CCSL.CoatingChamberStatesID = CoatingChamberStates.CoatingChamberStatesID
INNER JOIN CoatingChambers on CCSL.CoatingChambersID = CoatingChambers.CoatingChambersID

where CCSL.StartDT >= @STARTDT
and CCSL.LastDT <= @STOPDT
and CoatingChambers.FullName = @CNAME

或者,如果您对如何解决此问题有更好的想法,我将不胜感激。我的目标是评估和发现 SSRS 的限制,但我认为这种递归 CTE 可以解决当前的限制。

谢谢!

【问题讨论】:

    标签: sql sql-server recursion reporting-services common-table-expression


    【解决方案1】:

    这是一种方法。如果您可以生成包含所有可能日期的日期表,这将更容易。然后,您可以 join 它与现有表一起根据 case 表达式逻辑拆分行(如果它们跨越多天)。

    with dates(dt) as (select '2017-01-24' union all select '2017-01-25' union all select '2017-01-26' union all select '2017-01-27')
    --This just uses the dates from the example in question
    /*To generate dates for a given timeframe (for example all dates in 2017), use
    with dates(dt) as (select '2017-01-01' 
                       union all
                       select dateadd(day,1,dt) from dates where dt < '2017-12-31')
    */
    select t.statename 
    ,case when t.startdt>=d.dt then t.startdt else d.dt end as startdt
    ,case when datediff(day,lastdt,dt)=0 then t.lastdt else dateadd(day,1,d.dt) end as lastdt 
    ,datediff(millisecond
              ,case when t.startdt>=d.dt then t.startdt else d.dt end
              ,case when datediff(day,lastdt,dt)=0 then t.lastdt else dateadd(day,1,d.dt) end)/60000.0 
     as split_diff
    ,t.fullname
    from t
    join dates d on d.dt >= cast(t.startdt as date) and d.dt<=cast(t.lastdt as date)
    

    Sample Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-19
      • 2021-09-29
      • 1970-01-01
      • 2019-02-20
      相关资源
      最近更新 更多