Enthält das "Zwischen" von MS SQL Server die Bereichsgrenzen?


234

Zum Beispiel kann

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

Wählen Sie 5 und 10 oder sind sie aus dem Bereich ausgeschlossen?

Antworten:


258

Der ZWISCHEN Betreiber ist inklusive.

Aus Online-Büchern:

BETWEEN gibt TRUE zurück, wenn der Wert von test_expression größer oder gleich dem Wert von begin_expression und kleiner oder gleich dem Wert von end_expression ist.

DateTime-Einschränkung

NB: Bei DateTimes müssen Sie vorsichtig sein. Wenn nur ein Datum angegeben ist, wird der Wert ab Mitternacht an diesem Tag angenommen. Um zu vermeiden, dass Zeiten innerhalb Ihres Enddatums fehlen oder die Erfassung der Daten des folgenden Tages um Mitternacht in mehreren Bereichen wiederholt wird, sollte Ihr Enddatum 3 Millisekunden vor Mitternacht des Tages liegen, der auf Ihr bisheriges Datum folgt. 3 Millisekunden, da weniger als dieser Wert und der Wert am nächsten Tag auf Mitternacht aufgerundet werden.

Um beispielsweise alle Werte innerhalb von Juni 2016 zu erhalten, müssen Sie Folgendes ausführen:

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

dh

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

datetime2 und datetimeoffset

Wenn Sie 3 ms von einem Datum abziehen, sind Sie anfällig für fehlende Zeilen im 3 ms-Fenster. Die richtige Lösung ist auch die einfachste:

where myDateTime >= '20160601' AND myDateTime < '20160701'

11
Wenn Sie BETWEEN verwenden, um DateTimes zwischen zwei Datumsangaben zu filtern, können Sie die DateTime auch in ein Datum umwandeln, z. B.: Wobei CONVERT (DATE, MyDate) ZWISCHEN '2017-09-01' und '2017-09-30' Element der DateTime irrelevant
Pete

1
Versuchen Sie nicht, 3 ms von einem Datum zu subtrahieren. Sie werden Gegenstände aus diesen 3 ms vermissen. Und Sie auch nicht wollen , zu CONVERTeinem Datetime zu einem Zeitpunkt , als die Indizes unbrauchbar machen wird. Verwenden Sie den Standard WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Stellen Sie außerdem sicher, dass Sie verwenden yyyymmdd, da dies vom yyyy-mm-ddGebietsschema abhängig ist und abhängig von den mdy, dmy, ymd, ydm, myd, and dymEinstellungen Ihres Servers falsch interpretiert wird .
Ian Boyd

254

Ja, aber seien Sie vorsichtig, wenn Sie zwischen Daten verwenden.

BETWEEN '20090101' AND '20090131'

wird wirklich als 12 Uhr interpretiert, oder

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

Ich werde also alles verpassen, was am Tag des 31. Januar passiert ist. In diesem Fall müssen Sie Folgendes verwenden:

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

oder

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

UPDATE : Es ist durchaus möglich, dass Datensätze innerhalb der letzten Sekunde des Tages erstellt werden, mit einer Datums- und Uhrzeitangabe bis 20090101 23:59:59.997!!

Aus diesem Grund wird der BETWEEN (firstday) AND (lastday 23:59:59)Ansatz nicht empfohlen.

Verwenden Sie myDate >= (firstday) AND myDate < (Lastday+1)stattdessen den Ansatz.

Guter Artikel zu diesem Thema hier .


1
Ähnliche Probleme mit Zeichenfolgen schließen beispielsweise auch WHERE col BETWEEN 'a' AND 'z'die meisten z-Zeilen aus.
Martin Smith

8
Dieser Punkt ist natürlich richtig; sollte aber nicht überraschen, wenn Sie mit datetimes arbeiten. Es ist analog zu dem Hinweis, dass BETWEEN 5 AND 10nicht enthalten 10.2...
Andrzej Doyle

4
CASTing der datetimeals ein DATEfunktionieren würde: CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
Craig

2
@craig, das stimmt, solange Sie SQL 2008 oder höher verwenden, als der Datentyp Datum eingeführt wurde. Außerdem konvertiert diese Syntax diesen Wert für jede einzelne Zeile, sodass keine Indizes für dieses Feld verwendet werden können (wenn dies ein Problem darstellt).
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<- Könnten Sie nicht gerade dann verwenden AND '01/31/2009 23:59:59.99999999'oder wie viele Neuner erforderlich sind
Wal

16

Beispiel aus der realen Welt von SQL Server 2008.

Quelldaten:

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

Abfrage:

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

Ergebnisse:

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

Alt-Text


Ich habe deine Antwort nicht bekommen, um ehrlich zu sein. Vielleicht hat mein Internetprovider Ihren Screenshot versteckt, wenn Sie einen gepostet haben.
Anar Khalilov

2
Warum ist die Zeile mit ID = 3ausgeschlossen? Sein StartWert entspricht dem Wert der BETWEENoberen Grenze und BETWEENist ein inklusiver Bereich, kein exklusiver oberer Bereich.
Dai

Besser mit Ergebnissen antworten.
Sam

13

Wenn Sie dies treffen und nicht wirklich versuchen möchten, einen Tag im Code hinzuzufügen, lassen Sie die DB dies tun.

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

Wenn Sie den Zeitanteil angeben: Stellen Sie sicher, dass er auf Mitternacht verweist. Ansonsten können Sie einfach die Zeit weglassen:

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

und mach dir keine Sorgen.


12

ZWISCHEN (Transact-SQL)

Gibt einen ( n ) ( einschließlich ) Bereich zum Testen an.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

Argumente

test_expression

Ist der zu testende Ausdruck in dem Bereich, der durch begin_expression und end_expression definiert ist. test_expression muss vom gleichen Datentyp sein wie begin_expression und end_expression.

NOT

Gibt an, dass das Ergebnis des Prädikats negiert werden soll.

begin_expression

Ist ein gültiger Ausdruck. begin_expression muss der gleiche Datentyp sein wie test_expression und end_expression.

end_expression

Ist ein gültiger Ausdruck. end_expression muss der gleiche Datentyp sein wie test_expression und begin_expression.

AND

Dient als Platzhalter, der angibt, dass test_expression innerhalb des durch begin_expression und end_expression angegebenen Bereichs liegen sollte.

Bemerkungen

Verwenden Sie zum Angeben eines exklusiven Bereichs die Operatoren größer als (>) und kleiner als (<). Wenn eine Eingabe in das Prädikat BETWEEN oder NOT BETWEEN NULL ist, ist das Ergebnis UNBEKANNT.

Ergebniswert

BETWEEN gibt TRUE zurück, wenn der Wert von test_expression größer oder gleich dem Wert von begin_expression und kleiner oder gleich dem Wert von end_expression ist.

NOT BETWEEN gibt TRUE zurück, wenn der Wert von test_expression kleiner als der Wert von begin_expression oder größer als der Wert von end_expression ist.


3

Wenn der Spaltendatentyp datetime ist, können Sie dies wie folgt tun, um die Zeit von datetime zu entfernen und nur zwischen Datumsbereichen zu vergleichen.

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)

Dies funktioniert besser als das Hinzufügen von +1 zum Enddatum. Ich stimme Andrew Morton zu - wenn es nicht sargable ist, kann es die Leistung verbessern, den Spaltendatentyp zu ändern oder eine zweite Spalte nur mit vorberechneten Daten hinzuzufügen.
Arno Peters

0

Es enthält Grenzen.

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

-3

Ich habe das immer benutzt:

WO myDate ZWISCHEN startDate UND (endDate + 1)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.