通过日期时间/递归CTE将行拆分为bin?

时间:2017-02-03 20:27:34

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

我需要每天使用SQL查询来存储数据,以便我可以将其放入垃圾箱中以在SSRS中用于报告,即上午12点至凌晨12点。我的行的时间间隔延长到凌晨12点,可能持续数天。我想将一个或多个12am时间边界的行分成多行,这样我就可以按天分组进行一些求和。例如,这里有3行:

describe('Upload Endpoint - FL token ', function (){
   this.timeout(15000);
    it('Press Send w/out attaching photos returns error message', function (done){
    config.api.post('/customer/upload/?token='+config.token)
      .attach('file', '/Users/moi/Desktop/unit_test_extravaganza/hardwork.jpg')
      .expect(200)
      .end(function(err, res) {
         expect(res.body.ok).to.equal(false);
         done();
    });
});

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

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

这有意义吗?当第一行延伸到多个12am边界(即时间间隔超过24小时)时,我需要处理这种情况。

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

我指的是这个例子,因为它接近我想做的事情:

Split row based on start end date SQL Server

为了更清楚,这里是生成我想要分割的数据的原因:

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

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

谢谢!

1 个答案:

答案 0 :(得分:2)

这是一种方法。如果您可以生成包含所有可能日期的日期表,这将更容易。然后,您可以使用现有表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