SQL: BETWEEN vs <= et> =

111

Dans SQL Server 2000 et 2005:

  • quelle est la différence entre ces deux WHEREclauses?
  • lequel dois-je utiliser dans quels scénarios?

Requête 1:

SELECT EventId, EventName
FROM EventMaster
WHERE EventDate BETWEEN '10/15/2009' AND '10/18/2009'

Requête 2:

SELECT EventId, EventName
FROM EventMaster
WHERE EventDate >='10/15/2009'
  AND EventDate <='10/18/2009'

(Modifier: la deuxième date de l'événement manquait à l'origine, donc la requête était syntaxiquement incorrecte)

Shyju
la source
1
Ceci est un quasi-double avec stackoverflow.com/questions/1572840/sql-between-v1-and-v2
mjv
6
pas vraiment, la gestion de datetime est légèrement différente, en plus c'était pour SQL Server 2008, et il n'y a aucun moyen que Shyju puisse être certain sans demander que la réponse serait la même pour les versions précédentes.
Irfy

Réponses:

119

Ils sont identiques: BETWEENc'est un raccourci pour la syntaxe plus longue de la question.

Utilisez une autre syntaxe plus longue là où BETWEENne fonctionne pas, par exemple

Select EventId,EventName from EventMaster
where EventDate >= '10/15/2009' and EventDate < '10/18/2009'

(Notez <plutôt qu'en <=deuxième condition.)

Tony Andrews
la source
19
Peut-être devriez-vous insister sur le fait que la deuxième condition est «<». Il m'a fallu un certain temps pour repérer la différence.
zendar
21
J'ajouterais que je recommande fortement de ne jamais utiliser BETWEEN sauf si vous traitez avec le type de données DATE ou que vous ayez autrement garanti que vos valeurs datetime n'auront jamais de composante temporelle. Être cohérent à ce sujet réduira la probabilité que vous utilisiez BETWEEN par erreur au lieu de> = et <, et que vous obteniez des données dans la requête que vous ne vouliez pas, ou que vous pensiez que vous receviez un jour supplémentaire de données quand vous n'êtes pas ...
Aaron Bertrand
1
Y aurait-il une deuxième étape du compilateur lorsque BETWEEN est converti en conditions? Je comprends que c'est un peu pédant, mais y aurait-il des frais généraux supplémentaires?
James Scott
1
@xmashallax parce qu'ils le sont? Comment sont-ils pas?
Tony Andrews
2
Etrange ... Je pense que j'ai été confus par la question, l'écriture de la réponse, les commentaires et le fait que mon code a évidemment un bogue maintenant =)
xmashallax
37

Ce sont les mêmes.

Une chose à laquelle il faut faire attention, c'est que si vous l'utilisez avec un DATETIME, la correspondance pour la date de fin sera le début de la journée:

<= 20/10/2009

n'est pas la même chose que:

<= 20/10/2009 23:59:59

(il serait match contre <= 20/10/2009 00:00:00.000)

Irfy
la source
Vous pouvez simplement utiliser entre '2009-10-20' et '2009-10-21' dans ce cas pour capturer la journée
David Andrei Ned
4
@DavidAndreiNed qui correspondrait également à «2009-10-21 00: 00: 00.000» - probablement pas ce que vous voulez.
Hans Ke st ing
2
Vous voudriez le champ BETWEEN '2009-10-20 00:00:00' ET '2009-10-20 23:59:59' ou le champ> = '2009-10-20 00:00:00' ET le champ <= «2009-10-20 23:59:59» pour être absolument certain.
geilt
@geilt Vos exemples manqueraient tout ce qui s'est passé dans la dernière seconde de la journée ... c'est-à-dire entre 23:59:59 et 00:00:00 le jour suivant.
Seth Flowers
00:00:00 est le début du jour suivant et pourquoi j'utilise> = et <= et non> ou <. Mais si vous vouliez dire des microsecondes et que vous les stockez, vous voudrez également mettre la dernière et dernière microseconde.
geilt
14

Bien qu'il BETWEENsoit facile à lire et à maintenir, je recommande rarement son utilisation car il s'agit d'un intervalle fermé et, comme mentionné précédemment, cela peut être un problème avec les dates - même sans composants de temps.

Par exemple, lorsqu'il s'agit de données mensuelles, il est souvent courant de comparer les dates BETWEEN first AND last, mais en pratique, cela est généralement plus facile à écrire dt >= first AND dt < next-first(ce qui résout également le problème de la partie de temps) - car la détermination lastest généralement une étape de plus que la déterminationnext-first (en soustrayant un jour) .

De plus, un autre problème est que les limites inférieure et supérieure doivent être spécifiées dans le bon ordre (c'est-à-dire BETWEEN low AND high).

Cade Roux
la source
4

En règle générale, il n'y a pas de différence - le BETWEENmot-clé n'est pas pris en charge sur toutes les plates-formes SGBDR, mais si tel est le cas, les deux requêtes doivent être identiques.

Puisqu'ils sont identiques, il n'y a vraiment aucune distinction en termes de vitesse ou quoi que ce soit d'autre - utilisez celui qui vous semble le plus naturel.

marc_s
la source
4

Comme mentionné par @marc_s, @Cloud, et al. ils sont fondamentalement les mêmes pour une plage fermée.

Mais toute valeur de temps fractionnaire peut entraîner des problèmes avec une plage fermée (supérieure ou égale et inférieure ou égale ) par opposition à une plage semi-ouverte (supérieure ou égale et inférieure à ) avec une valeur de fin après le dernier instant possible.

Donc, pour éviter que la requête ne soit réécrite comme:

SELECT EventId, EventName
  FROM EventMaster
 WHERE (EventDate >= '2009-10-15' AND
        EventDate <  '2009-10-19')    /* <<<== 19th, not 18th */

Comme BETWEENne fonctionne pas pour les intervalles semi-ouverts, je regarde toujours attentivement toute requête de date / heure qui l'utilise, car c'est probablement une erreur.

devstuff
la source
4

J'ai une légère préférence pour BETWEENcar cela indique instantanément au lecteur que vous vérifiez un champ pour une plage . Cela est particulièrement vrai si vous avez des noms de champ similaires dans votre table.

Si, par exemple, notre tableau a à la fois un transactiondateet un transitiondate, si je lis

transactiondate between ...

Je sais immédiatement que les deux extrémités du test sont contre ce seul champ.

Si je lis

transactiondate>='2009-04-17' and transactiondate<='2009-04-22'

Je dois prendre un moment supplémentaire pour m'assurer que les deux champs sont identiques.

De plus, lorsqu'une requête est modifiée au fil du temps, un programmeur bâclé peut séparer les deux champs. J'ai vu beaucoup de requêtes qui disent quelque chose comme

where transactiondate>='2009-04-17'
  and salestype='A'
  and customernumber=customer.idnumber
  and transactiondate<='2009-04-22'

S'ils essaient cela avec un BETWEEN, bien sûr, ce sera une erreur de syntaxe et rapidement corrigée.

Geai
la source
3

Je pense que la seule différence est la quantité de sucre syntaxique sur chaque requête. BETWEEN est juste une manière astucieuse de dire exactement la même chose que la deuxième requête.

Il peut y avoir une différence spécifique au SGBDR dont je ne suis pas conscient, mais je ne pense pas vraiment.

pyrocumulus
la source
2

Logiquement, il n'y a aucune différence. En termes de performances, il n'y a - généralement, sur la plupart des SGBD - aucune différence.

mjv
la source
2

Consultez cet excellent article de blog d' Aaron Bertrand expliquant pourquoi vous devriez changer le format de votre chaîne et comment les valeurs de limite sont gérées dans les requêtes de plage de dates.

Andy Jones
la source
1
Lien déplacé ici
João Ciocca
1

Avis de non-responsabilité: Tout ce qui suit n'est qu'anecdotique et tiré directement de mon expérience personnelle. Quiconque se sent prêt à mener une analyse empiriquement plus rigoureuse est le bienvenu pour la mener à bien et voter si je le suis. Je suis également conscient que SQL est un langage déclaratif et que vous n'êtes pas censé avoir à considérer COMMENT votre code est traité lorsque vous l'écrivez, mais, parce que j'apprécie mon temps, je le fais.

Il existe des instructions logiquement équivalentes infinies, mais j'en considérerai trois (ish).

Cas 1: deux comparaisons dans un ordre standard (ordre d'évaluation fixe)

A> = MinBound ET A <= MaxBound

Cas 2: Sucre syntaxique (l'ordre d'évaluation n'est pas choisi par l'auteur)

UN ENTRE MinBound ET MaxBound

Cas 3: Deux comparaisons dans un ordre éduqué (ordre d'évaluation choisi au moment de l'écriture)

A> = MinBound ET A <= MaxBound

Ou

A <= MaxBound AND A> = MinBound

D'après mon expérience, le cas 1 et le cas 2 n'ont pas de différences de performances cohérentes ou notables car ils ignorent l'ensemble de données.

Cependant, le cas 3 peut considérablement améliorer les temps d'exécution. Plus précisément, si vous travaillez avec un grand ensemble de données et que vous avez des connaissances heuristiques pour savoir si A est plus susceptible d'être supérieur à MaxBound ou inférieur à MinBound vous pouvez améliorer sensiblement les temps d'exécution en utilisant le cas 3 et en ordonnant les comparaisons. en conséquence.

Un cas d'utilisation que j'ai est l'interrogation d'un grand ensemble de données historiques avec des dates non indexées pour les enregistrements dans un intervalle spécifique. Lors de l'écriture de la requête, j'aurai une bonne idée de l'existence ou non de plus de données AVANT l'intervalle spécifié ou APRÈS l'intervalle spécifié et je pourrai ordonner mes comparaisons en conséquence. J'ai eu des temps d'exécution réduits de moitié en fonction de la taille de l'ensemble de données, de la complexité de la requête et du nombre d'enregistrements filtrés par la première comparaison.

LanchPad
la source
Euh, quoi? Le cas 3 ne partage pas la même logique que le cas 1 et le cas 2. Si vous voulez voir si Aest supérieur aux deux limites, vérifiez simplement si le Aest supérieur au MaxBound. Votre message a besoin d'être ajusté.
mickmackusa
On dirait que j'ai fait une faute de frappe sur les opérateurs d'égalité. Bonne prise.
LanchPad
0

Dans ce scénario col BETWEEN ... AND ...et col <= ... and col >= ...sont équivalents.


SQL Standard définit également le prédicat Symmetric BETWEEN T461 :

 <between predicate part 2> ::=
 [ NOT ] BETWEEN [ ASYMMETRIC | SYMMETRIC ]
 <row value predicand> AND <row value predicand>

Transact-SQL ne prend pas en charge cette fonctionnalité.

BETWEENexige que les valeurs soient triées. Par exemple:

SELECT 1 WHERE 3 BETWEEN 10 AND 1
-- no rows

<=>

SELECT 1 WHERE 3 >= 10 AND 3 <= 1
-- no rows

D'autre part:

SELECT 1 WHERE 3 BETWEEN SYMMETRIC 1 AND 10;
-- 1

SELECT 1 WHERE 3 BETWEEN SYMMETRIC 10 AND 1
-- 1

Cela fonctionne exactement comme d'habitude, BETWEENmais après avoir trié les valeurs de comparaison.

démo db <> fiddle

Lukasz Szozda
la source