Почему SQL между, а не наполовину открыт?

45

Полуоткрытый (или Half-Open, полузакрытый , Half-Bounded ) интервалы ( [a,b)где xпринадлежит интервалу МФЛ a <= x < b) довольно распространены в программировании, так как они имеют много удобных свойств.

Может кто-нибудь предложить обоснование, которое объясняет, почему SQL BETWEENиспользует закрытый интервал ( [a,b])? Это особенно. неудобно для свиданий. Почему вы так BETWEENсебя вели?

Алекс
источник
Мне интересно, какие удобные свойства у них есть?
phant0m
2
если это не было включено, как вы могли бы легко запросить все фамилии в диапазоне от A до D? или имена от W до Z? Для чисел от 1 до 10 вы можете искать 0 <n <11, но для символов вам придется использовать числа ASCII? или Unicode номера? Кроме того, индексы могут легко привести вас к началу ваших данных.
JQA
2
Я понимаю ваше разочарование, (StartDate> = '2010-01-01' и StartDate <'2011-01-01'), работает прекрасно, использовать между Equivelent будет (StartDate между '2010-01-01' и ' 2010-12-31 23:59:59 '), и громоздким, и нужно знать, сколько дней в декабре
Тодд
1
@ phant0m [a, b) U [c, d) == [a, d). [a: int, b: int) содержит ровно ba элементов. Комментарий Тодда показывает, как они работают особенно хорошо для свиданий (которые я скучал по ним больше всего). По сути, при кодировании полуоткрытые интервалы имеют тенденцию быть проще, проще в использовании и надежнее.
Алекс
Лучший ответ должен был ссылаться на документацию по объективному решению от людей, которые сначала указали МЕЖДУ для SQL, таким образом отвечая на «Почему», а не на «субъективный ответ».
Тодд

Ответы:

48

Я думаю, что инклюзивность BETWEENболее интуитивна (и, очевидно, так же, как и дизайнеры SQL), чем полуоткрытый интервал. Например, если я скажу «Выберите число от 1 до 10», большинство людей будут включать числа от 1 до 10. В действительности открытый интервал особенно запутывает не-разработчиков, потому что он асимметричный. Иногда непрограммисты используют SQL для выполнения простых запросов, и полуоткрытая семантика была бы для них гораздо более запутанной.

Oleksi
источник
9
Ваш пример фокусируется на целых числах, для десятичных чисел и других разделенных величин (таких как даты) термин между неоднозначен. Если я скажу, что вы делали X между 2012 и 2013 годами, я не включаю 2013 (или конкретно день 2013-01-01)
Тодд
4
@Todd Любое использование этих терминов неоднозначно. Вот почему математики, ученые и опытные программисты документируют свое намерение как «полуоткрытое» или что-то подобное. Я думаю, что смысл ответа Олески в том, что SQL изначально предназначался для конечных пользователей, а не для программистов (на самом деле!). Очевидно, разработчики SQL сделали ударение на определении, которое они считали лучшим для этой аудитории. Но, как предполагают авторы Вопроса, полуоткрытое почти всегда лучше для работы с диапазонами, такими как промежутки времени.
Василий Бурк
«Я думаю, что инклюзивное МЕЖДУ более интуитивным» субъективно. «SQL иногда используют непрограммисты для выполнения простых запросов» - непрограммистам в равной степени необходимо проверять спецификации.
Тодд
Также часто задают вопрос «Выберите число от 1 до 10» (просто чтобы избежать явной двусмысленности). Как примечание стороны. Вы говорите «выберите число от 1 до 10»; большинство людей, вероятно, не выбрали бы 1 или 10. Разумеется, это скорее проблема психологии. :) Люди по-прежнему принимают 1 и 10 в качестве допустимых вариантов (несмотря на то, что они семантически неверны); но это результат контекстной интерпретации, предполагающей, что 1 и 10 верны. Если вы скажете: «между 13 и 24», и вас с большей вероятностью спросят, включены ли 13 и 24.
Разочарован
26

ВОПРОС: Почему SQL между включительно?

ОТВЕТ: Поскольку разработчики языка SQL приняли плохое проектное решение, им не удалось предоставить синтаксис, который позволил бы разработчикам указать, какой из 4 вариантов BETWEEN (закрытый, полуоткрытый левый, полуоткрытый правый или открытый они бы предпочли.

РЕКОМЕНДАЦИЯ: Если / до тех пор, пока не будет изменен стандарт SQL, не используйте МЕЖДУ для дат / времени. Вместо этого приобретите привычку кодировать сравнения диапазона ДАТЫ как независимые условия на начальной и конечной границах вашего диапазона МЕЖДУ. Это немного многословно, но оставит вам написание условий, которые являются интуитивно понятными (а значит, менее подвержены ошибкам) ​​и понятными оптимизаторам базы данных, что позволяет определять оптимальные планы выполнения и использовать индексы.

Например, если ваш запрос принимает спецификацию входного дня и должен вернуть все записи, приходящиеся на эту дату, вы должны кодировать как:

  • WHERE DATE_FIELD >= :dt AND DATE_FIELD < :dt+1

Попытка написать логику с помощью BETWEEN рискует проблемами с производительностью и / или ошибочным кодом. Три распространенных оплошности:

1) WHERE DATE_FIELD BETWEEN :dt AND :dt+1

Это почти наверняка ошибка - пользователь ожидает увидеть только записи за определенную дату, но в один прекрасный день будет получен отчет, содержащий записи с 12:00 следующего дня.

2) WHERE TRUNC(DATE_FIELD) = :dt

Дает правильный ответ, но применение функции к DATE_FIELD сделает большую часть индексации / статистики бесполезной (хотя иногда администраторы баз данных пытаются помочь, добавляя индексы на основе функций к полям даты - по-прежнему сжигая человеко-часы и дисковое пространство и добавляя накладные расходы на IUD операции на столе)

3) WHERE EVENT_DATE BETWEEN :dt AND :dt + 1-1/24/60/60

Том Кайт, экстраординарный гуру Oracle, рекомендует это не слишком элегантное (IMO) решение. Работает отлично, пока вы не потратите весь день на поиск этого «1-1 / 24/06/60» в запросе, который дает неполные результаты ... или пока вы случайно не используете его в поле TIMESTAMP. Плюс, это немного запатентовано; совместим с типом данных Oracle DATE (который отслеживает второй), но должен быть скорректирован с точностью DATE / TIME различных продуктов баз данных.

РЕШЕНИЕ: обратиться в комитет ANSI SQL с просьбой улучшить спецификации языка SQL, изменив синтаксис BETWEEN для поддержки спецификации альтернатив по умолчанию CLOSED / INCLUSIVE. Нечто подобное могло бы сработать:

выражение1 МЕЖДУ expr2 [ ВКЛ [USIVE] | EXCL [USIVE]] И expr3 [ ВКЛ [USIVE] | EXCL [USIVE]]

Подумайте, как легко выразить WHERE DATE_FIELD BETWEEN :dt INCLUSIVE AND :dt+1 EXCLUSIVE(или просто WHERE DATE_FIELD BETWEEN :dt AND :dt+1 EXCL)

Может быть, ANSI SQL: 2015?

KevinKirkpatrick
источник
Этот ответ мудрый совет.
Василий Бурк
@KevinKirkPatrick - Отличный ответ! Я предлагаю вам также попытаться найти документацию по принятию решения в качестве объективного доказательства первоначальной причины.
Тодд
3
Лично мне нравится, exp1 BETWEEN exp2 AND exp3 AND exp1 != exp3что вы можете поддерживать оператор между, чтобы вы знали, что это ранжированный предикат, а предикат неравенства гарантирует его полуоткрытость.
Сентин
@ Страж, Ницца! Я не собираюсь объявлять себя конвертированным преждевременно, но я обязательно запомню этот вариант при следующем кодировании условий диапазона дат. На первый взгляд, он обладает большей лингвистической привлекательностью, чем exp1> = exp2 AND exp1 <exp3; и, очевидно, одинаково хорошо решает проблемы с МЕЖДУ. Мне было бы интересно, если бы оптимизаторы показали большее «понимание» одного варианта над другим; конечно, кажется правдоподобным, что ваши результаты также могут дать лучшие результаты в этом отношении (хотя, честно говоря, я был бы весьма разочарован оптимизатором, который относился к ним по-разному)
KevinKirkpatrick
@KevinKirkpatrick Я никогда не рассказывал им, чтобы выяснить, есть ли различия, и я тоже был бы разочарован, если бы они были.
Сентин
8

И inclusive ( a <= x <= b), и exclusive ( a < x < b) примерно одинаковы, поэтому при разработке стандартов им просто нужно было выбрать один. «Между» в обычном английском языке обычно включительно, и SQL-выражение предназначено для чтения, похожего на английское предложение, поэтому включение было разумным выбором.

Мэтт С
источник
4
На самом деле использование на английском еще более смешано, так как вы оставили Half-Open. Когда мы говорим «обед между 12:00 и 13:00», мы имеем в виду полуоткрытое, когда вас ожидают вернуться на урок / работу в момент с 13:00 до 00 000, перерыв до первого, но не включающего час часов. a <= x < bполуоткрыт.
Василий Бурк
1
@BasilBourque: Это может быть из-за бесконечной точности - например, обед между 12: 59: 99.9999999999999 ....
Брендан
@ Брендан Да, вы делаете мою точку зрения. Бесконечная (или неоднозначная) точность является одной из проблем, которая решается с помощью полуоткрытого подхода к определению промежутка времени. Дело в том, что в английском разговоре мы интуитивно обращаемся с открытыми и закрытыми (как уже упоминалось в этом ответе), а также с полуоткрытыми диапазонами, не задумываясь. Каждый подход служит цели. Вот почему определение SQL BETWEEN не является оптимальным. В идеале SQL следовал бы предложению Кевина Киркпатрика .
Василий Бурк
2
Предполагается, что SQL похож на английский, и хотя инклюзивные и эксклюзивные могут быть одинаково распространены, это язык запросов для аналитиков и программистов. Как программист, я думаю, что это определено неправильно, но это не имеет значения, я все равно избегаю использовать «МЕЖДУ». Не ахти какое дело.
Тодд
5

Оператор не вызывается ∩[a,b), он называется BETWEEN, так что его семантика гораздо более уместна, если использовать его в английской фразе «находится между», чем в математическом предикате «находится в полуоткрытом интервале».

AakashM
источник
Нужно рассмотреть все приложения, а не только английские приложения для целочисленных множеств. «между 1 и 10», «между полуднем и 13:00», «между 1,0 и 5,0» (граммы). «от 5,50 до 10,30» (доллары). Непрерывные количества будут логически (по-английски) считаться исключительными.
Тодд
1
Проблема в том, что BETWEENоператор не использует семантику английской фразы «между». В английском языке «между» - это время, пространство или интервал, который разделяет вещи (то есть, он исключает ). Если вы попытаетесь ударить по мячу, мяч должен пройти между стойками, чтобы забить. Если вы нажмете на сообщение, не пройдя между ними - нет очков для вас.
Разочарован
1
@CraigYoung, как следует из принятого ответа (и я согласен), «если я скажу« Выберите число от 1 до 10 », большинство людей включит цифры от 1 до 10 [в свой диапазон возможных ответов]». В пространственной области я согласен с вами, но для чисел я бы сказал, что все по-другому. Лучше для английского языка и использования, чем здесь, хотя!
AakashM
@AakashM Моя точка зрения состоит в том, что вы сделали заявление об английском языке, который является просто ложным по словарному определению слова «между», чтобы оправдать семантику программирования. Тот факт, что есть общее понимание фразы «между 1 и 10», имеет меньшее отношение к значению «между» и больше касается позиций 1 и 10 в десятичной системе счисления. «Автокоррекция» человеческого мозга игнорирует, что «между» исключает конечные точки в этом случае, потому что кажется смешным означать «от 2 до 9». Попробуйте то же самое с «между 13 и 24». Или даже «между 0 и 11».
Разочарован
Между вами и мной категорические заявления о естественных языках обычно небезопасны.
AakashM