Czy „pomiędzy” MS SQL Server zawiera granice zakresu?

234

Na przykład może

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

wybrać 5 i 10 czy są one wykluczone z zakresu?

Lea Verou
źródło

Odpowiedzi:

258

Operator BETWEEN obejmuje.

Z książek online:

BETWEEN zwraca PRAWDA, jeśli wartość wyrażenia testowego jest większa lub równa wartości wyrażenia początkowego i mniejsza lub równa wartości wyrażenia końcowego.

Zastrzeżenie dotyczące DateTime

NB: Z DateTimes musisz być ostrożny; jeżeli podano tylko datę, wartość przyjmuje się od północy tego dnia; aby uniknąć brakujących czasów w dacie końcowej lub powtarzania przechwytywania danych następnego dnia o północy w wielu zakresach, data końcowa powinna wynosić 3 milisekundy przed północą następnego dnia po dacie. 3 milisekundy, ponieważ mniej niż to, a wartość zostanie zaokrąglona w górę do północy następnego dnia.

np. aby uzyskać wszystkie wartości w czerwcu 2016 r., musisz uruchomić:

where myDateTime between '20160601' and DATEADD(millisecond, -3, '20160701')

to znaczy

where myDateTime between '20160601 00:00:00.000' and '20160630 23:59:59.997'

datetime2 i datetimeoffset

Odjęcie 3 ms od daty spowoduje, że będziesz narażony na brakujące wiersze w oknie 3 ms. Prawidłowe rozwiązanie jest również najprostsze:

where myDateTime >= '20160601' AND myDateTime < '20160701'
DJ.
źródło
11
Korzystając z opcji BETWEEN do filtrowania DateTimes między dwiema datami, możesz także przesyłać DateTime na Date, np .: gdzie CONVERT (DATE, MyDate) MIĘDZY „2017-09-01” a „2017-09-30” To podejście pozwala określić czas element DateTime nie ma znaczenia
Pete
1
Pamiętaj, aby nie próbować odejmować 3 ms od daty; przegapisz przedmioty z tych 3 ms. I ty też nie chcą CONVERTsię datetime do daty , jako że odda indeksy bezużyteczne. Użyj standardu WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Pamiętaj też, aby użyć yyyymmdd, ponieważ yyyy-mm-ddjest zależne od ustawień regionalnych i będzie źle interpretowane w zależności od ustawień twojego serwera mdy, dmy, ymd, ydm, myd, and dym.
Ian Boyd,
254

Tak, ale zachowaj ostrożność, używając między datami.

BETWEEN '20090101' AND '20090131'

jest naprawdę interpretowane jako 12 rano lub

BETWEEN '20090101 00:00:00' AND '20090131 00:00:00'

więc przegapi wszystko, co wydarzyło się w dniu 31 stycznia. W takim przypadku będziesz musiał użyć:

myDate >= '20090101 00:00:00' AND myDate < '20090201 00:00:00'  --CORRECT!

lub

BETWEEN '20090101 00:00:00' AND '20090131 23:59:59' --WRONG! (see update!)

AKTUALIZACJA : Całkowicie możliwe jest utworzenie rekordów w ostatniej sekundzie dnia, z datetime nawet do 20090101 23:59:59.997!!

Z tego powodu BETWEEN (firstday) AND (lastday 23:59:59)podejście nie jest zalecane.

Użyj myDate >= (firstday) AND myDate < (Lastday+1)podejście zamiast.

Dobry artykuł na ten temat tutaj .

BradC
źródło
1
Podobne problemy z łańcuchami również WHERE col BETWEEN 'a' AND 'z'wykluczą na przykład większość wierszy.
Martin Smith
8
Ten punkt jest oczywiście słuszny; ale nie powinno być zaskoczeniem, jeśli pracujesz z czasem danych. Jest to analogiczne do wskazania, że BETWEEN 5 AND 10nie obejmuje 10.2...
Andrzej Doyle
4
CASTing datetimejak DATEto działa: CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
craig
2
@craig, to prawda, o ile używasz SQL 2008 lub nowszego, czyli wtedy, gdy wprowadzono typ danych Data. Ponadto ta składnia konwertuje tę wartość dla każdego wiersza, więc nie będzie można używać indeksów w tym polu (jeśli jest to problem).
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<- nie mógłbyś wtedy użyć AND '01/31/2009 23:59:59.99999999'lub jak wiele 9 jest wymaganych
wal
16

Przykład świata rzeczywistego z SQL Server 2008.

Dane źródłowe:

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

Pytanie:

SELECT
    *
FROM
    tbl
WHERE
    Start BETWEEN '2010-04-01 00:00:00' AND '2010-05-01 00:00:00'

Wyniki:

ID    Start
1     2010-04-30 00:00:01.000
2     2010-04-02 00:00:00.000

alternatywny tekst

Ryan Rodemoyer
źródło
Szczerze mówiąc, nie dostałem twojej odpowiedzi. Być może mój dostawca Internetu ukrył zrzut ekranu, jeśli go opublikowałeś.
anar khalilov
2
Dlaczego wiersz jest ID = 3wykluczony? Jego Startwartość jest równa BETWEENgórnej wartości granicznej i BETWEENjest zakresem obejmującym, a nie wyłącznym zakresem górnym.
Dai,
Lepsza odpowiedź z wynikami.
Sam
13

jeśli trafisz w to i tak naprawdę nie chcesz próbować poradzić sobie z dodawaniem dnia w kodzie, pozwól DB to zrobić ...

myDate >= '20090101 00:00:00' AND myDate < DATEADD(day,1,'20090101 00:00:00')

Jeśli uwzględnisz przedział czasu: upewnij się, że odnosi się on do północy. W przeciwnym razie możesz po prostu pominąć czas:

myDate >= '20090101' AND myDate < DATEADD(day,1,'20090101')

i nie martw się o to.

Shaun
źródło
12

MIĘDZY (Transact-SQL)

Określa ( n ) ( włącznie ) zakres do przetestowania.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

Argumenty

test_expression

Jest to wyrażenie do przetestowania w zakresie zdefiniowanym przez wyrażenie_początkowe i wyrażenie_końcowe. wyrażenie_wyrażeniowe musi być tego samego typu danych co wyrażenie początkowe i wyrażenie końcowe.

NOT

Określa, że ​​wynik predykatu będzie zanegowany.

begin_expression

Jest dowolnym prawidłowym wyrażeniem. wyrażenie_początkowe musi być tego samego typu, co wyrażenie_wyrażeniowe test i wyrażenie końcowe.

end_expression

Jest dowolnym prawidłowym wyrażeniem. wyrażenie_końcowe musi mieć ten sam typ danych, co wyrażenie_wyrażeniowe i początkowe.

AND

Działa jako symbol zastępczy wskazujący, że wyrażenie_testowe powinno znajdować się w zakresie wskazanym przez wyrażenie_początkowe i wyrażenie_końcowe.

Uwagi

Aby określić zakres wyłączności, użyj wartości większej niż (>) i mniejszej niż operatory (<). Jeśli jakiekolwiek dane wejściowe do predykatu MIĘDZY lub NIE MIĘDZY są predykatem NULL, wynik jest NIEZNANY.

Wartość wyniku

BETWEEN zwraca PRAWDA, jeśli wartość wyrażenia testowego jest większa lub równa wartości wyrażenia początkowego i mniejsza lub równa wartości wyrażenia końcowego.

NOT BETWEEN zwraca PRAWDA, jeśli wartość wyrażenia testowego jest mniejsza niż wartość wyrażenia początkowego lub większa niż wartość wyrażenia końcowego.

Russ Cam
źródło
3

Jeśli typem danych kolumny jest data / godzina, możesz to zrobić w następujący sposób, aby wyeliminować czas z godziny i porównać tylko zakres dat.

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)
Kahlil Vanz
źródło
Działa to lepiej niż dodanie +1 do daty zakończenia. Zgadzam się z Andrew Mortonem - jeśli nie jest wymienny, może poprawić wydajność, zmienić typ danych kolumny lub dodać drugą kolumnę tylko z wcześniej obliczonymi datami.
Arno Peters
0

Obejmuje granice.

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
Halim
źródło
-3

Zawsze używałem tego:

GDZIE moja data MIĘDZY datą początkową ORAZ (data końcowa + 1)

użytkownik2296528
źródło