我有两列:Start_Date和End_Date。
任务是返回到第二天结束的时间(使用T-SQL,SSMS 14.0)。
例如:
Start_Date = '2018-11-21 23:40:00' End_Date = '2018-11-23 02:40:00'
查询应返回3行:
0 hour 20 min -- time between 2018-11-21 23:40:00 and 2018-11-22 00:00:00
24 hour 0 min -- time between 2018-11-22 00:00:00 and 2018-11-23 00:00:00
2 hour 40 min -- time between 2018-11-23 00:00:00 and 2018-11-23 02:40:00
我想可以使用游标或递归CTE来实现。
答案 0 :(得分:1)
是的,CTE
可以与DATEDIFF
一起使用,并且DATEADD
的功能如下:
CREATE VIEW DAYS AS
WITH CTE AS (
SELECT 1 as nr
UNION ALL
SELECT nr+1
FROM CTE
WHERE nr <= DATEDIFF( day, CONVERT(date, '2018-11-21 23:40:00'),
CONVERT(date, '2018-11-23 02:40:00') )
)
SELECT
DATEDIFF(
minute,
(case when nr > 1 then
DATEADD ( day , nr - 1 , CONVERT(date, '2018-11-21 23:40:00') )
else
DATEADD ( day , nr - 1 , CONVERT(datetime, '2018-11-21 23:40:00'))
end),
(case when nr < 3 then
DATEADD ( day , nr , CONVERT(date, '2018-11-21 23:40:00') )
else
DATEADD ( day , nr - 3, CONVERT(datetime, '2018-11-23 02:40:00'))
end)
) as time_diff
FROM CTE;
SELECT cast(time_diff/60 as varchar) + ' hours '
+ cast(time_diff % 60 as varchar) + ' minutes' as "Time Difference" FROM DAYS;
Time Difference
-------------------
0 hours 20 minutes
24 hours 0 minutes
2 hours 40 minutes
答案 1 :(得分:0)
您可以获得的预期结果
WITH Dates AS
(
SELECT 1 RN,
@sd StartD,
CAST(DATEADD(Day, -1, @ed) AS DATE) EndD
UNION
SELECT 2,
CAST(DATEADD(Day, 1, @sd) AS DATE),
CAST(@ed AS DATE)
UNION
SELECT 3,
CAST(@ed AS DATE),
@ed
)
SELECT
CAST( DATEDIFF(YEAR, StartD, EndD) AS VARCHAR(10) )+ ' Years, '+
CAST( DATEDIFF(MONTH, StartD, EndD)%12 AS VARCHAR(10) )+ ' Months, '+
CAST( (DATEDIFF(DAY, StartD, EndD)%31)%12
- CASE WHEN RN = 1 THEN RN ELSE 0 END AS VARCHAR(10) )+ ' Days, '+
CAST( (DATEDIFF(HOUR, StartD, EndD)%60)%24
- CASE WHEN RN = 1 THEN RN ELSE 0 END AS VARCHAR(10) ) + ' Hours,'+
CAST( DATEDIFF(MINUTE, StartD, EndD)%60 AS VARCHAR(10) ) +' Minutes, '+
CAST( DATEDIFF(SECOND, StartD, EndD)%60 AS VARCHAR(10) ) +' Seconds' AS Results
FROM Dates;
结果:
+----------------------------------------------------------+
| Results |
+----------------------------------------------------------+
| 0 Years, 0 Months, 0 Days, 0 Hours,20 Minutes, 0 Seconds |
| 0 Years, 0 Months, 1 Days, 0 Hours,0 Minutes, 0 Seconds |
| 0 Years, 0 Months, 0 Days, 2 Hours,40 Minutes, 0 Seconds |
+----------------------------------------------------------+
最后,请注意,我认为您的结果应该是
+----------------------------------------------------------+
| Results |
+----------------------------------------------------------+
| 0 Years, 0 Months, 1 Days, 1 Hours,20 Minutes, 0 Seconds |
| 0 Years, 0 Months, 1 Days, 0 Hours,0 Minutes, 0 Seconds |
| 0 Years, 0 Months, 0 Days, 2 Hours,40 Minutes, 0 Seconds |
+----------------------------------------------------------+
如果我是对的,那么您要做的就是删除两(2)个CASE
表达式。
答案 2 :(得分:0)
我相信您会希望将此功能应用于各种任务持续时间。在这里,我使用了一个动态的“统计表”,该表只是一系列从0到(在这种情况下)为100的数字,如果需要更大的范围,可以通过添加额外的交叉联接来修改Tally
cte。如果您已经有一个数字表,或者您自己的首选方法可以代替我的方法。
CREATE TABLE mytable(
ID Integer NOT NULL
,Start_Date datetime NOT NULL
,End_Date datetime NOT NULL
);
INSERT INTO mytable(id,Start_Date,End_Date) VALUES (1,'2018-11-21 23:40:00','2018-11-23 02:40:00');
INSERT INTO mytable(id,Start_Date,End_Date) VALUES (2,'2018-11-23 13:40:00','2018-11-23 22:40:00');
INSERT INTO mytable(id,Start_Date,End_Date) VALUES (3,'2018-11-18 23:40:00','2018-11-23 02:40:00');
给定的3个测试用例,持续时间很短+持续时间更长:
;WITH
Digits AS (
SELECT 0 AS digit UNION ALL
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
SELECT 9
)
, Tally AS (
SELECT [ones].digit
+ [tens].digit * 10
-- + [hundreds].digit * 100
AS number
FROM Digits [ones]
CROSS JOIN Digits [tens]
-- CROSS JOIN Digits [hundreds]
)
select
ID
, cast(ca2.minutes/60 as varchar) + ' hours '
+ cast(ca2.minutes % 60 as varchar) + ' minutes' as Duration
, format(on_date,'yyyy-MM-dd') on_date
, portion
, format(start_date,'yyyy-MM-dd hh:mm') start_date
, format(end_date,'yyyy-MM-dd hh:mm') end_date
from mytable t
inner join Tally on Tally.number <= datediff(dd,t.Start_Date,t.End_Date)
cross apply (
select dateadd(dd,tally.number,dateadd(dd,datediff(dd,0,t.start_date),0)) on_date
) ca
cross apply (
select
case
when t.start_date >= ca.on_date and t.end_date <= dateadd(dd,1,ca.on_date) then datediff(minute,t.start_date,t.end_date)
when cast(t.end_date as date) = ca.on_date then datediff(minute,ca.on_date,t.end_date)
when ca.on_date between t.start_date and t.end_date then 24*60
when ca.on_date < t.start_date then datediff(minute,t.start_date,dateadd(dd,1,ca.on_date))
end minutes
, case
when t.start_date >= ca.on_date and t.end_date <= dateadd(dd,1,ca.on_date) then 'is on'
when cast(t.end_date as date) = ca.on_date then 'end'
when ca.on_date between t.start_date and t.end_date then 'span'
when ca.on_date < t.start_date then 'start'
end portion
) ca2
我使用了2个Apply运算符,第一个将Tally
中的数字转换为日期,然后在第二个Apply中使用别名on_date
重用它,我们可以计算出持续时间。请注意,第二种情况表达式portion
不是必需的,它只是用来帮助记录逻辑。
结果:
ID Duration on_date portion start_date end_date
---- ---- -------------------- ------------ --------- ------------------ ------------------
1 1 0 hours 20 minutes 2018-11-21 start 2018-11-21 11:40 2018-11-23 02:40
2 1 24 hours 0 minutes 2018-11-22 span 2018-11-21 11:40 2018-11-23 02:40
3 1 2 hours 40 minutes 2018-11-23 end 2018-11-21 11:40 2018-11-23 02:40
4 2 9 hours 0 minutes 2018-11-23 is on 2018-11-23 01:40 2018-11-23 10:40
5 3 0 hours 20 minutes 2018-11-18 start 2018-11-18 11:40 2018-11-23 02:40
6 3 24 hours 0 minutes 2018-11-19 span 2018-11-18 11:40 2018-11-23 02:40
7 3 24 hours 0 minutes 2018-11-20 span 2018-11-18 11:40 2018-11-23 02:40
8 3 24 hours 0 minutes 2018-11-21 span 2018-11-18 11:40 2018-11-23 02:40
9 3 24 hours 0 minutes 2018-11-22 span 2018-11-18 11:40 2018-11-23 02:40
10 3 2 hours 40 minutes 2018-11-23 end 2018-11-18 11:40 2018-11-23 02:40