【问题标题】:SQL Server between two datetime fields, not working correctly两个日期时间字段之间的 SQL Server,无法正常工作
【发布时间】:2011-05-10 01:11:00
【问题描述】:

SQL Server 2005:

以下视图

  SELECT CONVERT(VARCHAR(20), keyedtimestamp, 101) as KeyedDate
    FROM TMSSTATFILE_STATS a                                                                
   WHERE (CONVERT(VARCHAR(20), a.KeyedTimestamp, 101) BETWEEN '03/01/2011' And '03/31/2011')  
ORDER BY KeyedDate

结果为关键日期 2011 年 3 月 2 日至 2011 年 3 月 31 日。

如果我将第一个日期更改为 03/00/2011

  SELECT CONVERT(VARCHAR(20), keyedtimestamp, 101) as KeyedDate
    FROM TMSSTATFILE_STATS a                                                                
   WHERE (CONVERT(VARCHAR(20), a.KeyedTimestamp, 101) BETWEEN '03/00/2011' And '03/31/2011')  
ORDER BY KeyedDate

它现在提供日期为 2011 年 3 月 1 日至 2011 年 3 月 31 日的数据

KeyedTimestamp 字段是 DateTime,并且有与这些记录相关联的时间。 2011 年 3 月 31 日的所有记录均已计算在内。我知道我可以通过在第二个日期之间提供最大时间来做到这一点,所以我不是在寻找替代 where 子句,而是理解为什么它忽略了第一个记录,即使它包含了这些记录从 31 日开始。

它几乎就像它检查 3/1/2011 23:59:59,我希望我可以消除这种我只关心日期而不是时间的检查

【问题讨论】:

    标签: sql-server between


    【解决方案1】:

    通过不使用 BETWEEN 来避免列上的函数。函数意味着永远不会使用任何索引

    WHERE
        a.KeyedTimestamp >= '20110301' AND a.KeyedTimestamp < '20110401'  
    

    pre-SQL Server 2008 yyyymmdd唯一安全的日期格式。

    【讨论】:

    • 而 pre-SQL Server 2008 yyyymmdd 是唯一安全的日期格式。...除非你使用Set DateFormat
    • @Thomas:这就是为什么 yyyymdd 可以安全使用:不依赖于 Set DateFormat 并且它独立于环境。恕我直言,依赖设置的 DateFormat 或设置的语言并不安全。如果这是一个必须在客户端的 SQL 框上运行的第三方应用程序怎么办?您是否阅读了我的链接中带有 marc_s 的背面和 cmets?
    • DateFormat 应该始终有效。事实上,我相信 ADO.NET 驱动程序会发送 Set DateFormat。这个问题可以追溯到很多版本。我记得在 SQL 7.0 时代读过 Kalen Delaney 的一篇关于同一主题的文章。如果您正在写出查询,那么使用 YYYYMMDD 是最安全的,但通常在您和查询之间存在一个抽象层。
    • 顺便说一句,当我谈到 DateFormat 总是有效时,我的意思是你在每个有日期的查询之前设置它。我并不是要假设它在您运行查询之前设置为您所期望的。
    • 关于索引信息的奖励,感谢您提供宝贵的信息!
    【解决方案2】:

    您不应该将日期时间转换为字符串。相反,将它们作为日期时间进行比较。听起来您正在尝试解决存储时间的问题:

    Select DateAdd(d, DateDiff(d, 0, T.KeyedTimeStamp), 0) As KeyedDate
    From TMSSTATFILE_STATS As T
    Where T.KeyedTimeStamp >= '20110301'
        And T.KeyedTimeStamp < DateAdd(m,1,'20110301')
    

    需要注意的是DateTimeVal Between DateTimeA And DateTimeB 转换为DateTimeVal &gt;= DateTimeA And DateTimeVal &lt;= DateTimeB。即,它包括两个端点。在上述解决方案中,我得到了下个月的第一天,并要求所有值严格小于该值,这意味着将包括三月份的所有值,包括时间。最后,Select 语句从所有返回的 KeyedTimeStamp 值中剥离时间值。

    【讨论】:

      【解决方案3】:

      您是否尝试过转换为DATETIME 值(或类似值)然后进行比较?您正在比较字符串...我不知道 '03/00/2011' 在概念上对 BETWEEN 运算符意味着什么。坦率地说,我很惊讶您的结果完全有意义!

      SQL Server 2008 有一个本机 DATE 类型,它不包括时间戳。 如果您没有没有时间戳的本机类型(您提到 V9),您可以使用以下内容:

      SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, your_date_here))
      

      摘自 Anatoly Lubarsky 的博客:
      http://blogs.x2line.com/al/archive/2006/02/17/1458.aspx

      【讨论】:

      • 我假设 2005 年,连接说版本 9,但我可以做 CTE。 2005 没有日期,只有日期时间。我相信日期直到 2008 年才开始发挥作用,这就是为什么我要开始有趣的转换
      • 对,我注意到您提到了 V9...但是您不应该将日期作为字符串进行比较...这可能是这里的失败。
      【解决方案4】:

      没有进行日期时间比较,在比较时一切都是 VARCHAR。

      试试:

      SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, keyedtimestamp)) as KeyedDate
      FROM TMSSTATFILE_STATS a                                                                
      WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, keyedtimestamp)) BETWEEN '03/01/2011' AND '03/31/2011'
      ORDER BY DATEADD(dd, 0, DATEDIFF(dd, 0, keyedtimestamp))
      

      【讨论】:

      • 这很有效,并且是我正在寻找的行为。鉴于转换为 varchar,我很惊讶它正在工作,所以我想知道幕后发生了什么让这项工作首先发生。
      猜你喜欢
      • 2020-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-05
      • 2017-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多