T-SQL - DateTime间隙分布

时间:2017-01-17 18:22:27

标签: sql-server sql-server-2014

代码:

DECLARE @SD DATE    = '2017-01-01'
        ,@ED DATE   = '2017-01-07'
        ,@ST TIME   = '08:00:00'
        ,@ET TIME   = '16:00:00';

DECLARE @DT_T TABLE (SDT DATETIME, EDT DATETIME)

目标: 要合并开始/结束日期和开始/结束时间(@ SD / @ ED和@ ST / @ ET)并创建一个表格,其中包含StartDateTime和EndDateTime之间的间隙,如下面所需的输出所示。

期望输出

/* @DT_T Data
SDT                         EDT
2017-01-01 08:00:00         2017-01-01 16:00:00
2017-01-02 08:00:00         2017-01-02 16:00:00
2017-01-03 08:00:00         2017-01-03 16:00:00
2017-01-04 08:00:00         2017-01-04 16:00:00
2017-01-05 08:00:00         2017-01-05 16:00:00
2017-01-06 08:00:00         2017-01-06 16:00:00
2017-01-07 08:00:00         2017-01-07 16:00:00
*/

我正在尝试使用数字表,但到目前为止还没有到达任何地方。

4 个答案:

答案 0 :(得分:1)

这样的东西? rextester:http://rextester.com/ULTV27021

declare @sd date    = '2017-01-01'
        ,@ed date   = '2017-01-07'
        ,@st_hour int = 8
        ,@et_hour int = 16;

declare @dt_t table (sdt datetime, edt datetime);

;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, d as (
  select 
      sdt=dateadd(hour,@st_hour,convert(datetime,dateadd(day, row_number() over (order by (select 1)) -1,@sd)))
    , edt=dateadd(hour,@et_hour,convert(datetime,dateadd(day, row_number() over (order by (select 1)) -1,@sd)))
    from         n as deka
      cross join n as hecto
      cross join n as kilo     /* 2.73 years */
      --cross join n as [10k]    /* 27.3 years */
)
insert into @dt_t (sdt,edt)
  select top (datediff(day,@sd,@ed)+1)
      sdt
    , edt
    from d
    order by sdt;

select * from @dt_t 

注意: rextester的日期默认输出格式为dd.MM.yyyy

答案 1 :(得分:1)

试试这个。应该得到你想要的东西。

DECLARE @SD DATE    = '2017-01-01'
        ,@ED DATE   = '2017-01-07'
        ,@ST TIME   = '08:00:00'
        ,@ET TIME   = '16:00:00';

DECLARE @DT_T TABLE (SDT DATETIME, EDT DATETIME)

Declare @i int = 0

While (@SD < @ED)
Begin
    Insert Into @DT_T(SDT, EDT)
    Select Cast(Convert(varchar(10),DateAdd(Day,@i,@SD),21) + ' ' + Convert(varchar(8),@ST,21) as datetime), Cast(Convert(varchar(10),DateAdd(Day,@i,@SD),21) + ' ' + Convert(varchar(10),@ET,21) as DateTime)  
    Set @i = @i + 1     
    IF (DateAdd(Day,@i,@SD) = @ED)      
        Break
    Else
        Continue
END
Insert Into @DT_T(SDT, EDT)
Select Cast(Convert(varchar(10),@ED,21) + ' ' + Convert(varchar(8),@ST,21) as datetime), Cast(Convert(varchar(10),@ED,21) + ' ' + Convert(varchar(10),@ET,21) as DateTime)

Select SDT, EDT From @DT_T

答案 2 :(得分:1)

使用下一个方法

  1. 使用datediff函数在2之间插入行     范围。

  2. 仅更新日期时间值的时间。

  3. <强>演示: -

    DECLARE @SD DATE    = '2017-01-01'
            ,@ED DATE   = '2017-01-07'
            ,@ST TIME   = '08:00:00'
            ,@ET TIME   = '16:00:00';
    
    DECLARE @DT_T TABLE (SDT DATETIME, EDT DATETIME)
    DECLARE @start int
    
    set @start = 0
    while @start <= datediff(day,@SD,@ED)
    begin
        insert into @DT_T values
                                (   dateadd(day,@start, @SD)  , 
                                    dateadd(day,@start, @SD))  
    
        set @start = @start + 1
    end
    
    UPDATE @DT_T 
    SET SDT = DATEADD(HOUR, 8, CAST(CAST(SDT AS DATE) AS DATETIME)) ,
        EDT = DATEADD(HOUR, 16, CAST(CAST(EDT AS DATE) AS DATETIME))
    
    select * from @DT_T
    

    <强>结果: -

    enter image description here

答案 3 :(得分:1)

我经常使用TVF创建动态日期/时间范围。计数表也可以解决这个问题。 UDF可以比递归CTE更快并且是参数驱动的。您提供日期范围,DatePart和增量。例如:

Declare @D1 datetime = '2017-01-01'
Declare @D2 datetime = '2017-01-07'
Declare @T1 datetime = '08:00'

Select RetSeq
      ,STD = RetVal
      ,EDT = DateAdd(HOUR,8,RetVal)
 From [dbo].[udf-Range-Date](@D1+@T1,@D2+@T1,'DD',1)

返回

enter image description here

UDF(如果需要)

CREATE FUNCTION [dbo].[udf-Range-Date] (@R1 datetime,@R2 datetime,@Part varchar(10),@Incr int)
Returns Table
Return (
    with cte0(M)   As (Select 1+Case @Part When 'YY' then DateDiff(YY,@R1,@R2)/@Incr When 'QQ' then DateDiff(QQ,@R1,@R2)/@Incr When 'MM' then DateDiff(MM,@R1,@R2)/@Incr When 'WK' then DateDiff(WK,@R1,@R2)/@Incr When 'DD' then DateDiff(DD,@R1,@R2)/@Incr When 'HH' then DateDiff(HH,@R1,@R2)/@Incr When 'MI' then DateDiff(MI,@R1,@R2)/@Incr When 'SS' then DateDiff(SS,@R1,@R2)/@Incr End),
         cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
         cte2(N)   As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
         cte3(N,D) As (Select 0,@R1 Union All Select N,Case @Part When 'YY' then DateAdd(YY, N*@Incr, @R1) When 'QQ' then DateAdd(QQ, N*@Incr, @R1) When 'MM' then DateAdd(MM, N*@Incr, @R1) When 'WK' then DateAdd(WK, N*@Incr, @R1) When 'DD' then DateAdd(DD, N*@Incr, @R1) When 'HH' then DateAdd(HH, N*@Incr, @R1) When 'MI' then DateAdd(MI, N*@Incr, @R1) When 'SS' then DateAdd(SS, N*@Incr, @R1) End From cte2 )

    Select RetSeq = N+1
          ,RetVal = D 
     From  cte3,cte0 
     Where D<=@R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1) 
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1) 
*/