SQL: МЕЖ ДО <= і> =


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'

(Редагувати: другий Дата події спочатку відсутній, тому запит був синтаксично неправильним)


1
Це квазі дублікат з stackoverflow.com/questions/1572840/sql-between-v1-and-v2
MJV

6
Насправді, обробка даних timetime дещо інша, плюс це було для SQL-сервера 2008 року, і Shyju не може бути впевнений, не вимагаючи, щоб відповідь була однаковою для попередніх версій.
Ірфі

Відповіді:


119

Вони ідентичні: BETWEENце скорочення для довшого синтаксису питання.

Використовуйте альтернативний довший синтаксис, де BETWEENне працює, наприклад

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

(Зверніть увагу, <а не <=на другу умову.)


19
Можливо, вам слід підкреслити, що друга умова - «<». Знадобилося мені трохи часу, щоб помітити різницю.
zendar

21
Я додам, що я настійно рекомендую ніколи не використовувати BETWEEN, якщо ви не маєте справу з типом даних DATE або іншим чином гарантуєте, що значення вашої дати ніколи не будуть складовою часу. Якщо дотримуватися цього, ви зробите меншою ймовірність, що ви будете використовувати 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)


Ви можете просто використовувати в цьому випадку між '2009-10-20' та '2009-10-21', щоб захопити день
David Andrei Ned

4
@DavidAndreiNed, що також відповідатиме "2009-10-21 00: 00: 00.000" - ймовірно, не те, що ви хочете.
Ганс Ке

2
Ви хочете поле МЕЖУ '2009-10-20 00:00:00' І '2009-10-20 23:59:59' або поле> = '2009-10-20 00:00:00' І поле <= '2009-10-20 23:59:59', щоб бути абсолютно впевненим.
geilt

@geilt Ваші приклади будуть пропускати все, що сталося протягом останньої секунди дня ... тобто: між 23:59:59 та 00:00:00 наступного дня.
Seth Flowers

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ключове слово не підтримується на всіх платформах RDBMS, але якщо воно є, два запити повинні бути однаковими.

Оскільки вони однакові, насправді немає різниці в швидкості чи в іншому - використовуйте той, який здається вам більш природним.


4

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

Але будь-які дробові значення часу можуть викликати проблеми з закритим діапазоном (більше або дорівнює і менше або дорівнює ) , на відміну від напіввідчинені діапазону (більше або дорівнює , і менш ніж ) з кінцевим значенням після останній можливий момент.

Щоб уникнути того, що запит слід переписати як:

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

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


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

Думаю, єдина різниця - кількість синтаксичного цукру в кожному запиті. МЕЖДУ - просто хитрий спосіб сказати точно так само, як і другий запит.

Можливо, є якась специфічна різниця RDBMS, про яку я не знаю, але я не думаю, що так.


2

Логічно різниці взагалі немає. Виконання продуктивності існує - типово, для більшості СУБД - різниці взагалі немає.



1

Відмова від відповідальності: все, що нижче, лише анекдотичне та витягнуте безпосередньо з мого особистого досвіду. Кожен, хто захоче провести більш емпірично суворий аналіз, може запросити його і проголосувати, якщо я буду. Я також усвідомлюю, що SQL є декларативною мовою, і вам не доведеться вважати, ЯК ваш код обробляється під час його написання, але, оскільки я ціную свій час, я це роблю.

Є нескінченно логічно еквівалентні твердження, але я розгляну три (ish).

Випадок 1: Два порівняння у стандартному порядку (Порядок оцінювання фіксований)

A> = MinBound AND A <= MaxBound

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

МІЖ МІНБАНКІВ І МАКСУБДОВИХ

Випадок 3: Два порівняння в освіченому порядку (Порядок оцінювання, обраний під час запису)

A> = MinBound AND A <= MaxBound

Або

A <= MaxBound AND A> = MinBound

На моєму досвіді, у випадку 1 та випадку 2 немає жодних послідовних чи помітних відмінностей у роботі, оскільки вони невідомі до набору даних.

Однак Case 3 може значно покращити терміни виконання. Зокрема, якщо ви працюєте з великим набором даних і маєте деякі евристичні знання про те, чи є A швидше більший за MaxBound або менший, ніж MinBound, ви можете помітно покращити час виконання, використовуючи Case 3 і замовляючи порівняння відповідно.

Один із випадків використання, який я маю - це запит великого історичного набору даних з неіндексованими датами для записів протягом певного інтервалу. Під час написання запиту я буду мати гарне уявлення про те, чи існує більше даних перед тим, як вказаний інтервал або ПІСЛЯ вказаного інтервалу, і можу відповідно замовити свої порівняння. У мене було скорочено терміни виконання приблизно на половину залежно від розміру набору даних, складності запиту та кількості записів, відфільтрованих за допомогою першого порівняння.


Гм, що? Випадок 3 не поділяє ту ж логіку, що і у випадку 1 та у випадку 2. Якщо ви хочете побачити, чи Aбільша вона від обох меж, просто перевірте, чи Aбільша величина, ніж величина MaxBound. Ваша посада потребує певного коригування.
mickmackusa

Схоже, я зробив друк на операторах рівності. Хороший улов.
LanchPad

0

У цьому сценарії col BETWEEN ... AND ...і col <= ... and col >= ...рівнозначні.


Стандарт SQL визначає також T461 симетричний між предикатом :

 <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 <> скриптова демонстрація

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.