Sql server 从其他日期时间范围中减去日期时间范围(T-SQL)

Sql server 从其他日期时间范围中减去日期时间范围(T-SQL),sql-server,tsql,datetime,range,subtraction,Sql Server,Tsql,Datetime,Range,Subtraction,我需要一些帮助来创建SQL查询。至少有一点关于如何做到这一点的提示。 我有一个带有datetime范围的表时间表,还有一个带有datetime范围的表UnavailableTimes。从这个我想要的可用时间,从时间表中减去不可用的时间 T-SQL(测试数据) CREATE TABLE Schedule ( ID INT, StartTime DATETIME, EndTime DATETIME ) CREATE TABLE UnavailableTimes (

我需要一些帮助来创建SQL查询。至少有一点关于如何做到这一点的提示。 我有一个带有datetime范围的表时间表,还有一个带有datetime范围的表UnavailableTimes。从这个我想要的可用时间,从时间表中减去不可用的时间

T-SQL(测试数据)

CREATE TABLE Schedule (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

CREATE TABLE UnavailableTimes (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

CREATE TABLE AvailableTimes (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

INSERT INTO Schedule (ID, StartTime, EndTime)
VALUES 
    (2, '2018-02-27 08:00', '2018-02-27 12:00'),
    (2, '2018-02-27 13:00', '2018-02-27 17:00')

INSERT INTO UnavailableTimes (ID, StartTime, EndTime)
VALUES 
    (2, '2018-02-27 07:30', '2018-02-27 08:30'),
    (2, '2018-02-27 08:00', '2018-02-27 09:30'),
    (2, '2018-02-27 13:30', '2018-02-27 14:00'),
    (2, '2018-02-27 16:00', '2018-02-27 18:00')
ID  StartTime           EndTime  
2   2018-02-27 08:00    2018-02-27 12:00  
2   2018-02-27 13:00    2018-02-27 17:00
ID  StartTime           EndTime  
2   2018-02-27 07:30    2018-02-27 08:30  
2   2018-02-27 08:00    2018-02-27 09:30  
2   2018-02-27 13:30    2018-02-27 14:00
2   2018-02-27 16:00    2018-02-27 18:00
ID  StartTime           EndTime  
2   2018-02-27 09:30    2018-02-27 12:00  
2   2018-02-27 13:00    2018-02-27 13:30
2   2018-02-27 14:00    2018-02-27 16:00  
时间表

CREATE TABLE Schedule (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

CREATE TABLE UnavailableTimes (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

CREATE TABLE AvailableTimes (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

INSERT INTO Schedule (ID, StartTime, EndTime)
VALUES 
    (2, '2018-02-27 08:00', '2018-02-27 12:00'),
    (2, '2018-02-27 13:00', '2018-02-27 17:00')

INSERT INTO UnavailableTimes (ID, StartTime, EndTime)
VALUES 
    (2, '2018-02-27 07:30', '2018-02-27 08:30'),
    (2, '2018-02-27 08:00', '2018-02-27 09:30'),
    (2, '2018-02-27 13:30', '2018-02-27 14:00'),
    (2, '2018-02-27 16:00', '2018-02-27 18:00')
ID  StartTime           EndTime  
2   2018-02-27 08:00    2018-02-27 12:00  
2   2018-02-27 13:00    2018-02-27 17:00
ID  StartTime           EndTime  
2   2018-02-27 07:30    2018-02-27 08:30  
2   2018-02-27 08:00    2018-02-27 09:30  
2   2018-02-27 13:30    2018-02-27 14:00
2   2018-02-27 16:00    2018-02-27 18:00
ID  StartTime           EndTime  
2   2018-02-27 09:30    2018-02-27 12:00  
2   2018-02-27 13:00    2018-02-27 13:30
2   2018-02-27 14:00    2018-02-27 16:00  
不可用时间

CREATE TABLE Schedule (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

CREATE TABLE UnavailableTimes (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

CREATE TABLE AvailableTimes (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

INSERT INTO Schedule (ID, StartTime, EndTime)
VALUES 
    (2, '2018-02-27 08:00', '2018-02-27 12:00'),
    (2, '2018-02-27 13:00', '2018-02-27 17:00')

INSERT INTO UnavailableTimes (ID, StartTime, EndTime)
VALUES 
    (2, '2018-02-27 07:30', '2018-02-27 08:30'),
    (2, '2018-02-27 08:00', '2018-02-27 09:30'),
    (2, '2018-02-27 13:30', '2018-02-27 14:00'),
    (2, '2018-02-27 16:00', '2018-02-27 18:00')
ID  StartTime           EndTime  
2   2018-02-27 08:00    2018-02-27 12:00  
2   2018-02-27 13:00    2018-02-27 17:00
ID  StartTime           EndTime  
2   2018-02-27 07:30    2018-02-27 08:30  
2   2018-02-27 08:00    2018-02-27 09:30  
2   2018-02-27 13:30    2018-02-27 14:00
2   2018-02-27 16:00    2018-02-27 18:00
ID  StartTime           EndTime  
2   2018-02-27 09:30    2018-02-27 12:00  
2   2018-02-27 13:00    2018-02-27 13:30
2   2018-02-27 14:00    2018-02-27 16:00  
我想从时间表中的时间范围中减去不可用时间中的时间范围,得到如下可用时间:

可用时间

CREATE TABLE Schedule (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

CREATE TABLE UnavailableTimes (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

CREATE TABLE AvailableTimes (
    ID INT,
    StartTime DATETIME,    
    EndTime DATETIME
)

INSERT INTO Schedule (ID, StartTime, EndTime)
VALUES 
    (2, '2018-02-27 08:00', '2018-02-27 12:00'),
    (2, '2018-02-27 13:00', '2018-02-27 17:00')

INSERT INTO UnavailableTimes (ID, StartTime, EndTime)
VALUES 
    (2, '2018-02-27 07:30', '2018-02-27 08:30'),
    (2, '2018-02-27 08:00', '2018-02-27 09:30'),
    (2, '2018-02-27 13:30', '2018-02-27 14:00'),
    (2, '2018-02-27 16:00', '2018-02-27 18:00')
ID  StartTime           EndTime  
2   2018-02-27 08:00    2018-02-27 12:00  
2   2018-02-27 13:00    2018-02-27 17:00
ID  StartTime           EndTime  
2   2018-02-27 07:30    2018-02-27 08:30  
2   2018-02-27 08:00    2018-02-27 09:30  
2   2018-02-27 13:30    2018-02-27 14:00
2   2018-02-27 16:00    2018-02-27 18:00
ID  StartTime           EndTime  
2   2018-02-27 09:30    2018-02-27 12:00  
2   2018-02-27 13:00    2018-02-27 13:30
2   2018-02-27 14:00    2018-02-27 16:00  

编辑: 在MJH的帮助下,我得到了开始时间和结束时间。现在我只需要把这些放在一起:

;WITH S1 AS (
        SELECT  U.EndTime AS StartTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.EndTime BETWEEN W.StartTime AND DATEADD(s, -1, W.EndTime)
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.EndTime BETWEEN S.StartTime AND S.EndTime
        )
),
S2 AS (
        SELECT  S.StartTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.StartTime BETWEEN U.StartTime AND U.EndTime
        )
)
SELECT  StartTime
FROM    S1
UNION ALL
SELECT  StartTime
FROM    S2
ORDER BY 1


;WITH S1 AS (
        SELECT  U.StartTime AS EndTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.StartTime BETWEEN DATEADD(s, 1, W.StartTime) AND W.EndTime
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.StartTime BETWEEN S.StartTime AND S.EndTime
        )
),
S2 AS (
        SELECT  S.EndTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.EndTime BETWEEN U.StartTime AND U.EndTime
        )
)
SELECT  EndTime
FROM    S1
UNION ALL
SELECT  EndTime
FROM    S2
ORDER BY 1
;WITH S1 AS (
        SELECT  U.EndTime AS StartTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.EndTime BETWEEN W.StartTime AND DATEADD(s, -1, W.EndTime)
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.EndTime BETWEEN S.StartTime AND S.EndTime
        )
),
S2 AS (
        SELECT  S.StartTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.StartTime BETWEEN U.StartTime AND U.EndTime
        )
),
S3 AS (
        SELECT  StartTime
        FROM    S1
        UNION ALL
        SELECT  StartTime
        FROM    S2
),
S AS (
        SELECT  StartTime, ROW_NUMBER() OVER(ORDER BY StartTime) RN
        FROM    S3
),
E1 AS (
        SELECT  U.StartTime AS EndTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.StartTime BETWEEN DATEADD(s, 1, W.StartTime) AND W.EndTime
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.StartTime BETWEEN S.StartTime AND S.EndTime
        )
),
E2 AS (
        SELECT  S.EndTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.EndTime BETWEEN U.StartTime AND U.EndTime
        )
),
E3 AS (
        SELECT  EndTime
        FROM    E1
        UNION ALL
        SELECT  EndTime
        FROM    E2
),
E AS (
        SELECT  EndTime, ROW_NUMBER() OVER(ORDER BY EndTime) RN
        FROM    E3
)
SELECT  S.StartTime, E.EndTime
FROM    S INNER JOIN E
        ON S.RN = E.RN
ORDER BY S.RN

我已经为您破解了开始时间,您应该能够自己解决如何完成结束时间:

;WITH S1 AS (
        SELECT  U.EndTime AS StartTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.EndTime BETWEEN W.StartTime AND DATEADD(s, -1, W.EndTime)
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.EndTime BETWEEN S.StartTime AND S.EndTime
        )
),
S2 AS (
        SELECT  S.StartTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.StartTime BETWEEN U.StartTime AND U.EndTime
        )
)
SELECT  StartTime
FROM    S1
UNION ALL
SELECT  StartTime
FROM    S2
ORDER BY 1

这很好,拼图的最后一部分是将其缝合在一起:

;WITH S1 AS (
        SELECT  U.EndTime AS StartTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.EndTime BETWEEN W.StartTime AND DATEADD(s, -1, W.EndTime)
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.EndTime BETWEEN S.StartTime AND S.EndTime
        )
),
S2 AS (
        SELECT  S.StartTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.StartTime BETWEEN U.StartTime AND U.EndTime
        )
)
SELECT  StartTime
FROM    S1
UNION ALL
SELECT  StartTime
FROM    S2
ORDER BY 1


;WITH S1 AS (
        SELECT  U.StartTime AS EndTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.StartTime BETWEEN DATEADD(s, 1, W.StartTime) AND W.EndTime
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.StartTime BETWEEN S.StartTime AND S.EndTime
        )
),
S2 AS (
        SELECT  S.EndTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.EndTime BETWEEN U.StartTime AND U.EndTime
        )
)
SELECT  EndTime
FROM    S1
UNION ALL
SELECT  EndTime
FROM    S2
ORDER BY 1
;WITH S1 AS (
        SELECT  U.EndTime AS StartTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.EndTime BETWEEN W.StartTime AND DATEADD(s, -1, W.EndTime)
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.EndTime BETWEEN S.StartTime AND S.EndTime
        )
),
S2 AS (
        SELECT  S.StartTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.StartTime BETWEEN U.StartTime AND U.EndTime
        )
),
S3 AS (
        SELECT  StartTime
        FROM    S1
        UNION ALL
        SELECT  StartTime
        FROM    S2
),
S AS (
        SELECT  StartTime, ROW_NUMBER() OVER(ORDER BY StartTime) RN
        FROM    S3
),
E1 AS (
        SELECT  U.StartTime AS EndTime
        FROM    UnavailableTimes U
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes W
                WHERE   U.StartTime BETWEEN DATEADD(s, 1, W.StartTime) AND W.EndTime
        )
        AND EXISTS (
                SELECT  *
                FROM    Schedule S
                WHERE   U.StartTime BETWEEN S.StartTime AND S.EndTime
        )
),
E2 AS (
        SELECT  S.EndTime
        FROM    Schedule S
        WHERE   NOT EXISTS (
                SELECT  *
                FROM    UnavailableTimes U
                WHERE   S.EndTime BETWEEN U.StartTime AND U.EndTime
        )
),
E3 AS (
        SELECT  EndTime
        FROM    E1
        UNION ALL
        SELECT  EndTime
        FROM    E2
),
E AS (
        SELECT  EndTime, ROW_NUMBER() OVER(ORDER BY EndTime) RN
        FROM    E3
)
SELECT  S.StartTime, E.EndTime
FROM    S INNER JOIN E
        ON S.RN = E.RN
ORDER BY S.RN

您正在使用哪个数据库SQL Server(T-SQL)谢谢。这真的很有帮助。我能自己完成最后时刻。再次感谢你。我不知道如何把它们按正确的顺序排列。“ROW_NUMBER()OVER”是答案,我以前从未使用过。不客气,在这一点上,我可能应该指出,这个解决方案可能不会很好地“伸缩”,如果您正在考虑将类似的内容应用到商业产品中,那么最好有一个日历表,其中包含您需要的所有时间增量(例如每15分钟一次),并链接到该日历表。这样就很容易得到不使用的时段。祝你好运