sql - 按日期时间/递归 CTE 将行拆分到 bin?

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

我需要每天利用 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 可以解决当前的限制。

谢谢!

最佳答案

这是一种方法。如果您可以生成包含所有可能日期的日期表,这会更容易。然后,您可以将其与现有表连接,以便根据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

关于sql - 按日期时间/递归 CTE 将行拆分到 bin?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42032497/

相关文章:

sql - 使用 Google Analytics 导出的数据在 BigQuery 中进行队列/保留查询

sql - WHERE 子句中是否可以有 CASE WHEN THEN SELECT

java - 递归函数StackOverflowError

recursion - J中的多个递归函数调用

c++ - 使用递归的机器学习算法

sql - 选择查询中的动态类型转换

sql - LEFT OUTER JOIN 和 NOT EXISTS 查询

php - 使用连接表对 mysql 结果进行分组

sql - 获取 2 个提供日期之间的所有年份

c# - Microsoft.SqlServer.Types 在 Azure 辅助角色上无法正常运行