Чи включає "між" MS SQL Server "межі" діапазону?


234

Наприклад, може

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

виберіть 5 і 10 або вони виключені з діапазону?

Відповіді:


258

Оператор BETWEEN включено.

З книг онлайн:

BETWEEN повертає TRUE, якщо значення test_expression більше або дорівнює значенню begin_expression і менше або дорівнює значенню end_expression.

ДатаTime 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 та timetime offset

Віднімання 3 мс від дати зробить вас вразливими до відсутніх рядків у вікні 3 мс. Правильне рішення також є найпростішим:

where myDateTime >= '20160601' AND myDateTime < '20160701'

11
Використовуючи BETWEEN для фільтрації DateTimes між двома датами, ви також можете призначати DateTime до дати, наприклад: де CONVERT (DATE, MyDate) МЕЖДУ '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:00, або

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 рядків 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
пройдіть

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

alt текст


Чесно кажучи, я не отримав вашої відповіді. Можливо, мій інтернет-провайдер приховав ваш екран, якщо ви розмістили його.
анар халілов

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 повинен бути того ж типу даних, що і тестовий вираз і кінцевий вираз.

end_expression

Чи будь-яке дійсне вираження. end_expression повинен бути того ж типу даних, що і тестовий_вираз і start_expression.

AND

Виступає як заповнювач місця, який вказує на тестовий вираз, повинен знаходитися в межах діапазону, зазначеного початковим виразом та кінцевим виразом.

Зауваження

Щоб вказати ексклюзивний діапазон, використовуйте більше (>) та менше операторів (<). Якщо будь-який вхід до предиката 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.