MS SQL Server的"之间"是否包含范围边界?

Lea*_*rou 229 sql sql-server between

比如可以

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10
Run Code Online (Sandbox Code Playgroud)

选择5和10还是他们被排除在范围之外?

DJ.*_*DJ. 252

BETWEEN运算符包含在内.

来自联机丛书:

如果test_expression的值大于或等于begin_expression的值且小于或等于end_expression的值,则BETWEEN返回TRUE.

DateTime警告

注意:使用DateTimes你必须要小心; 如果只给出一个日期,那么该值是在当天的午夜时截取的; 为了避免在结束日期内丢失时间,或者在多个范围内的午夜重复捕获第二天的数据,您的结束日期应该是在您到目前为止的第二天午夜之前的3毫秒.3毫秒,因为任何小于此值,该值将被四舍五入到第二天的午夜.

例如,要获得2016年6月内的所有值,您需要运行:

where myDateTime between '20160601' and DATEADD(millisecond, -3, '20160701')

where myDateTime between '20160601 00:00:00.000' and '20160630 23:59:59.997'

datetime2和datetimeoffset

从日期减去3毫秒将使您容易在3毫秒窗口中丢失行.正确的解决方案也是最简单的解决方案:

where myDateTime >= '20160601' AND myDateTime < '20160701'
Run Code Online (Sandbox Code Playgroud)

  • 当使用BETWEEN过滤两个日期之间的DateTime时,您也可以将DateTime转换为日期,例如:CONVERT(DATE,MyDate)BETWEEN'2017-09-01'和'2017-09-30'这种方法可以让时间DateTime的元素无关紧要 (11认同)
  • 确保不要尝试从日期中减去 3 毫秒;你会错过那 3 毫秒的项目。而且您也不希望将 **datetime** 转换为 **date**,因为这会使索引变得无用。使用标准的`WHERE OrderDate &gt;= '20160601' AND OrderDate &lt; '20160701'`。此外,请务必使用 `yyyymmdd`,因为 `yyyy-mm-dd` 是依赖于语言环境的,并且会根据您服务器的 `mdy、dmy、ymd、ydm、myd 和 dym` 设置而被误解。 (2认同)

Bra*_*adC 251

是的,但在日期之间使用时要小心.

BETWEEN '20090101' AND '20090131'
Run Code Online (Sandbox Code Playgroud)

真的被解释为12点,或者

BETWEEN '20090101 00:00:00' AND '20090131 00:00:00'
Run Code Online (Sandbox Code Playgroud)

所以会遗漏1月31日那天发生的任何事情.在这种情况下,您将不得不使用:

myDate >= '20090101 00:00:00' AND myDate < '20090201 00:00:00'  --CORRECT!
Run Code Online (Sandbox Code Playgroud)

要么

BETWEEN '20090101 00:00:00' AND '20090131 23:59:59' --WRONG! (see update!)
Run Code Online (Sandbox Code Playgroud)

更新:完全有可能在当天的最后一秒创建记录,日期时间最晚20090101 23:59:59.997!

因此,BETWEEN (firstday) AND (lastday 23:59:59)不建议采用这种方法.

改用这种myDate >= (firstday) AND myDate < (Lastday+1)方法.

这里有关于这个问题的文章.

  • 这一点当然是正确的; 但如果你正在处理日期时间,那就不应该感到惊讶.它类似于指出"BETWEEN 5和10"不包括"10.2"...... (8认同)
  • ``'datetime`为'DATE`将起作用:'CAST(DATE_TIME_COL AS DATE)在'01/01/2009'和'01/31/2009'之间. (4认同)
  • @craig,这是真的,只要你使用的是SQL 2008或更高版本,就是引入Date数据类型的时候.此外,该语法将为每一行转换该值,因此将无法在该字段上使用任何索引(如果这是一个问题). (2认同)

Rya*_*yer 16

来自SQL Server 2008的真实示例.

来源数据:

ID    Start
1     2010-04-30 00:00:01.000
2     2010-04-02 00:00:00.000
3     2010-05-01 00:00:00.000
4     2010-07-31 00:00:00.000
Run Code Online (Sandbox Code Playgroud)

查询:

SELECT
    *
FROM
    tbl
WHERE
    Start BETWEEN '2010-04-01 00:00:00' AND '2010-05-01 00:00:00'
Run Code Online (Sandbox Code Playgroud)

结果:

ID    Start
1     2010-04-30 00:00:01.000
2     2010-04-02 00:00:00.000
Run Code Online (Sandbox Code Playgroud)

替代文字

  • 为什么排除了“ID = 3”的行?它的“Start”值等于“BETWEEN”上界值,“BETWEEN”是一个包含范围,而不是一个排除上界范围。 (3认同)

小智 13

如果你点击这个,并且真的不想尝试处理在代码中添加一天,那么让DB去做吧..

myDate >= '20090101 00:00:00' AND myDate < DATEADD(day,1,'20090101 00:00:00')
Run Code Online (Sandbox Code Playgroud)

如果你确实包括时间部分:确保它引用午夜.否则你可以简单地省略时间:

myDate >= '20090101' AND myDate < DATEADD(day,1,'20090101')
Run Code Online (Sandbox Code Playgroud)

而不用担心它.


Rus*_*Cam 12

BETWEEN(Transact-SQL)

指定要测试的(n)(包含)范围.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression
Run Code Online (Sandbox Code Playgroud)

参数

test_expression
Run Code Online (Sandbox Code Playgroud)

是否在begin_expression和end_expression定义的范围内测试表达式.test_expression必须与begin_expression和end_expression具有相同的数据类型.

NOT
Run Code Online (Sandbox Code Playgroud)

指定否定谓词的结果.

begin_expression
Run Code Online (Sandbox Code Playgroud)

是否有效表达.begin_expression必须与test_expression和end_expression具有相同的数据类型.

end_expression
Run Code Online (Sandbox Code Playgroud)

是否有效表达.end_expression必须与test_expression和begin_expression具有相同的数据类型.

AND
Run Code Online (Sandbox Code Playgroud)

作为占位符表示test_expression应该在begin_expression和end_expression指示的范围内.

备注

要指定独占范围,请使用大于(>)和小于运算符(<).如果BETWEEN或NOT BETWEEN谓词的任何输入为NULL,则结果为UNKNOWN.

结果值

如果test_expression的值大于或等于begin_expression的值且小于或等于end_expression的值,则BETWEEN返回TRUE.

如果test_expression的值小于begin_expression的值或大于end_expression的值,则NOT BETWEEN返回TRUE.