2013-05-15 5 views
2

У меня есть структура таблицы какСоздание нескольких строк из одной строки SQL

ATM   Ticket Open Time Ticket Closed Time 

M30G324202 17-02-2013 06:15 19-02-2013 20:54 
M30G324202 28-02-2013 21:00 01-03-2013 11:18 
M30G324203 27-02-2013 19:10 28-02-2013 07:14 
M30G324203 28-02-2013 07:15 28-02-2013 11:18 

Если билет Open Time ИЛИ Ticket Closed Время лежит между '20: 00: 00' и '06: 00: 00' , то есть 8 PM & 6 AM, затем следует создать новую строку, которая не имеет этого временного кадра

eg для первой строки в таблице выше

ATM   Ticket Open Time Ticket Closed Time 

M30G324202 17-02-2013 06:15 17-02-2013 20:00 
M30G324202 18-02-2013 06:00 18-02-2013 20:00 
M30G324202 19-02-2013 06:00 19-02-2013 20:00 

//Above was for Only 1st Row 

//Second Row Change AS Follows 

M30G324202 01-03-2013 06:00 01-03-2013 11:18 
    (Time From 28-02-2013 21:00 Will get neglected till next day morning 6 AM 
    as it is after 8 PM) 

//Third Row Change AS Follows 

M30G324203 27-02-2013 19:10 27-02-2013 20:00 
M30G324203 28-02-2013 06:00 28-02-2013 07:14 

//Fourth Row Change AS Follows 

M30G324203 28-02-2013 07:15 28-02-2013 11:18 (No Change as it is) 

Я написал 20:00 вместо 20:54, потому что 54 мин. после 8 вечера на 19 февраля.

+0

Таким образом, просто чтобы быть ясно, что вы после выбора дополнительного ряда на каждый день, которая попадет в этих пределах для каждой строки в данных? – KaraokeStu

+0

Абсолютно правильно .. !!! – Shaggy

+2

Пожалуйста, добавьте ожидаемый результат для второй записи 'M30G324202'. – TechDo

ответ

1

Отличный вопрос! Пожалуйста, проверьте мои попробовать:

declare @tbl as table (ATM nvarchar(20), TicketOpenTime datetime, TicketClosedTime datetime) 
insert into @tbl values 
('M30G324202', '02-17-2013 06:15', '02-19-2013 20:54'), 
('M30G324202', '02-28-2013 21:00', '03-01-2013 11:18'), 
('M30G324203', '02-27-2013 19:10', '02-28-2013 07:14'), 
('M30G324203', '02-28-2013 07:15', '02-28-2013 11:18') 

declare @min datetime, @max datetime 
select @min = MIN(TicketOpenTime), @max = max(TicketClosedTime) from @tbl 

;with T as(
    select CONVERT(datetime, convert(numeric(20), @min, 101)) dt 
    union all 
    select dt+1 from T where dt<@max 
) 
select 
    a.ATM, 
    case when a.TicketOpenTime>dt1 then a.TicketOpenTime else dt1 end TicketOpenTime, 
    case when a.TicketClosedTime>dt2 then dt2 else a.TicketClosedTime end TicketClosedTime 
From @tbl a 
cross apply(
    select 
     dt, 
     DATEADD(minute, 360, dt) dt1, 
     DATEADD(minute, 1200, dt) dt2 from T b 
    where 
     dt between CAST(a.TicketOpenTime as DATE) and cast(a.TicketClosedTime as DATE) 
)x 
where a.TicketOpenTime<=x.dt2 
order by a.ATM, a. TicketOpenTime 
+0

Проверьте отредактированный ответ. – TechDo

2

Вы можете сделать это, используя рекурсивный CTE. Следующий код показывает, как. Для тестовых данных в КТР A, использовать что-то вроде

SELECT ATM, [Ticket Open Time], [Ticket Close Time] FROM Table1 

тестовые данные здесь, чтобы показать, что все случаи были учтены. Если вы не хотите, чтобы в комплекте был включен ATM = W, или вы хотите настроить дату начала, вы можете соответствующим образом изменить SQL.

Кроме того, я использовал старомодную технику, чтобы получить часть даты datetime. Снова настройте в соответствии с версией SQL Server, на которой вы находитесь.

WITH A 
AS (

    SELECT 'X' as ATM 
     , convert(datetime, '2/17/2013 6:15') as [Ticket Open Time] 
     , convert(datetime, '2/19/2013 20:54') as [Ticket Close Time] 
    UNION ALL 
    SELECT 'Y' 
     , convert(datetime, '2/24/2013 7:32') 
     , convert(datetime, '2/25/2013 14:26') 
    UNION ALL 
    SELECT 'Z' 
     , convert(datetime, '2/20/2013 9:00') 
     , convert(datetime, '2/20/2013 13:43')  
    UNION ALL 
    SELECT 'W' 
     , convert(datetime, '3/1/2013 3:34') 
     , convert(datetime, '3/1/2013 6:45') 
) 
, B 
AS (

    SELECT ATM 
     , [Ticket Open Time] 
     , [Original Ticket Close Time] = A.[Ticket Close Time] 
     , [Ticket Close Time] = CASE WHEN DateAdd(hh, 20, convert(datetime, convert(varchar(10), [Ticket Open Time], 101))) > A.[Ticket Close Time] 
       THEN [Ticket Close Time] 
       ELSE DateAdd(hh, 20, convert(datetime, convert(varchar(10), [Ticket Open Time], 101))) 
      END 
    FROM A 
    UNION ALL 
    SELECT ATM 
     , [Ticket Open Time] = DateAdd(hh, 10, B1.[Ticket Close Time]) 
     , [Original Ticket Close Time] = b1.[Original Ticket Close Time] 
     , [Ticket Close Time] = CASE 
       WHEN DateAdd(hh, 24, b1.[Ticket Close Time]) > b1.[Original Ticket Close Time] 
       AND b1.[Original Ticket Close Time] <= DateAdd(hh,24, b1.[Ticket Close Time]) 
       THEN b1.[Original Ticket Close Time] 
       ELSE DateAdd(hh, 24, b1.[Ticket Close Time]) 
      END 
    FROM B b1 
    WHERE [Ticket Close Time] < b1.[Original Ticket Close Time] 

) 
, C 
as (
    select * 
    from B 
    where [Ticket Open Time] < [Ticket Close Time] 
) 
     -- Your actual output 
select ATM, 
      [Ticket Open Time], 
     [Ticket Close Time], 
from  C 
order by ATM, 
     [Ticket Open Time] 
+1

+1: Это очень хорошо, однако рекурсивные CTE не очень быстры. Вероятно, лучше было бы присоединиться к цифрам или к календарной таблице/CTE. – RBarryYoung

+0

@ Ann L. Большое усилие .. но для W ATM 'Ticket Open Time = 2013-03-01 06: 00: 00.000 & Ticket Закрытое время = 2013-03-01 06: 45: 00.000' .... as 8 ПМ до 6 утра будет пренебрегать. – Shaggy

Смежные вопросы