【问题标题】:Select records where date not in table of multiple date ranges SQL Server选择日期不在多个日期范围的表中的记录 SQL Server
【发布时间】:2012-02-25 02:44:12
【问题描述】:

我在 SQL Server 中有一个包含各种日期范围的表。

表格的开始日期和结束日期如下:-

start_date                  end_date
=======================     =======================
2011-02-21 00:00:00.000     2011-02-25 00:00:00.000
2011-04-18 00:00:00.000     2011-04-29 00:00:00.000
2011-05-31 00:00:00.000     2011-06-03 00:00:00.000
2011-07-21 00:00:00.000     2011-08-31 00:00:00.000
2011-10-24 00:00:00.000     2011-10-28 00:00:00.000
2011-12-19 00:00:00.000     2012-01-02 00:00:00.000
2012-02-13 00:00:00.000     2012-02-17 00:00:00.000
2012-04-02 00:00:00.000     2012-04-13 00:00:00.000
2012-06-04 00:00:00.000     2012-06-08 00:00:00.000
2012-07-20 00:00:00.000     2012-08-31 00:00:00.000
2012-10-29 00:00:00.000     2012-11-02 00:00:00.000
2012-12-24 00:00:00.000     2013-01-01 00:00:00.000
2013-02-10 00:00:00.000     2013-02-16 00:00:00.000
2013-03-24 00:00:00.000     2013-04-06 00:00:00.000
2013-05-26 00:00:00.000     2013-06-01 00:00:00.000
2013-07-24 00:00:00.000     2013-08-31 00:00:00.000
2013-10-27 00:00:00.000     2013-11-02 00:00:00.000

我需要从另一个表中选择日期戳在上述任何范围内都不存在的记录。

上表中的开始日期和结束日期可能相同,表示只排除一天。

我最初的想法是扩展上述范围内的所有日期,然后执行 SELECT WHERE NOT EXISTS IN,还是有更有效的方法来实现这一点?

【问题讨论】:

  • 另一个表是否只存储日期或者是否可以包含时间,这是否相关。例如,您可以在排除表中将“02/02/2012”作为开始和结束,并将值“02/02/2012 12:00”进行比较。在大多数提交的答案中,这不会被排除在外,因此它似乎是一个关键的信息。
  • 根据帖子,日期格式如下:2012-12-24 00:00:00.000 看起来所有时间都是 00:00:00.000

标签: sql sql-server date between


【解决方案1】:

您可以对范围表进行左连接,并添加一个 where 子句过滤掉任何匹配项。

SELECT anothertable.* FROM anothertable
LEFT JOIN range on anothertable.date >= range.start_date and anothertable.date <= range.end_date
WHERE range.start_date IS NULL

【讨论】:

    【解决方案2】:
    SELECT t.* 
    FROM AnotherTable t 
    WHERE NOT EXISTS(
        SELECT 1 
        FROM TblDate d 
        WHERE d.start_date <= t.DateColumn
        AND   d.end_date   >= t.DateColumn
    )
    

    编辑:刚刚看到这是您最初的想法。所以我认为这是最简单和最快的方法。以下是有关此主题的内容:

    http://sqlserverperformance.idera.com/tsql-optimization/finding-nonexistent-records-hurry/

    【讨论】:

    • 对不起之前的评论,你是对的。我将“日期戳”误读为“时间戳”。
    【解决方案3】:

    在(我认为)最终结果相同的情况下,以下建议比您的建议更有效。我唯一不确定的是,我是否了解您关于开始日期等于结束日期然后不包括一整天的标准。

    SELECT  *
    FROM    Table1
            LEFT JOIN
            (   SELECT  Start_date, CASE WHEN End_Date = Start_Date THEN DATEADD(MILLISECOND, -1, DATEADD(DAY, 1, End_Date)) ELSE End_Date END [End_Date]
                FROM    table2
            ) Exc
                ON table.DateColumn BETWEEN Exc.Start_Date AND Exc.End_Date
    WHERE   Exc.Start_Date IS NULL
    

    【讨论】:

      【解决方案4】:

      您需要检查 2 个条件: 1.日期在范围之间 2. Date 与 start_date 具有相同的 Day,但比 end_date 晚(范围内没有小时、分钟和秒)

      SELECT * FROM VALUE_TABLE
      LEFT JOIN DATE_RANGE_TABLE ON 
        YEAR(VALUE_TABLE.CHECK_DATE) = YEAR(start_date)
        and MONTH (VALUE_TABLE.CHECK_DATE) = MONTH (start_date)
        AND DAY (VALUE_TABLE.CHECK_DATE) = DAY (start_date)
        OR VALUE_TABLE.CHECK_DATE BETWEEN start_date and end_date
      WHERE start_date IS NULL
      

      【讨论】:

      • @chris - 在堆栈溢出时,您可以假定 [sql-server] 标记专门适用于 Microsoft SQL Server。您可以将鼠标悬停在标签上以获得简短的摘要。
      【解决方案5】:
      select * from anothertable
      WHERE NOT EXISTS (SELECT 1 FROM range 
                         WHERE anothertable.date BETWEEN range.start_date AND range.end_date)
      

      使用BETWEEN 而不是&lt;= and &gt;=

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多