选择期间不重叠的日期范围

Sim*_*.A. 7 sql sql-server date

我有两个表,每个表都包含几个时期的开始和结束日期。我想要一种有效的方法来查找日期在第一个表的范围内但不在第二个表的范围内的期间(日期范围)。

例如,如果这是我的第一张桌子(有我想要的日期)

start_date  end_date
2001-01-01  2010-01-01
2012-01-01  2015-01-01
Run Code Online (Sandbox Code Playgroud)

这是我的第二张桌子(我不想要的日期)

start_date  end_date
2002-01-01  2006-01-01
2003-01-01  2004-01-01
2005-01-01  2009-01-01
2014-01-01  2018-01-01
Run Code Online (Sandbox Code Playgroud)

然后输出看起来像

start_date  end_date
2001-01-01  2001-12-31
2009-01-02  2010-01-01
2012-01-01  2013-12-31
Run Code Online (Sandbox Code Playgroud)

我们可以安全地假设第一个表中的期间不重叠,但不能假设第二个表中的期间重叠。

我已经有一种方法可以做到这一点,但它比我能接受的要慢一个数量级。所以希望有人可以提出一个更快的方法。

我目前的方法看起来像:

  1. 将表 2 合并为不重叠的时段
  2. 求表 2 的倒数
  3. 连接表 1 和倒表 2 中的重叠时段

如果可以将其中一些步骤合并在一起,我相信会有更快的方法。

更详细

start_date  end_date
2001-01-01  2010-01-01
2012-01-01  2015-01-01
Run Code Online (Sandbox Code Playgroud)

Sim*_*.A. 0

感谢@zip 和@Gordon 的回答。两者都优于我最初的方法。然而,在我的环境和上下文中,以下解决方案比他们的两种方法都要快:

WITH acceptable_starts AS (
    SELECT [start_date] FROM table1 AS a
    WHERE NOT EXISTS (
        SELECT 1 FROM table2 AS b
        WHERE DATEADD(DAY, 1, a.[end_date]) BETWEEN b.[start_date] AND b.
    UNION ALL
    SELECT DATEADD(DAY, 1, [end_date]) FROM table2 AS a
    WHERE NOT EXISTS (
        SELECT 1 FROM table2 AS b
        WHERE DATEADD(DAY, 1, a.[end_date]) BETWEEN b.[start_date] AND b.[end_date]
    )
),
acceptable_ends AS (
    SELECT [end_date] FROM table1 AS a
    WHERE NOT EXISTS (
        SELECT 1 FROM table2 AS b
        WHERE DATEADD(DAY, -1, a.[start_date]) BETWEEN b.[start_date] AND b.[end_date]
    )
    UNION ALL
    SELECT DATEADD(DAY, -1, [start_date]) FROM table2 AS a
    WHERE NOT EXISTS (
        SELECT 1 FROM table2 AS b
        WHERE DATEADD(DAY, -1, a.[start_date]) BETWEEN b.[start_date] AND b.[end_date]
    )
)
SELECT s.[start_date], MIN(e.[end_date]) AS [end_date]
FROM acceptable_starts
INNER JOIN acceptable_ends
ON s.[start_date] < e.[end_date]
Run Code Online (Sandbox Code Playgroud)