SQL: МЕЖДУ vs <= и> =

111

В SQL Server 2000 и 2005:

  • в чем разница между этими двумя WHEREпунктами?
  • какой из них я должен использовать в каких сценариях?

Запрос 1:

SELECT EventId, EventName
FROM EventMaster
WHERE EventDate BETWEEN '10/15/2009' AND '10/18/2009'

Запрос 2:

SELECT EventId, EventName
FROM EventMaster
WHERE EventDate >='10/15/2009'
  AND EventDate <='10/18/2009'

(Изменить: вторая дата события изначально отсутствовала, поэтому запрос был синтаксически неверным)

Shyju
источник
1
Это квази-дубликат с stackoverflow.com/questions/1572840/sql-between-v1-and-v2
mjv,
6
не совсем так, обработка datetime немного отличается, плюс это было для SQL Server 2008, и Шайджу никак не мог быть уверен, не спросив, что ответ будет таким же для предыдущих версий.
Irfy

Ответы:

119

Они идентичны: BETWEENэто сокращение от более длинного синтаксиса вопроса.

Используйте альтернативный более длинный синтаксис, если BETWEENон не работает, например

Select EventId,EventName from EventMaster
where EventDate >= '10/15/2009' and EventDate < '10/18/2009'

(Обратите внимание, <а не <=во втором условии.)

Тони Эндрюс
источник
19
Может быть, вам следует подчеркнуть, что второе условие - это '<'. Мне потребовалось некоторое время, чтобы заметить разницу.
zendar
21
Я бы добавил, что настоятельно рекомендую никогда не использовать BETWEEN, если вы не имеете дело с типом данных DATE или иным образом не гарантировали, что ваши значения datetime никогда не будут иметь компонент времени. Последовательность в этом отношении снизит вероятность того, что вы по ошибке будете использовать BETWEEN вместо> = и <, и либо получите некоторые данные в запросе, которые вы не имели в виду, либо подумайте, что вы получаете дополнительный день данные, когда вы не ...
Аарон Бертран
1
Будет ли второй этап компиляции, когда BETWEEN преобразуется в условные выражения? Я понимаю, что это немного педантично, но будут ли дополнительные накладные расходы?
Джеймс Скотт
1
@xmashallax, потому что они такие? А как они?
Тони Эндрюс
2
Странно ... Думаю, меня смутил вопрос, написание ответа, комментарии и тот факт, что в моем коде явно есть ошибка =)
xmashallax
37

Они одинаковые.

Следует остерегаться одного: если вы используете это против DATETIME, совпадение для даты окончания будет началом дня:

<= 20/10/2009

не то же самое, что:

<= 20/10/2009 23:59:59

(это будет соответствовать <= 20/10/2009 00:00:00.000)

Irfy
источник
Вы можете просто использовать между '2009-10-20' и '2009-10-21' в этом случае, чтобы запечатлеть день
Дэвид Андрей Нед
4
@DavidAndreiNed, который также будет соответствовать '2009-10-21 00: 00: 00.000' - вероятно, не то, что вы хотите.
Ханс
2
Вам нужно поле BETWEEN '2009-10-20 00:00:00' AND '2009-10-20 23:59:59' или field> = '2009-10-20 00:00:00' AND field <= '2009-10-20 23:59:59', чтобы быть абсолютно уверенным.
geilt
@geilt В ваших примерах будет пропущено все, что произошло за последнюю секунду дня ... например, между 23:59:59 и 00:00:00 следующего дня.
Сет Флауэрс
00:00:00 - это начало следующего дня, и почему я использую> = и <=, а не> или <. Но если вы имели в виду микросекунды и сохраняете их, то вам также следует указать последнюю и последнюю микросекунду.
geilt
14

Хотя BETWEENего легко читать и поддерживать, я редко рекомендую его использовать, потому что это закрытый интервал, и, как упоминалось ранее, это может быть проблемой с датами - даже без компонентов времени.

Например, при работе с ежемесячными данными часто сравнивают даты BETWEEN first AND last, но на практике это обычно легче написать dt >= first AND dt < next-first(что также решает проблему временной части), поскольку определение lastобычно на один шаг дольше, чем определение next-first(путем вычитания дня) .

Кроме того, еще одна проблема заключается в том, что нижнюю и верхнюю границы необходимо указывать в правильном порядкеBETWEEN low AND high. Е. ).

Кейд Ру
источник
4

Как правило, разницы нет - BETWEENключевое слово не поддерживается на всех платформах СУБД, но если это так, два запроса должны быть идентичными.

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

marc_s
источник
4

Как упоминалось @marc_s, @Cloud и др. в основном они одинаковы для закрытого диапазона.

Но любые дробные значения времени могут вызвать проблемы с закрытым диапазоном (больше или равно и меньше или равно ) , в отличие от полуоткрытую диапазона (больше или равно , и менее чем ) с конечным значением после последний возможный момент.

Поэтому, чтобы избежать этого, запрос следует переписать как:

SELECT EventId, EventName
  FROM EventMaster
 WHERE (EventDate >= '2009-10-15' AND
        EventDate <  '2009-10-19')    /* <<<== 19th, not 18th */

Поскольку BETWEENне работает для полуоткрытых интервалов, я всегда внимательно смотрю на любой запрос даты / времени, который его использует, поскольку это, вероятно, ошибка.

devstuff
источник
4

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

Если, скажем, в нашей таблице есть и a, transactiondateи a transitiondate, если я прочитал

transactiondate between ...

Я сразу знаю, что оба конца теста против этого поля.

Если я прочитаю

transactiondate>='2009-04-17' and transactiondate<='2009-04-22'

Я должен воспользоваться дополнительным моментом, чтобы убедиться, что эти два поля совпадают.

Кроме того, поскольку запрос со временем редактируется, небрежный программист может разделить два поля. Я видел множество запросов, в которых говорилось что-то вроде

where transactiondate>='2009-04-17'
  and salestype='A'
  and customernumber=customer.idnumber
  and transactiondate<='2009-04-22'

Если они попробуют это сделать BETWEEN, конечно, это будет синтаксическая ошибка, и она будет быстро исправлена.

Джей
источник
3

Я думаю, единственная разница - это количество синтаксического сахара в каждом запросе. BETWEEN - это простой способ сказать то же самое, что и второй запрос.

Может быть какая-то особенная разница в СУБД, о которой я не знаю, но я так не думаю.

пирокумулус
источник
2

По логике вообще никакой разницы. С точки зрения производительности, как правило, на большинстве СУБД нет никакой разницы.

MJV
источник
1

Отказ от ответственности: все нижеприведенное является анекдотическим и основано непосредственно на моем личном опыте. Любой, кто считает нужным провести более строгий эмпирический анализ, может провести его и проголосовать против, если я. Я также знаю, что SQL - это декларативный язык, и вам не нужно учитывать, КАК ваш код обрабатывается, когда вы его пишете, но, поскольку я ценю свое время, я это делаю.

Существует бесконечное количество логически эквивалентных утверждений, но я рассмотрю три (иш).

Случай 1: два сравнения в стандартном порядке (фиксированный порядок оценки)

A> = MinBound И A <= MaxBound

Случай 2: Синтаксический сахар (порядок оценки не выбран автором)

МЕЖДУ MinBound И MaxBound

Случай 3: два сравнения в образованном порядке (порядок оценки выбран во время написания)

A> = MinBound И A <= MaxBound

Или

A <= MaxBound AND A> = MinBound

По моему опыту, случаи 1 и 2 не имеют каких-либо последовательных или заметных различий в производительности, поскольку они игнорируют набор данных.

Однако вариант 3 может значительно сократить время выполнения. В частности, если вы работаете с большим набором данных и у вас есть некоторые эвристические знания о том, будет ли A больше, чем MaxBound или меньше, чем MinBound, вы можете заметно улучшить время выполнения, используя случай 3 и упорядочивая сравнения соответственно.

Один из вариантов использования, который у меня есть, - это запрос большого набора исторических данных с неиндексированными датами для записей в пределах определенного интервала. При написании запроса я буду иметь представление о том, существует ли больше данных ДО указанного интервала или ПОСЛЕ указанного интервала, и могу соответственно упорядочить свои сравнения. У меня время выполнения сократилось наполовину в зависимости от размера набора данных, сложности запроса и количества записей, отфильтрованных при первом сравнении.

LanchPad
источник
Эм, что? Случай 3 не использует ту же логику, что и Случай 1 и Случай 2. Если вы хотите увидеть, Aбольше ли оно, чем обе границы, просто проверьте, больше ли Aоно, чем MaxBound. Ваш пост нуждается в корректировке.
mickmackusa
Похоже, я сделал опечатку в операторах равенства. Хороший улов.
LanchPad
0

В этом сценарии col BETWEEN ... AND ...и col <= ... and col >= ...эквивалентны.


Стандарт SQL определяет также предикат T461 Symmetric BETWEEN :

 <between predicate part 2> ::=
 [ NOT ] BETWEEN [ ASYMMETRIC | SYMMETRIC ]
 <row value predicand> AND <row value predicand>

Transact-SQL не поддерживает эту функцию.

BETWEENтребует сортировки значений. Например:

SELECT 1 WHERE 3 BETWEEN 10 AND 1
-- no rows

<=>

SELECT 1 WHERE 3 >= 10 AND 3 <= 1
-- no rows

С другой стороны:

SELECT 1 WHERE 3 BETWEEN SYMMETRIC 1 AND 10;
-- 1

SELECT 1 WHERE 3 BETWEEN SYMMETRIC 10 AND 1
-- 1

Он работает точно так же, как обычно, BETWEENно после сортировки значений сравнения.

db <> демо скрипта

Лукаш Шозда
источник