web-dev-qa-db-fra.com

SQL "entre" non inclus

J'ai une requête comme celle-ci:

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

Mais cela ne donne aucun résultat même s'il y a des données sur le 1er.

created_at ressemble à 2013-05-01 22:25:19, je suppose que cela a à voir avec le temps? Comment cela pourrait-il être résolu?

Cela fonctionne très bien si je fais de plus grandes plages de dates, mais cela devrait également fonctionner avec une seule date.

100
JBurace

Il est inclusif. Vous comparez les dates/heures. La deuxième date est interprétée comme minuit quand le jour commence.

Une façon de résoudre ce problème est:

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

Une autre façon de résoudre le problème est d'utiliser des comparaisons binaires explicites.

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

Aaron Bertrand a une longue entrée de blog sur les dates ( ici ), où il discute de cette question et d’autres questions relatives aux dates.

226
Gordon Linoff

Il a été supposé que la seconde référence de date dans la syntaxe BETWEEN est considérée comme par magie comme étant la "fin de journée" mais c'est faux .

c'est-à-dire que c'était prévu:

 SELECT * FROM Cases 
 WHERE created_at BETWEEN le début de  '2013-05-01' ET la fin de '2013-05-01'

mais ce qui se passe réellement est le suivant:

 SELECT * FROM Cases 
 WHERE created_at ENTRE '2013-05-01 00: 00: 00 + 00000'AND' 2013-05-01 00: 00: 00 + 00000'

Ce qui devient l'équivalent de:

 SELECT * FROM Cas WHERE created_at =  '2013-05-01 00: 00: 00 + 00000'

Le problème est celui des perceptions/attentes à propos de BETWEEN qui inclut inclut à la fois la valeur inférieure et les valeurs supérieures dans la plage, mais ne fait pas comme par magie une date le "début" ou "la fin de ".

BETWEEN doit être évité lors du filtrage par plages de dates.

Toujours utilise plutôt le >= AND < 

 SELECT * FROM Cases 
 WHERE (created_at > =  '20130501' ET  créé à <  '20130502')

les parenthèses sont facultatives ici mais peuvent être importantes dans les requêtes plus complexes.

31
Used_By_Already

Vous devez faire l'une de ces deux options:

  1. Incluez la composante heure dans votre condition between: ... where created_at between '2013-05-01 00:00:00' and '2013-05-01 23:59:59' (non recommandé ... voir le dernier paragraphe)
  2. Utilisez des inégalités au lieu de between. Notez que vous devrez ensuite ajouter un jour à la seconde valeur: ... where (created_at >= '2013-05-01' and created_at < '2013-05-02')

Ma préférence personnelle est la deuxième option. En outre, Aaron Bertrand a une explication très claire pourquoi il devrait être utilisé.

13
Barranka

Je trouve que la meilleure solution pour comparer un champ date/heure à un champ date est la suivante:

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 

Cela équivaut à une instruction inclusive, car elle inclut à la fois les dates de début et de fin, ainsi que celles comprises entre.

4
Ted

Il suffit d'utiliser l'horodatage comme date:

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

Cela ne fonctionnera qu'en 2008 et les versions plus récentes de SQL Server

Si vous utilisez une version plus ancienne, utilisez 

convert(varchar, created_at, 101)
0
Ali Adravi

Vous pouvez utiliser la fonction date() qui extraira la date d'un datetime et vous donnera le résultat comme date inclusive:

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