从选择查询的开始时间和结束时间列表中,我需要找出不包括重叠时间和休息时间的总时间。
StartTime EndTime
2014-10-01 10:30:00.000 2014-10-01 12:00:00.000 -- 90 mins
2014-10-01 10:40:00.000 2014-10-01 12:00:00.000 --0 since its overlapped with previous
2014-10-01 10:42:00.000 2014-10-01 12:20:00.000 -- 20 mins excluding overlapped time
2014-10-01 10:40:00.000 2014-10-01 13:00:00.000 -- 40 mins
2014-10-01 10:44:00.000 2014-10-01 12:21:00.000 -- 0 previous ones have already covered this time range
2014-10-13 15:50:00.000 2014-10-13 16:00:00.000 -- 10 mins
因此,在这种情况下总计应该是160分钟。
我不想用这么多循环来解决这个问题。寻找一些简单的解决方案。
答案 0 :(得分:1)
DECLARE @table TABLE (StartTime DateTime2, EndTime DateTime2)
INSERT INTO @table SELECT '2014-10-01 10:30:00.000', '2014-10-01 12:00:00.000'
INSERT INTO @table SELECT '2014-10-01 10:40:00.000', '2014-10-01 12:00:00.000'
INSERT INTO @table SELECT '2014-10-01 10:42:00.000', '2014-10-01 12:20:00.000'
INSERT INTO @table SELECT '2014-10-01 10:40:00.000', '2014-10-01 13:00:00.000'
INSERT INTO @table SELECT '2014-10-01 10:44:00.000', '2014-10-01 12:21:00.000'
INSERT INTO @table SELECT '2014-10-13 15:50:00.000', '2014-10-13 16:00:00.000'
;WITH addNR AS ( -- Add row numbers
SELECT StartTime, EndTime, ROW_NUMBER() OVER (ORDER BY StartTime, EndTime) AS RowID
FROM @table AS T
), createNewTable AS ( -- Recreate table according overlap time
SELECT StartTime, EndTime, RowID
FROM addNR
WHERE RowID = 1
UNION ALL
SELECT
CASE
WHEN a.StartTime <= AN.StartTime AND AN.StartTime <= a.EndTime THEN a.StartTime
ELSE AN.StartTime END AS StartTime,
CASE WHEN a.StartTime <= AN.EndTime AND AN.EndTime <= a.EndTime THEN a.EndTime
ELSE AN.EndTime END AS EndTime,
AN.RowID
FROM addNR AS AN
INNER JOIN createNewTable AS a
ON a.RowID + 1 = AN.RowID
), getMinutes AS ( -- Get difference in minutes
SELECT DATEDIFF(MINUTE,StartTime,MAX(EndTime)) AS diffMinutes
FROM createNewTable
GROUP BY StartTime
)
SELECT SUM(diffMinutes) AS Result
FROM getMinutes
结果是160
答案 1 :(得分:0)
为了得到你给出的数据的结果,我假设不包括结束时间(否则第一次运行将是91分钟)。考虑到这一点,这将为您提供您想要的结果,没有游标或循环。如果时间跨越多天,则需要调整逻辑。
--Create sample data
CREATE TABLE TimesToCheck
([StartTime] datetime, [EndTime] datetime)
;
INSERT INTO TimesToCheck
([StartTime], [EndTime])
VALUES
('2014-10-01 10:30:00', '2014-10-01 12:00:00'),
('2014-10-01 10:40:00', '2014-10-01 12:00:00'),
('2014-10-01 10:42:00', '2014-10-01 12:20:00'),
('2014-10-01 10:40:00', '2014-10-01 13:00:00'),
('2014-10-01 10:44:00', '2014-10-01 12:21:00'),
('2014-10-13 15:50:00', '2014-10-13 16:00:00')
;--Now the solution.
;WITH
E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 1*10^1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), -- 1*10^2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), -- 1*10^4 or 10,000 rows
N AS (SELECT TOP (3600) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1 AS Number FROM E4),
TimeList AS (SELECT CAST(DATEADD(minute,n.number,0) as time) AS m FROM N),
--We really only need the Timelist table. If it is already created, we can start here.
ActiveTimes AS (SELECT DISTINCT t.m FROM TimeList T
INNER JOIN TimesToCheck C ON t.m BETWEEN CAST(c.StartTime as time) AND CAST(DATEADD(minute,-1,c.EndTime) as time))
SELECT COUNT(*) FROM ActiveTimes