Dlaczego SQL BETWEEN jest włączony, a nie w połowie otwarty?

45

Półotwarte (lub pół-Open, przymknięte , Half-Bounded ) interwały ( [a,b), gdzie xnależy do przedziału MFF a <= x < b) są dość powszechne na programowaniu, ponieważ mają one wiele dogodnych właściwości.

Czy ktoś może przedstawić uzasadnienie wyjaśniające, dlaczego SQL BETWEENużywa zamkniętego przedziału ( [a,b])? To jest esp. niewygodne dla dat. Dlaczego miałbyś BETWEENsię tak zachowywać?

alex
źródło
Jestem ciekaw, jakie mają wygodne właściwości?
phant0m,
2
jeśli nie było to włączone, w jaki sposób można łatwo wyszukać wszystkie nazwiska z zakresu od A do D? lub nazwy W do Z? W przypadku liczb od 1 do 10 możesz wyszukać 0 <n <11, ale w przypadku znaków musisz użyć liczb ASCII? czy numery Unicode? Ponadto indeksy mogą łatwo doprowadzić Cię do początku danych.
jqa
2
Rozumiem twoją frustrację, (StartDate> = „2010-01-01” i StartDate <„2011-01-01”), działa pięknie, aby użyć Między ekwiwalentem byłoby (StartDate między „2010-01-01” a „ 2010-12-31 23:59:59 '), zarówno nieporęczne, jak i trzeba wiedzieć, ile dni jest w grudniu
Todd
1
@ phant0m [a, b) U [c, d) == [a, d). [a: int, b: int) zawiera dokładnie elementy ba. Komentarz Todda pokazuje, w jaki sposób działają szczególnie dobrze na randki (czyli tam, gdzie najbardziej za nimi tęsknię). Zasadniczo, podczas kodowania, półotwarte interwały wydają się być prostsze, łatwiejsze w użyciu i solidne.
alex,
Najlepsza odpowiedź powinna odwoływać się do obiektywnej dokumentacji decyzji osób, które jako pierwsze określiły BETWEEN dla SQL, odpowiadając tym samym na pytanie Dlaczego, a nie na wybraną odpowiedź subiektywną.
Todd

Odpowiedzi:

48

Myślę, że włączenie BETWEENjest bardziej intuicyjne (i najwyraźniej tak samo zrobili projektanci SQL) niż półotwarty przedział. Na przykład, jeśli powiem „Wybierz liczbę od 1 do 10”, większość osób będzie zawierać liczby 1 i 10. Interwał otwarty jest w rzeczywistości szczególnie mylący dla nie-programistów, ponieważ jest asymetryczny. Niekiedy programiści używają języka SQL do tworzenia prostych zapytań, a semantyczna półotwarta byłaby dla nich znacznie bardziej zagmatwana.

Oleksi
źródło
9
Twój przykład koncentruje się na liczbach całkowitych, dla liczb dziesiętnych i innych ograniczonych wielkości (takich jak daty), termin pomiędzy jest niejednoznaczny. Jeśli powiem, czy zrobiłeś X między 2012 a 2013 rokiem, nie uwzględniam 2013 (a konkretnie dnia 2013-01-01)
Todd
4
@Todd Każde użycie tych warunków jest dwuznaczne. Dlatego matematycy, naukowcy i doświadczeni programiści dokumentują swój zamiar jako „na wpół otwarty” lub podobny. Myślę, że sednem odpowiedzi Oleskiego jest to, że SQL był pierwotnie przeznaczony dla użytkowników końcowych, a nie dla programistów (naprawdę!). Najwyraźniej projektanci SQL spróbowali zdefiniować najlepszą dla tej grupy odbiorców definicję. Ale jak sugerują autorzy pytania, półotwarta jest prawie zawsze lepsza do pracy z zakresami, takimi jak przedziały czasu.
Basil Bourque,
„Myślę, że integracja MIĘDZY jest bardziej intuicyjna” jest subiektywna. „Czasami użytkownicy niebędący programistami używają języka SQL do wykonywania prostych zapytań” - nieprogramiści musieliby również sprawdzić specyfikację.
Todd
Często zadawane jest również pytanie „Wybierz liczbę od 1 do 10” (aby uniknąć oczywistej dwuznaczności). Na marginesie. Mówisz „wybierz liczbę od 1 do 10”; większość ludzi prawdopodobnie nie wybrałaby 1 lub 10. To prawda, że ​​to bardziej problem psychologiczny. :) Ludzie nadal przyjmowaliby 1 i 10 jako prawidłowe wybory (mimo że są semantycznie niepoprawne); ale wynika to z interpretacji kontekstualnej przy założeniu, że 1 i 10 są prawidłowe. Gdybyś powiedział: „między 13 a 24”, a częściej pytane jest, czy uwzględniono 13 i 24.
Rozczarowany
26

PYTANIE: Dlaczego SQL zawiera MIĘDZY włącznie?

ODPOWIEDŹ: Ponieważ projektanci języka SQL podjęli kiepską decyzję projektową, ponieważ nie dostarczyli składni, która pozwoliłaby programistom określić, który z 4 wariantów BETWEEN (zamknięty, pół-otwarty-lewy, pół-otwarty-prawy lub otwarty ) woleliby.

ZALECENIE: O ile / dopóki nie zostanie zmieniony standard SQL, nie używaj MIĘDZY datami / godzinami. Zamiast tego nabądź zwyczaju kodowania porównań zakresu DATE jako niezależnych warunków na granicach początkowych i końcowych zakresu BETWEEN. Jest to trochę zbyt szczegółowe, ale pozostawi Ci warunki do pisania, które są intuicyjne (a więc mniej prawdopodobne, że będą wadliwe) i jasne dla optymalizatorów bazy danych, umożliwiając określenie optymalnych planów wykonania i użycie indeksów.

Na przykład, jeśli zapytanie akceptuje specyfikację dnia wejściowego i powinno zwrócić wszystkie rekordy, które przypadły w tym dniu, kodujesz jako:

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

Próba napisania logiki przy użyciu BETWEEN ryzykuje problemy z wydajnością i / lub błędny kod. Trzy typowe błędy:

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

To prawie na pewno błąd - użytkownik oczekuje, że zobaczy tylko rekordy dla określonej daty, ale pewnego dnia zakończy się raport zawierający rekordy od godziny 12:00 następnego dnia.

2) WHERE TRUNC(DATE_FIELD) = :dt

Daje prawidłową odpowiedź, ale zastosowanie funkcji do DATE_FIELD sprawi, że większość indeksowania / statystyk stanie się bezużyteczna (chociaż czasami DBA próbują pomóc, dodając indeksy oparte na funkcjach do pól daty - nadal spalając roboczogodziny i miejsce na dysku oraz dodając koszty ogólne do IUD operacje na stole)

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

Tom Kyte, nadzwyczajny guru Oracle, zaleca to mniej niż eleganckie (IMO) rozwiązanie. Działa świetnie, dopóki nie spędzasz całego dnia na znalezieniu „1-1 / 24/06/60” w zapytaniu, które daje niekompletne wyniki ... lub dopóki przypadkowo nie użyjesz go w polu TIMESTAMP. Ponadto jest to trochę zastrzeżone; zgodny z typem danych DATE Oracle (który śledzi do drugiego), ale należy go dostosować do dokładności DATA / CZAS różnych produktów bazodanowych.

ROZWIĄZANIE: Złóż petycję do komitetu ANSI SQL w celu ulepszenia specyfikacji języka SQL poprzez modyfikację składni BETWEEN w celu obsługi specyfikacji alternatyw dla wartości domyślnej CLOSED / INCLUSIVE. Coś takiego mogłoby załatwić sprawę:

wyr1 MIĘDZY wyraż2 [ WŁĄCZNIE [USIVE] | WYŁĄCZENIEM [USIVE]] I wyrażenie3 [ WŁĄCZNIE [USIVE] | EKSKLUZYWNY] ]

Zastanów się, jak łatwo jest wyrazić WHERE DATE_FIELD BETWEEN :dt INCLUSIVE AND :dt+1 EXCLUSIVE(lub po prostu WHERE DATE_FIELD BETWEEN :dt AND :dt+1 EXCL)

Może ANSI SQL: 2015?

KevinKirkpatrick
źródło
Ta odpowiedź jest mądrą radą.
Basil Bourque,
@KevinKirkPatrick - Świetna odpowiedź! Sugeruję również, abyś spróbował znaleźć dokumentację decyzji jako obiektywny dowód oryginalnego Dlaczego.
Todd
3
Osobiście podoba mi się exp1 BETWEEN exp2 AND exp3 AND exp1 != exp3to, jak możesz zachować operatora między, więc wiesz, że jest to predykat dystansowy, a predykat nierówności zapewnia, że ​​jest częściowo otwarty.
Sentinel,
@Sentinel, Nicea! Nie zamierzam przedwcześnie deklarować konwersji, ale na pewno będę pamiętać o tym wariancie, gdy następnym razem koduję warunki zakresu dat. Przy pierwszym rumieńcu ma on większą atrakcyjność językową niż exp1> = exp2 AND exp1 <exp3; i oczywiście rozwiązuje problemy z BETWEEN równie dobrze. Byłbym zainteresowany, gdyby jakiś optymalizator wykazał lepsze „zrozumienie” jednej odmiany w stosunku do drugiej; z pewnością wydaje się prawdopodobne, że twoje mogą również przynieść lepsze wyniki w tym względzie (choć szczerze mówiąc, byłbym bardzo rozczarowany optymalizatorem, który traktował je inaczej)
KevinKirkpatrick
@KevinKirkpatrick Nigdy ich nie profilowałem, aby sprawdzić, czy są jakieś różnice, i ja też byłbym rozczarowany, gdyby tak było.
Sentinel
8

Zarówno inclusive ( a <= x <= b), jak i exclusive ( a < x < b) są mniej więcej tak samo powszechne, więc przy tworzeniu standardów po prostu musiał wybrać jeden. „Pomiędzy” we wspólnym języku angielskim jest zwykle włącznie, a wyrażenie SQL ma brzmieć podobnie do zdania w języku angielskim, więc włączenie było rozsądnym wyborem.

Matt S.
źródło
4
W rzeczywistości użycie w języku angielskim jest jeszcze bardziej zróżnicowane, ponieważ pominięto opcję Half-Open. Kiedy mówimy „obiad jest między południem a 1 PM” rozumiemy pół-otwarty w które są oczekiwanym powrotem w klasie / pracę w chwili 13: 00: 00.000, z przerwa podchodząc do , ale nie w tym pierwszym momencie godzina pierwsza. a <= x < bjest półotwarty.
Basil Bourque,
1
@BasilBourque: Może to wynikać z nieskończonej precyzji - np. Lunch jest między południem a 12: 59: 99.999999999999999 ....
Brendan
@Brendan Tak, masz rację. Nieskończona (lub niejednoznaczna) precyzja jest jednym z problemów, który rozwiązuje się, stosując półotwarte podejście do definiowania przedziału czasu. Chodzi o to, że w rozmowie w języku angielskim intuicyjnie obsługujemy otwarte i zamknięte (jak wspomniano w tej odpowiedzi), a także półotwarte zakresy bez większego namysłu. Każde podejście służy celowi. Dlatego definicja SQL BETWEEN jest mniejsza niż optymalna. Idealnie byłoby, gdyby SQL podążał za sugestią Kevina Kirkpatricka .
Basil Bourque,
2
SQL powinien być podobny do angielskiego i chociaż włączanie i wyłączanie mogą być równie powszechne, jest to język zapytań dla analityków i programistów. Jako programista myślę, że jest źle zdefiniowany, ale to nie ma znaczenia, po prostu unikam używania „MIĘDZY”. Żaden problem.
Todd
5

Operator nie jest wywoływany ∩[a,b), jest wywoływany BETWEEN, więc znacznie bardziej odpowiednie jest, aby jego semantyka była w angielskiej frazie „jest pomiędzy” niż w predykacie matematycznym „jest w półotwartym przedziale”.

AakashM
źródło
Trzeba wziąć pod uwagę wszystkie aplikacje, nie tylko angielskie dla zestawów liczb całkowitych. „od 1 do 10”, „od południa do 13”, „od 1,0 do 5,0” (w gramach). „od 5,50 do 10,30” (dolary). Ilości ciągłe byłyby logicznie (w języku angielskim) uważane za wyłączne.
Todd
1
Problem polega na tym, że BETWEENoperator nie używa semantyki angielskiej frazy „jest pomiędzy”. W języku angielskim „pomiędzy” to czas, przestrzeń lub interwał, który oddziela rzeczy (tj. Jest wyłączny ). Jeśli spróbujesz kopnąć gola, piłka musi przejść między słupkami, aby zdobyć bramkę. Jeśli trafisz w słupek, nie przechodząc między nimi - nie uzyskasz żadnego wyniku.
Rozczarowany
1
@CraigYoung, jak sugeruje zaakceptowana odpowiedź (i zgadzam się), „jeśli powiem„ Wybierz liczbę od 1 do 10 ”, większość osób uwzględni liczby 1 i 10 [w zakresie możliwych odpowiedzi]”. W dziedzinie przestrzennej zgadzam się z tobą, ale w przypadku liczb powiedziałbym, że jest inaczej. Lepsze dla języka angielskiego i użytkowania niż tutaj!
AakashM
@AakashM Chodzi mi o to, że zgłosiłeś roszczenie dotyczące języka angielskiego, który jest po prostu fałszywy według słownikowej definicji słowa „pomiędzy”, aby uzasadnić semantykę programowania. Fakt, że istnieje powszechne zrozumienie wyrażenia „między 1 a 10”, ma mniej wspólnego ze znaczeniem „między”, a bardziej z pozycjami 1 i 10, w systemie liczb dziesiętnych. „Autokorekta” ludzkiego mózgu ignoruje to, że „pomiędzy” wyklucza punkty końcowe w tym przypadku, ponieważ absurdalne wydaje się oznaczenie „od 2 do 9”. Spróbuj tego samego z „od 13 do 24”. Lub nawet „między 0 a 11”.
Rozczarowany
Między tobą a mną kategoryczne twierdzenia dotyczące języków naturalnych są zwykle niebezpieczne.
AakashM