我有像
这样的表结构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
如果票务开放时间或票证关闭时间位于'20:00:00'和'06:00:00'之间,即晚上8点&早上6点然后应该创建一个没有该时间范围的新行
e.g。对于上表中的第一行
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分钟。是在19点之后的晚上8点之后。
答案 0 :(得分:2)
您可以使用递归CTE执行此操作。以下代码显示了如何操作。对于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)
一个很棒的问题! 请检查我的尝试:
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