i have table structure like
我有桌子结构
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
If Ticket Open Time OR Ticket Closed Time is lies between '20:00:00' and '06:00:00' i.e. 8 PM & 6 AM then new row should get created which does not have that time frame
如果票证开放时间或票证关闭时间位于'20:00:00'和'06:00:00'之间,即晚上8点和早上6点,那么应该创建没有该时间范围的新行
e.g. for first row in above table
例如对于上表中的第一行
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)
I have written 20:00
instead of 20:54
because 54 min. are after 8 PM for 19th feb.
因为54分钟,我写了20:00而不是20:54。是在19点之后的晚上8点之后。
2 个解决方案
#1
1
A great question! Please check my try:
一个很好的问题!请检查我的尝试:
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
#2
2
You can do this using a recursive CTE. The following code shows how. For the test data in CTE A
, use something like
您可以使用递归CTE执行此操作。以下代码显示了如何操作。对于CTE A中的测试数据,请使用类似的东西
SELECT ATM, [Ticket Open Time], [Ticket Close Time] FROM Table1
The test data is here to show that all cases have been taken care of. If you don't want case ATM = W included, or you want to adjust the start date, you can modify the SQL accordingly.
测试数据在此表明所有案例都已得到处理。如果您不想包含ATM = W,或者您想调整开始日期,则可以相应地修改SQL。
Also, I used an old-fashioned technique to get the date portion of the datetime
. Again, adjust according to the version of SQL Server you're on.
此外,我使用了一种老式的技术来获取日期时间的日期部分。再次,根据您所在的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
A great question! Please check my try:
一个很好的问题!请检查我的尝试:
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
#2
2
You can do this using a recursive CTE. The following code shows how. For the test data in CTE A
, use something like
您可以使用递归CTE执行此操作。以下代码显示了如何操作。对于CTE A中的测试数据,请使用类似的东西
SELECT ATM, [Ticket Open Time], [Ticket Close Time] FROM Table1
The test data is here to show that all cases have been taken care of. If you don't want case ATM = W included, or you want to adjust the start date, you can modify the SQL accordingly.
测试数据在此表明所有案例都已得到处理。如果您不想包含ATM = W,或者您想调整开始日期,则可以相应地修改SQL。
Also, I used an old-fashioned technique to get the date portion of the datetime
. Again, adjust according to the version of SQL Server you're on.
此外,我使用了一种老式的技术来获取日期时间的日期部分。再次,根据您所在的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]