【问题标题】:SQL "between" not inclusiveSQL“之间”不包括在内
【发布时间】:2013-04-27 04:36:58
【问题描述】:

我有一个这样的查询:

SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'

但是即使1号有数据,这也没有结果。

created_at 看起来像2013-05-01 22:25:19,我怀疑它与时间有关?如何解决?

如果我做更大的日期范围,它工作得很好,但它应该(包括)也适用于单个日期。

【问题讨论】:

标签: sql sql-server sql-server-2008 tsql date


【解决方案1】:

你的代码

SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'

SQL 如何读取它

SELECT * FROM Cases WHERE '2013-05-01 22:25:19' BETWEEN '2013-05-01 00:00:00' AND '2013-05-01 00:00:00'

如果您在比较 DateTime 和 Date 时未提及时间,默认时时:分:秒在您的情况下将为零,日期相同,但如果您比较时间 created_at 是在结束日期范围之前的 22 hours

如果上述内容很清楚,您可以通过多种方式解决此问题,例如将结束时间放在结束日期中,例如 BETWEEN '2013-05-01' AND ''2013-05-01 23:59:59''

在转换为日期'2013-05-01 22:25:19' 之后将create_at 转换为cast(created_at as date) 这样的日期将等于'2013-05-01 00:00:00'

【讨论】:

    【解决方案2】:

    sql查询之间的动态日期

    var startDate = '2019-08-22';
    var Enddate = '2019-10-22'
         let sql = "SELECT * FROM Cases WHERE created_at BETWEEN '?' AND '?'";
         const users = await mysql.query( sql, [startDate, Enddate]);
    

    【讨论】:

      【解决方案3】:

      您需要执行以下两个选项之一:

      1. between 条件中包含时间组件:... where created_at between '2013-05-01 00:00:00' and '2013-05-01 23:59:59'(不推荐...见最后一段)
      2. 使用不等式代替between。请注意,您必须将一天添加到第二个值:... where (created_at >= '2013-05-01' and created_at < '2013-05-02')

      我个人的偏好是第二个选项。另外,Aaron Bertranda very clear explanation on why 应该使用。

      【讨论】:

      • +1 表示 2。但 -1 表示 1。这种结束一天的黑客攻击完全不可靠,而且是个坏主意。
      • @AaronBertrand 我也更喜欢选项 2(我经常使用它)。但是为什么你说选项 1“完全不可靠”呢?
      • please read this in full。对于包含时间的日期范围查询,您永远不应该使用BETWEEN;太多可能会出错。
      • 虽然 2. 有效,但我将始终将其写为 where ('2013-05-01' <= created_at and created_at <= '2013-05-01') 以提高可读性
      【解决方案4】:

      包容性的。您正在将日期时间与日期进行比较。第二个日期被解释为当天开始时的午夜

      解决此问题的一种方法是:

      SELECT *
      FROM Cases
      WHERE cast(created_at as date) BETWEEN '2013-05-01' AND '2013-05-01'
      

      另一种解决方法是显式二进制比较

      SELECT *
      FROM Cases
      WHERE created_at >= '2013-05-01' AND created_at < '2013-05-02'
      

      Aaron Bertrand 有一篇关于日期的长博客文章 (here),他在其中讨论了这个和其他日期问题。

      【讨论】:

      • 为了这个好答案的完整性,我建议使用dateadd 来获得第二天。
      • @TimLehner 为了得到一个好的答案,我会使用“20130501”的 ISO-8601 格式。对于使用 dateformat dmy 的非美国人,你会得到这个:set dateformat dmy;select month(cast('2013-05-01' as datetime)); =1
      • @RichardTheKiwi - 我相信 explicit 位正在使用一个在一端关闭的间隔 (&gt;=) 在另一端打开 (&lt;) 并结合检查一个指定结束日期之后的一天。
      • @scottb 就我个人而言,每次我想显示、导出、导入或编写带有日期时间的类时,我都会觉得很烦人。我认为 SQL Server 有很多内置功能可以在大多数情况下操作和比较日期时间。
      • 您永远不应该在where 子句中强制转换列,因为它会丢失它拥有的任何索引。这是一个非常糟糕的模式。
      【解决方案5】:

      我发现将日期时间字段与日期字段进行比较的最佳解决方案如下:

      DECLARE @StartDate DATE = '5/1/2013', 
              @EndDate   DATE = '5/1/2013' 
      
      SELECT * 
      FROM   cases 
      WHERE  Datediff(day, created_at, @StartDate) <= 0 
             AND Datediff(day, created_at, @EndDate) >= 0 
      

      这相当于一个包含的 between 语句,因为它包括开始日期和结束日期以及介于两者之间的日期。

      【讨论】:

        【解决方案6】:

        您可以使用date() 函数从日期时间中提取日期并将结果作为包含日期提供给您:

        SELECT * FROM Cases WHERE date(created_at)='2013-05-01' AND '2013-05-01'
        

        【讨论】:

          【解决方案7】:

          假设BETWEEN 语法中的第二个日期引用被神奇地认为是“一天的结束”,但这是不正确的

          即这是意料之中的:

          从案例中选择 * WHERE created_at BETWEEN 开始'2013-05-01'和结束'2013-05- 01'

          但真正发生的是:

          从案例中选择 * WHERE created_at BETWEEN '2013-05-01 00:00:00+00000' AND '2013-05-01 00:00:00+00000'

          相当于:

          SELECT * FROM Cases WHERE created_at = '2013-05-01 00:00:00+00000'

          问题是对BETWEEN 的看法/期望之一,确实包括范围内的下限值和上限值,但 神奇地使日期“开始”或“结束”。

          在按日期范围过滤时应避免使用BETWEEN

          始终改用&gt;= AND &lt;

          从案例中选择 * WHERE(created_at >= '20130501' AND created_at '20130502')

          括号在这里是可选的,但在更复杂的查询中可能很重要。

          【讨论】:

          • 在问题已经得到解答后,不确定发布此内容是否明智,但我想强调一点不同
          • 致编辑;请不要尝试将伪 SQL 制作成代码块,因为注释依赖 BOLD,它根本不起作用。
          • 请各位编辑(再次)不要通过伪代码添加虚假引号;他们不帮助理解。
          【解决方案8】:

          只需使用时间戳作为日期:

          SELECT * FROM Cases WHERE date(created_at)='2013-05-01' 
          

          【讨论】:

          【解决方案9】:
          cast(created_at as date)
          

          这仅适用于 2008 年和更新版本的 SQL Server

          如果您使用的是旧版本,请使用

          convert(varchar, created_at, 101)
          

          【讨论】:

          • convert(varchar, created_at, 101) 结果就像dd/MM/yyyy 并且OP的字符串是yyyy-MM-dd,我认为这个答案行不通;)。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-11
          • 1970-01-01
          相关资源
          最近更新 更多