计算不包括重叠时间的总时间&在SQLServer中断

时间:2014-11-06 15:14:47

标签: sql sql-server

从选择查询的开始时间和结束时间列表中,我需要找出不包括重叠时间和休息时间的总时间。

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分钟。

我不想用这么多循环来解决这个问题。寻找一些简单的解决方案。

2 个答案:

答案 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