«Entre» de MS SQL Server inclut-il les limites de la plage?

234

Par exemple, peut

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

sélectionnez 5 et 10 ou ils sont exclus de la gamme?

Léa Verou
la source

Réponses:

258

L'opérateur BETWEEN est inclusif.

De Livres en ligne:

BETWEEN renvoie TRUE si la valeur de test_expression est supérieure ou égale à la valeur de begin_expression et inférieure ou égale à la valeur de end_expression.

DateTime Caveat

NB: Avec DateTimes il faut faire attention; si seule une date est donnée, la valeur est prise à minuit ce jour-là; pour éviter de manquer des heures dans votre date de fin ou de répéter la capture des données du jour suivant à minuit dans plusieurs plages, votre date de fin doit être de 3 millisecondes avant minuit le jour suivant votre date de fin. 3 millisecondes car moins que cela et la valeur sera arrondie à minuit le lendemain.

Par exemple, pour obtenir toutes les valeurs en juin 2016, vous devez exécuter:

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

c'est à dire

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

datetime2 et datetimeoffset

Soustraire 3 ms d'une date vous rendra vulnérable aux lignes manquantes de la fenêtre de 3 ms. La bonne solution est également la plus simple:

where myDateTime >= '20160601' AND myDateTime < '20160701'
DJ.
la source
11
Lorsque vous utilisez BETWEEN pour filtrer les DateTimes entre deux dates, vous pouvez également convertir le DateTime en une date, par exemple: où CONVERT (DATE, MyDate) BETWEEN '2017-09-01' et '2017-09-30' Cette approche rend l'heure élément du DateTime non pertinent
Pete
1
Assurez-vous de ne pas essayer de soustraire 3 ms d'une date; vous allez manquer des éléments de ces 3 ms. Et vous ne voulez pas non plus d' CONVERTun datetime à une date , car cela rendra les index inutiles. Utilisez la norme WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Assurez-vous également de l'utiliser yyyymmdd, car cela yyyy-mm-dddépend des paramètres régionaux, et sera mal interprété en fonction des mdy, dmy, ymd, ydm, myd, and dymparamètres de votre serveur .
Ian Boyd
254

Oui, mais soyez prudent lorsque vous utilisez entre les dates.

BETWEEN '20090101' AND '20090131'

est vraiment interprété comme 12h, ou

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

manquera donc tout ce qui s'est passé pendant la journée du 31 janvier. Dans ce cas, vous devrez utiliser:

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

ou

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

MISE À JOUR : Il est tout à fait possible d'avoir des enregistrements créés dans cette dernière seconde de la journée, avec une date et l'heure aussi tard que 20090101 23:59:59.997!!

Pour cette raison, l' BETWEEN (firstday) AND (lastday 23:59:59)approche n'est pas recommandée.

Utilisez myDate >= (firstday) AND myDate < (Lastday+1)plutôt l' approche.

Bon article sur cette question ici .

BradC
la source
1
Des problèmes similaires avec les chaînes WHERE col BETWEEN 'a' AND 'z'excluront également la plupart des lignes z par exemple.
Martin Smith
8
Ce point est bien sûr exact; mais cela ne devrait pas être surprenant si vous travaillez avec des horaires. C'est analogue à souligner que cela BETWEEN 5 AND 10n'inclut pas 10.2...
Andrzej Doyle
4
CASTing la datetimecomme DATEtravaillerait: CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
craig
2
@craig, c'est vrai, tant que vous utilisez SQL 2008 ou une version ultérieure, c'est-à-dire lorsque le type de données Date a été introduit. De plus, cette syntaxe convertira cette valeur pour chaque ligne, donc elle ne pourra pas utiliser d'index sur ce champ (si c'est un problème).
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<- ne pourriez-vous pas utiliser à ce moment-là AND '01/31/2009 23:59:59.99999999'ou autant de 9 sont nécessaires
wal
16

Exemple du monde réel de SQL Server 2008.

Données source:

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

Requete:

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

Résultats:

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

texte alternatif

Ryan Rodemoyer
la source
Je n'ai pas obtenu votre réponse, pour être honnête. Peut-être que mon fournisseur d'accès Internet a masqué votre capture d'écran si vous en avez publié une.
anar khalilov
2
Pourquoi la ligne avec ID = 3exclu? Sa Startvaleur est égale à la BETWEENvaleur de la limite supérieure et BETWEENest une plage inclusive, pas une plage supérieure exclusive.
Dai
Meilleure réponse avec des résultats.
Sam
13

si vous frappez ceci et que vous ne voulez pas vraiment essayer d'ajouter un jour dans le code, laissez la DB le faire.

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

Si vous incluez la partie heure: assurez-vous qu'elle fait référence à minuit. Sinon, vous pouvez simplement omettre l'heure:

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

et ne vous en faites pas.

Shaun
la source
12

ENTRE (Transact-SQL)

Spécifie une plage ( n ) ( inclusive ) à tester.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

Arguments

test_expression

Expression à tester dans la plage définie par begin_expression et end_expression. test_expression doit être du même type de données que begin_expression et end_expression.

NOT

Spécifie que le résultat du prédicat doit être annulé.

begin_expression

Est une expression valide. begin_expression doit être du même type de données que test_expression et end_expression.

end_expression

Est une expression valide. expression_fin doit être du même type de données que expression_test et expression_début.

AND

Agit comme un espace réservé qui indique que test_expression doit être dans la plage indiquée par begin_expression et end_expression.

Remarques

Pour spécifier une plage exclusive, utilisez les opérateurs supérieur à (>) et inférieur à (<). Si une entrée du prédicat BETWEEN ou NOT BETWEEN est NULL, le résultat est UNKNOWN.

Valeur du résultat

BETWEEN renvoie TRUE si la valeur de test_expression est supérieure ou égale à la valeur de begin_expression et inférieure ou égale à la valeur de end_expression.

NOT BETWEEN renvoie TRUE si la valeur de test_expression est inférieure à la valeur de begin_expression ou supérieure à la valeur de end_expression.

Russ Cam
la source
3

Si le type de données de la colonne est datetime, vous pouvez procéder comme suit pour éliminer l'heure de datetime et comparer uniquement la plage de dates.

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)
Kahlil Vanz
la source
Cela fonctionne mieux que d'ajouter +1 à la date de fin. Je suis d'accord avec Andrew Morton - s'il n'est pas discutable, il peut améliorer les performances pour changer le type de données de la colonne ou ajouter une deuxième colonne avec des dates précalculées uniquement.
Arno Peters
0

Cela inclut les limites.

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
la source
-3

Je l'ai toujours utilisé:

O my ma date entre la date de début ET (date de fin + 1)

user2296528
la source