DATEDIFF() 或 BETWEEN 用于 SQL 查询中的日期范围

Posted

技术标签:

【中文标题】DATEDIFF() 或 BETWEEN 用于 SQL 查询中的日期范围【英文标题】:DATEDIFF() or BETWEEN for Date Ranges in SQL Queries 【发布时间】:2013-01-04 08:48:58 【问题描述】:

我最近被告知在 SQL 中使用BETWEEN 方法有些不可靠,因此我应该使用DATEDIFF()。但是,另一位程序员告诉我情况并非如此,只要日期格式正确,BETWEEN 方法在所有情况下都能出色地工作。

请有人通过说明哪种方法更好以及为什么来解决这场争论?

目前我的日期范围 SQL 如下所示:

DATEDIFF(d,'01-Jan-1970',SIH.[Something_Date]) >= 0 AND DATEDIFF(d,'01-Jan-2013',SIH.[Something_Date]) <= 0

但是,如果我能确定它是可靠的,我宁愿这样写:

SIH.[Something_Date] BETWEEN '01-Jan-1970' AND '01-Jan-2013'

在这种特殊情况下,我使用的是 MsSQL,但是,我已经标记了 MySQL,因为我想知道这是否也适用于此

【问题讨论】:

“SQL 中的 BETWEEN 方法有些不可靠”——什么意思? 在这种情况下,您应该选择两者之间,因为它会在扫描时考虑索引,但在 DATEDIFF 中不考虑索引 @MitchWheat 这就是我被告知的,他没有说明为什么它不可靠,他只是说我不应该使用它 也许他们试图引用列有时间部分的事实?这与“不可靠”非常不同 如果不是不可靠的,它至少被一些人认为是邪恶的。 What do BETWEEN and the devil have in common? 【参考方案1】:

您的两个查询不等价。 datediff 版本将包括来自01-Jan-2013 的所有值,而与时间无关,而介于两者之间的版本将仅包括01-Jan-2013 上时间为00:00:00 的行。

如果您检查范围并且不对列进行任何计算,则您的查询将能够使用Something_Date 上的索引,同时包括来自01-Jan-2013 的所有值,无论时间部分如何.

where
  SIH.[Something_Date] >= '19700101' and
  SIH.[Something_Date] < '20130102'

【讨论】:

很困惑,你是说如果一个字段指定的时间不是 00:00:00 那么BETWEEN 会找不到它吗? @BenCarey 是的,这就是我的意思。当开发人员发现这一点时,他们通常会在“第二天”之间做一个间隔,而不是有副作用,即他们包含从第二天开始的带有时间 00:00:00 的行。当他们弄清楚这一点时,他们会写中间以使用20130101 23:59:59,并错过了最后一秒。当他们发现这一点时,他们尝试20130101 23:59:59.999 只是为了发现datetime 值的精度为3 ms,因此它向上舍入到20130102 00:00:00。到那时,即使20130101 23:59:59.997 确实有效,他们也希望停止使用 between,至少对于 datetime 太棒了,这就是我被指示不要使用它的原因。非常感谢:-) +1【参考方案2】:

避免 BETWEEN 的原因是,如果您的日期值可以包含时间组件,则无法正确使用它。如果包括时间,则与上限的比较必须使用严格小于比较,排除 BETWEEN。

另一方面,如果您知道日期值从不包含时间组件,或者如果您有一种方便的方法可以删除时间组件,那么我更喜欢使用 BETWEEN,因为它看起来更具可读性。

在 Oracle SQL 中,我可以使用 TRUNC 函数来删除时间部分(它也可以截断为 'MONTH' 或 'YEAR')。

所以我可以写:

where TRUNC(date_col) between '01-JAN-2021' and '31-DEC-2021'

并确保测试不会错过 31 日也有时间成分的日期。

我的印象是,TRUNC(和ROUND)的这种用法可能是 Oracle 独有的。我不知道 mysql 或 T-SQL 中是否有等价物。 (我似乎记得必须使用 datediff 技巧来完成 TRUNC 的工作。

如果没有TRUNC(或等效项),您必须使用:

where '01-JAN-2021' <= date_col and date_col < '01-JAN-2022'

注意与上限的比较必须严格小于。

这更短,可读性更强,可能更高效,并且保证可以工作。

但我还是更喜欢使用TRUNCBETWEEN,因为逻辑更清晰。 (在我做对之前,我以两种不同的方式搞砸了第二个示例)。

我怀疑效率是否存在很大差异,即使在大多数情况下,这也可能不是问题。我认为可读性比效率更重要(大多数时候)。

当然,正确性胜过一切。所以如果你没有方便的方法来移除时间分量或者必须包含时间分量,那么你就不能使用BETWEEN来准确测试datetime的值。

【讨论】:

以上是关于DATEDIFF() 或 BETWEEN 用于 SQL 查询中的日期范围的主要内容,如果未能解决你的问题,请参考以下文章

SQL学习——BETWEEN运算符

(MySQL) 使用 DATEDIFF 函数时遇到问题

s-s-rS - 用于计算当前日期匹配或(参数选择日期)与其他一些等效列的行的表达式

12 BETWEEN的用法

s-s-rS/报表生成器 datediff 以工作日为单位

流分析:源“子查询”只能用于使用“datediff”函数的时间谓词