为什么SQL的BETWEEN具有包容性而不是半开放?


45

半开放(或半开放,半封闭半有界)间隔([a,b),其中x属于间隔iff a <= x < b)在编程中非常常见,因为它们具有许多方便的属性。

谁能提供解释SQL为什么BETWEEN使用封闭间隔([a,b])的理由?这是特别的。日期不便。你怎么会BETWEEN这样


我很好奇,它们有什么便利的属性?
phant0m 2012年

2
如果不包括在内,您如何轻松查询A到D范围内的所有姓氏?或将W命名为Z?对于1到10之间的数字,您可以搜索0 <n <11,但是对于字符,您是否必须使用ASCII数字?或unicode码?另外,索引可以轻松将您带到数据的开始。
2012年

2
我了解您的无奈,(StartDate> ='2010-01-01'和StartDate <'2011-01-01')效果很好,要在等价之间使用(StartDate在'2010-01-01'和' 2010-12-31 23:59:59' ),体积大,需要知道有多少天在十二月
托德

1
@ phant0m [a,b)U [c,d)== [a,d)。[a:int,b:int)恰好包含ba元素。托德(Todd)的评论显示了它们在约会中的效果特别好(这是我最想念的日期)。基本上,在编码时,半开放间隔趋向于更简单,更易于使用且更可靠。
Alex

最佳答案应该参考最初为SQL指定BETWEEN的人员的客观决策文档,从而回答“为什么”,而不是选择的主观答案。
2014年

Answers:


48

我认为包容性BETWEEN比半开放时间间隔更直观(并且显然SQL设计者也是如此)。例如,如果我说“选择一个介于1到10之间的数字”,大多数人将包括数字1和10。对于非开发人员来说,开放式间隔实际上特别令人困惑,因为它是不对称的。SQL是偶尔使用非程序员进行简单的查询和半开放式的语义本来为他们多混乱。


9
您的示例着重于整数,对于十进制数字和其他定界数量(例如日期),“之间”一词是不明确的。如果我说您在2012年至2013年之间做过X,则不包括2013年(或具体说是2013
托德

4
@Todd这些术语的任何用法都不明确。这就是为什么数学家,科学家和精明的程序员将其意图记录为“半开放式”之类的原因。我认为Oleski的答案是SQL最初是面向最终用户而不是程序员的(真的!)。显然,SQL设计人员对他们认为最适合该受众的定义不屑一顾。但是正如课题作者所建议的那样,半开通常对于处理诸如时间跨度之类的范围几乎总是更好。
罗勒·布尔克

“我认为包容性BETWEEN更直观”是主观的。“非程序员有时会使用SQL来进行简单查询”-非程序员同样需要检查规范。
2014年


这个问题也常常问“选择一个号码 1 10”(只是为了避免明显的不确定性)。作为旁注。您说“选择1到10之间的数字”;大多数人可能不会选择1或10。当然,这更多是心理学问题。:)人们仍然会接受1和10作为有效选择(尽管在语义上不正确);但这是上下文解释的结果,假设 1和10有效。如果您说:“ 13和24之间”,则很可能会询问您是否包含13和24。
幻灭了

25

问题:为什么SQL的BETWEEN具有包容性?

解答:由于SQL语言设计者做出的设计决策很差,因此他们未能提供语法,使开发人员无法指定BETWEEN的4个变体中的哪个(封闭式,半开放式,半开放式或开放式)。 ),他们更喜欢。

建议:除非/直到对SQL标准进行修订,否则不要在日期/时间中使用BETWEEN。而是养成将DATE范围比较编码为BETWEEN范围的开始和结束边界上的独立条件的习惯。这有点冗长,但是会使您编写直观的条件(因此不太可能出现错误)并且对于数据库优化器来说是清楚的,从而可以确定最佳的执行计划并使用索引。

例如,如果您的查询接受输入日期规范,并且应返回该日期的所有记录,则您可以将代码编码为:

  • WHERE DATE_FIELD >= :dt AND DATE_FIELD < :dt+1

尝试使用BETWEEN编写逻辑可能会导致性能问题和/或错误代码。三种常见的失误:

1) WHERE DATE_FIELD BETWEEN :dt AND :dt+1

几乎可以肯定这是一个错误-用户希望只看到特定日期的记录,但是最后一天将生成包含第二天凌晨12:00的记录的报告。

2) WHERE TRUNC(DATE_FIELD) = :dt

给出正确答案,但是将函数应用于DATE_FIELD将使大多数索引/统计信息无用(尽管有时DBA会尝试通过在日期字段中添加基于函数的索引来提供帮助-仍然会消耗大量的工作时间和磁盘空间,并增加IUD的开销桌上的操作)

3) WHERE EVENT_DATE BETWEEN :dt AND :dt + 1-1/24/60/60

Oracle高级专家Tom Kyte推荐了这种不太雅致(IMO)的解决方案。直到您整日在查询中发现结果不完整的“ 1-1 / 24/06/60”为止,或者直到您在TIMESTAMP字段上不小心使用了它,效果都很好。另外,它有点专有;与Oracle的DATE数据类型(可追溯到第二种)兼容,但需要调整为不同数据库产品的DATE / TIME精度。

解决方案:请ANSI SQL委员会通过修改BETWEEN语法来支持CLOSED / INCLUSIVE缺省选项的替代规范,以增强SQL语言规范。这样的事情可以解决问题:

表达式1 BETWEEN 表达式2 [ INCL [USIVE] | EXCL [USIVE]]和expr3 [ INCL [USIVE] | EXCL [USIVE]]

考虑表达WHERE DATE_FIELD BETWEEN :dt INCLUSIVE AND :dt+1 EXCLUSIVE(或仅仅是WHERE DATE_FIELD BETWEEN :dt AND :dt+1 EXCL)变得多么容易

也许是ANSI SQL:2015?


这个答案是圣人的建议。
罗勒·布尔克

@KevinKirkPatrick-好答案!我建议您也尝试查找决策文档,作为原始“为什么”的客观证据。
2014年

3
我个人喜欢这样exp1 BETWEEN exp2 AND exp3 AND exp1 != exp3,您可以保留between运算符,因此您知道它是一个范围谓词,并且不等式谓词可确保它是半开放的。
Sentinel 2015年

@哨兵,很好!我不会过早声明自己要进行转换,但是在下次编写日期范围条件时,我一定会牢记此变体。乍一看,它确实比exp1> = exp2 AND exp1 <exp3具有更大的语言吸引力;显然可以很好地解决BETWEEN的问题。我想知道是否有任何优化器对一个变体比另一个变体有更好的“理解”;当然,在这方面您也可能会产生更好的结果似乎是合理的(尽管坦率地说,在对它们进行不同处理的优化程序中,我会非常失望)
KevinKirkpatrick

@KevinKirkpatrick我从来没有介绍过它们以确定是否存在差异,如果存在差异,我也将感到失望。
Sentinel

8

包含(a <= x <= b)和排斥(a < x < b)两者几乎相同,因此在制定标准时,他们只需选择一个即可。普通英语中的“之间”通常是包含性的,并且SQL语句的读法类似于英语句子,因此包含性是明智的选择。


4
实际上,当您省去半开时,英语的用法甚至更多。当我们说“午餐中午和下午1点之间,”我们平均半开的,你是回料类在13力矩/工作:00:00.000,与休息要上,但不包括第一时刻一点钟的时间。a <= x < b是半开。
罗勒·布尔克

1
@BasilBourque:这可能是由于无限的精确度-例如,午餐时间在正午到12:59:99.9999999999999 ....
Brendan

@Brendan是的,你是我的意思。无限(或模棱两可)的精度是使用半开方法定义时间跨度要解决的问题之一。这里的要点是,在英语会话中,我们无需过多考虑即可直观地处理开放和封闭(如本答案中所述)以及半开放范围。每种方法都有目的。这就是为什么BETWEEN的SQL定义不够理想的原因。理想情况下,SQL将遵循KevinKirkpatrick建议
罗勒·布尔克

2
SQL应该像英语一样,尽管包容性和排他性可能同样普遍,但它是分析人员和程序员的查询语言。作为程序员,我认为它的定义是错误的,但这并不重要,无论如何,我只是避免使用“ BETWEEN”。没有大碍。
2014年

5

运算符没有被调用∩[a,b),它被称为BETWEEN,所以它的语义要比英语谓词“处于半开区间”的语义更适合英语单词 “在...之间”。


需要考虑所有应用程序,而不仅仅是整数集的英语应用程序。“在1到10之间”,“中午到1pm之间”,“ 1.0到5.0之间”(克)。“介于5.50和10.30之间”(美元)。逻辑上(英语)上连续的数量被认为是排他的。
2014年

1
问题在于BETWEEN操作员使用英语短语“在...之间”的语义。在英语中,“之间”是事物分隔开的时间,空间或间隔(即,它是排他的)。如果您尝试踢球,则球必须在杆之间移动才能得分。如果您发帖失败,则无法在两者之间传递-没有分数。
幻灭了

1
@CraigYoung作为公认的答案表明(我同意),“如果我说“选择1到10之间的数字”,则大多数人会在可能的答案范围内包括数字1和10。在空间方面,我同意你的看法,但对于数字我会说是不同的。比这里更好的英语语言和用法
AakashM

@AakashM我的观点是,您已经对英语进行了声明,根据字典中“ between”一词的定义,这完全是错误的,以证明编程语义是合理的。对短语“介于1和10之间”有一个普遍的了解,这与“介于之间”的含义无关,而与十进制数字系统中的位置1和10无关。在这种情况下,人脑的“自动校正”忽略了“在...之间”排除了端点,因为这似乎意味着“从2到9”是荒谬的。用“ 13至24之间”尝试相同的操作。甚至是“ 0到11之间”。
幻灭了

在您和我之间,关于自然语言的明确主张通常是不安全的。
AakashM
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.