2017-01-17 2 views
0

Код:T-SQL - DateTime Gap Распределение

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) 

Цель: Совместить Start/End Дата и Start/End Time (@ 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 
*/ 

Я пытаюсь с таблицей чисел, но до сих пор не получают где-нибудь близко.

+0

Я не вижу никакого кода, кроме ваших заявлений DECLARE. Но вы должны просто добавить 1 день к '@ SD', пока не будете' = '' @ ED'. –

ответ

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 в форматирование дат ДД.ММ.ГГГГ

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 
+1

Зачем использовать цикл, когда вы можете использовать операцию на основе набора? [Создать набор или последовательность без петель - часть 1 - Аарон Бертран - 2013-01-16] (https://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1) – SqlZim

+0

Хорошо точка. Это была первая мысль, и я старался сделать ее простой по большей части. Спасибо за предложение! –

1

Используйте Следующий подход

  1. использовать datediff функцию для вставки строки между 2 диапазонов.

  2. Обновление только времени в значениях даты и времени.

Demo: -

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

+1

Зачем использовать цикл, когда вы можете использовать операцию на основе набора? [Создать набор или последовательность без циклов - часть 1 - Аарон Бертран - 2013-01-16] (https://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1) – SqlZim

1

Я часто используют TVF для создания динамических диапазонов даты/времени. Стол в таблице также будет делать трюк. UDF может быть быстрее рекурсивного CTE и управляться параметром. Вы указываете диапазон дат, DatePart и Increment. Для примера:

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](@[email protected],@[email protected],'DD',1) 

Возвращения

enter image description here

ОДС при необходимости

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<[email protected] 
) 
/* 
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) 
*/