Включает ли «между» MS SQL Server границы диапазона?


234

Например, может

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

выберите 5 и 10 или они исключены из диапазона?

Ответы:


258

МЕЖДУ оператором включительно.

Из книг онлайн:

BETWEEN возвращает TRUE, если значение test_expression больше или равно значению begin_expression и меньше или равно значению end_expression.

DateTime Caveat

NB: с DateTimes вы должны быть осторожны; если указана только дата, значение берется по состоянию на полночь этого дня; во избежание пропуска времени в вашей конечной дате или повторения захвата данных следующего дня в полночь в нескольких диапазонах ваша конечная дата должна быть за 3 миллисекунды до полуночи следующего дня после вашей даты. 3 миллисекунды, потому что любое значение меньше этого значения будет округлено до полуночи следующего дня.

например, чтобы получить все значения в течение июня 2016 года, вам нужно выполнить:

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'

11
Используя BETWEEN для фильтрации DateTimes между двумя датами, вы также можете привести DateTime к Date, например: where CONVERT (DATE, MyDate) BETWEEN '2017-09-01' и '2017-09-30' Этот подход требует времени элемент DateTime не имеет значения
Пит

1
Не пытайтесь отнять 3 мс от даты; Вы пропустите предметы из этих 3 мс. И вы также не хотите , чтобы CONVERTв DateTime на сегодняшний день , так как это делают индексы бесполезные. Используйте стандарт WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Кроме того, обязательно используйте yyyymmdd, так как yyyy-mm-ddэто зависит от локали, и будет неверно истолковано в зависимости от настроек вашего сервера mdy, dmy, ymd, ydm, myd, and dym.
Ян Бойд

254

Да, но будьте осторожны при использовании между датами.

BETWEEN '20090101' AND '20090131'

действительно интерпретируется как 12 утра, или

BETWEEN '20090101 00:00:00' AND '20090131 00:00:00'

поэтому пропустим все, что произошло в день 31 января. В этом случае вам придется использовать:

myDate >= '20090101 00:00:00' AND myDate < '20090201 00:00:00'  --CORRECT!

или

BETWEEN '20090101 00:00:00' AND '20090131 23:59:59' --WRONG! (see update!)

ОБНОВЛЕНИЕ : вполне возможно иметь записи, созданные в течение этой последней секунды дня, с датой и временем уже 20090101 23:59:59.997!!

По этой причине BETWEEN (firstday) AND (lastday 23:59:59) подход не рекомендуется.

myDate >= (firstday) AND myDate < (Lastday+1)Вместо этого используйте подход.

Хорошая статья по этому вопросу здесь .


1
Подобные проблемы со строками также WHERE col BETWEEN 'a' AND 'z'исключат большинство строк z, например.
Мартин Смит

8
Этот пункт, конечно, прав; но не удивительно, если вы работаете с датами. Это аналогично указанию на то, что BETWEEN 5 AND 10не включает 10.2...
Анджей Дойл

4
CASTтами , datetimeкак DATEбудет работать: CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
Крейг

2
@craig, это правда, если вы используете SQL 2008 или выше, то есть, когда был введен тип данных Date. Кроме того, этот синтаксис преобразует это значение для каждой отдельной строки, поэтому не сможет использовать индексы для этого поля (если это важно).
BradC

It is entirely possible to have records created within that last second of the day, with a datetime as late as 01/01/2009 23:59:59.997<- не могли бы вы просто тогда использовать AND '01/31/2009 23:59:59.99999999'или сколько требуется 9-ти
wal

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

Запрос:

SELECT
    *
FROM
    tbl
WHERE
    Start BETWEEN '2010-04-01 00:00:00' AND '2010-05-01 00:00:00'

Полученные результаты:

ID    Start
1     2010-04-30 00:00:01.000
2     2010-04-02 00:00:00.000

альтернативный текст


Я не получил ваш ответ, если честно. Возможно, мой интернет-провайдер скрыл ваш скриншот, если вы его опубликовали.
Анар Халилов

2
Почему строка с ID = 3исключена? Его Startзначение равно значению BETWEENверхней границы и BETWEENявляется включающим диапазоном, а не исключительным верхним ограниченным диапазоном.
Дай

Лучше ответь с результатами.
Сэм

13

если вы нажмете это и не захотите попробовать добавить день в коде, то пусть это сделает БД ..

myDate >= '20090101 00:00:00' AND myDate < DATEADD(day,1,'20090101 00:00:00')

Если вы включите часть времени: убедитесь, что она относится к полуночи. В противном случае вы можете просто пропустить время:

myDate >= '20090101' AND myDate < DATEADD(day,1,'20090101')

и не переживай об этом.


12

МЕЖДУ (Transact-SQL)

Определяет ( n ) ( включительно ) диапазон для проверки.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

аргументы

test_expression

Выражение для проверки в диапазоне, определенном begin_expression и end_expression. test_expression должен иметь тот же тип данных, что и begin_expression, и end_expression.

NOT

Указывает, что результат предиката должен быть отменен.

begin_expression

Является ли любое допустимое выражение. Параметр begin_expression должен иметь тот же тип данных, что и test_expression, и end_expression.

end_expression

Является ли любое допустимое выражение. end_expression должен иметь тот же тип данных, что и test_expression, и begin_expression.

AND

Действует как заполнитель, указывающий, что test_expression должен находиться в пределах диапазона, указанного в begin_expression и end_expression.

замечания

Чтобы указать исключительный диапазон, используйте операторы «больше» (>) и «меньше» (<). Если какой-либо вход в предикат BETWEEN или NOT BETWEEN имеет значение NULL, результат НЕИЗВЕСТЕН.

Результат Значение

BETWEEN возвращает TRUE, если значение test_expression больше или равно значению begin_expression и меньше или равно значению end_expression.

NOT BETWEEN возвращает TRUE, если значение test_expression меньше значения begin_expression или больше значения end_expression.


3

Если тип данных столбца - время-дата, вы можете сделать следующее, чтобы исключить время из даты-времени и сравнить только диапазон дат.

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)

Это работает лучше, чем добавление +1 к дате окончания. Я согласен с Эндрю Мортоном: если это невозможно, это может улучшить производительность, чтобы изменить тип данных столбца или добавить второй столбец только с предварительно вычисленными датами.
Арно Петерс

0

Это включает в себя границы.

declare @startDate date = cast('15-NOV-2016' as date) 
declare @endDate date = cast('30-NOV-2016' as date)
create table #test (c1 date)
insert into #test values(cast('15-NOV-2016' as date))
insert into #test values(cast('20-NOV-2016' as date))
insert into #test values(cast('30-NOV-2016' as date))
select * from #test where c1 between @startDate and @endDate
drop table #test
RESULT    c1
2016-11-15
2016-11-20
2016-11-30


declare @r1 int  = 10
declare @r2 int  = 15
create table #test1 (c1 int)
insert into #test1 values(10)
insert into #test1 values(15)
insert into #test1 values(11)
select * from #test1 where c1 between @r1 and @r2
drop table #test1
RESULT c1
10
11
15

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.