web-dev-qa-db-de.com

SQL "zwischen" nicht inklusive

Ich habe eine Frage wie diese:

SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'

Dies liefert jedoch keine Ergebnisse, obwohl Daten für den 1. Platz vorliegen.

created_at sieht aus wie 2013-05-01 22:25:19, ich vermute, es hat mit der Zeit zu tun? Wie konnte das gelöst werden?

Es funktioniert gut, wenn ich größere Datumsbereiche mache, aber es sollte (inklusive) auch mit einem einzigen Datum funktionieren.

100
JBurace

Es ist inklusive. Sie vergleichen Datumsangaben mit Datumsangaben. Das zweite Datum wird als Mitternacht interpretiert wenn der Tag beginnt.

Eine Möglichkeit, dies zu beheben, ist:

SELECT *
FROM Cases
WHERE cast(created_at as date) BETWEEN '2013-05-01' AND '2013-05-01'

Eine andere Möglichkeit, dies zu beheben, besteht in expliziten binären Vergleichen

SELECT *
FROM Cases
WHERE created_at >= '2013-05-01' AND created_at < '2013-05-02'

Aaron Bertrand hat einen langen Blogeintrag zu Terminen ( hier ), in dem er diese und andere Termine behandelt.

226
Gordon Linoff

Es wurde angenommen, dass die zweite Datumsreferenz in der BETWEEN-Syntax magisch als "Ende des Tages" betrachtet wird, aber dies ist nicht wahr.

das war erwartet worden:

 SELECT * FROM-Fälle 
 WO erstellt_at ZWISCHEN der Anfang von  "2013-05-01" UND das Ende von '2013-05-01'

was aber wirklich passiert ist folgendes:

 SELECT * FROM-Fälle 
 WO wurde zwischen 2013-05-01 erstellt 00: 00: 00 + 00000'UND' 2013-05-01 00: 00: 00 + 00000'

Welches wird das Äquivalent von:

 SELECT * FROM-Fälle, in denen WHERE_AT =  '2013-05-01 00: 00: 00 + 00000'

Das Problem ist eine der Wahrnehmungen/Erwartungen bezüglich BETWEEN, wobei do sowohl den unteren Wert als auch die oberen Werte des Bereichs enthält, aber nicht ein Datum magisch als "Anfang" oder "das Ende von".

BETWEEN sollte beim Filtern nach Datumsbereichen vermieden werden.

Immer stattdessen >= AND < verwenden 

 SELECT * FROM-Fälle 
 WHERE (Created_at > =  '20130501' UND  hergestellt in <  '20130502')

die Klammern sind hier optional, können jedoch bei komplexeren Abfragen wichtig sein.

31
Used_By_Already

Sie müssen eine der beiden folgenden Optionen ausführen:

  1. Fügen Sie die Zeitkomponente in Ihre between-Bedingung ein: ... where created_at between '2013-05-01 00:00:00' and '2013-05-01 23:59:59' (nicht empfohlen ... siehe letzten Absatz)
  2. Verwenden Sie Ungleichungen anstelle von between. Beachten Sie, dass Sie dem zweiten Wert dann einen Tag hinzufügen müssen: ... where (created_at >= '2013-05-01' and created_at < '2013-05-02')

Meine persönliche Präferenz ist die zweite Option. Aaron Bertrand hat eine sehr klare Erklärung warum es verwendet werden sollte.

13
Barranka

Ich finde, dass die beste Lösung zum Vergleichen eines datetime-Feldes mit einem Datumsfeld die folgende ist:

DECLARE @StartDate DATE = '5/1/2013', 
        @EndDate   DATE = '5/1/2013' 

SELECT * 
FROM   cases 
WHERE  Datediff(day, created_at, @StartDate) <= 0 
       AND Datediff(day, created_at, @EndDate) >= 0 

Dies ist gleichbedeutend mit einer inklusiven Anweisung zwischen den Anweisungen, da sowohl das Start- und Enddatum als auch die dazwischen liegenden enthalten sind.

4
Ted

Verwenden Sie einfach den Zeitstempel als Datum:

SELECT * FROM Cases WHERE date(created_at)='2013-05-01' 
4
Balinti
cast(created_at as date)

Das funktioniert nur in 2008 und neueren Versionen von SQL Server

Wenn Sie eine ältere Version verwenden, verwenden Sie 

convert(varchar, created_at, 101)
0
Ali Adravi

Sie können die Funktion date() verwenden, die das Datum aus einer Datumszeit extrahiert und das Ergebnis als Inklusivdatum ausgibt:

SELECT * FROM Cases WHERE date(created_at)='2013-05-01' AND '2013-05-01'
0
abhishek kumar