SQL: BETWEEN vs <= e> =

111

No SQL Server 2000 e 2005:

  • qual é a diferença entre essas duas WHEREcláusulas?
  • qual devo usar em quais cenários?

Consulta 1:

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

Consulta 2:

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

(Editar: o segundo Eventdate estava ausente originalmente, então a consulta estava sintaticamente errada)

Shyju
fonte
1
Esta é uma quase duplicata com stackoverflow.com/questions/1572840/sql-between-v1-and-v2
mjv
6
não realmente, o tratamento de data e hora é um pouco diferente, além disso, era para o SQL server 2008, e não há como Shyju ter certeza sem perguntar se a resposta seria a mesma para as versões anteriores.
Irfy

Respostas:

119

Eles são idênticos: BETWEENé uma abreviatura para a sintaxe mais longa na questão.

Use uma sintaxe alternativa mais longa onde BETWEENnão funcionar, por exemplo

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

(Observe em <vez de <=na segunda condição.)

Tony Andrews
fonte
19
Talvez você deva enfatizar que a segunda condição é '<'. Levei algum tempo para perceber a diferença.
zendar
21
Eu acrescentaria que eu recomendo fortemente nunca usar BETWEEN, a menos que você esteja lidando com o tipo de dados DATE ou tenha garantido que seus valores de data e hora nunca terão um componente de tempo. Ser consistente sobre isso tornará menos provável que você use BETWEEN por engano em vez de> = e <, e obtenha alguns dados na consulta que você não pretendia, ou pense que está recebendo um dia adicional de dados quando você não está ...
Aaron Bertrand
1
Haveria uma segunda etapa do compilador quando BETWEEN fosse convertido em condicionais? Eu entendo que isso é um pouco pedante, mas haveria uma sobrecarga adicional?
James Scott
1
@xmashallax porque eles são? Como eles não estão?
Tony Andrews,
2
Estranho ... Acho que fiquei confuso com a pergunta, a redação da resposta, os comentários e o fato de que meu código obviamente tem um bug agora =)
xmashallax
37

Eles são os mesmos.

Deve-se ter cuidado: se você estiver usando isso em DATETIME, a correspondência para a data de término será o início do dia:

<= 20/10/2009

não é o mesmo que:

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

(ele iria corresponder contra <= 20/10/2009 00:00:00.000)

Irfy
fonte
Você pode simplesmente usar entre '2009-10-20' e '2009-10-21' nesse caso para capturar o dia
David Andrei Ned
4
@DavidAndreiNed que também corresponderia a '2009-10-21 00: 00: 00.000' - provavelmente não é o que você deseja.
Hans Ke st ing
2
Você deve querer o campo ENTRE '2009-10-20 00:00:00' E '2009-10-20 23:59:59' ou o campo> = '2009-10-20 00:00:00' E o campo <= '2009-10-20 23:59:59' para ter certeza absoluta.
geilt
@geilt Seus exemplos perderiam tudo o que ocorresse no último segundo do dia ... ou seja: entre 23:59:59 e 00:00:00 do dia seguinte.
Seth Flowers de
00:00:00 é o início do dia seguinte e por que eu uso> = e <= e não> ou <.Mas se você quis dizer microssegundos e os armazena, você deve colocar o último e o último microssegundo também.
geilt
14

Embora BETWEENseja fácil de ler e manter, raramente recomendo seu uso porque é um intervalo fechado e, como mencionado anteriormente, isso pode ser um problema com datas - mesmo sem componentes de tempo.

Por exemplo, ao lidar com dados mensais, muitas vezes é comum comparar datas BETWEEN first AND last, mas na prática isso geralmente é mais fácil de escrever dt >= first AND dt < next-first(o que também resolve o problema da parte do tempo) - uma vez que determinar lastgeralmente é um passo mais longo do que determinar next-first(subtraindo um dia) .

Além disso, outra pegadinha é que os limites inferior e superior precisam ser especificados na ordem correta (ou seja, BETWEEN low AND high).

Cade Roux
fonte
4

Normalmente, não há diferença - a BETWEENpalavra-chave não é suportada em todas as plataformas RDBMS, mas se for, as duas consultas devem ser idênticas.

Como eles são idênticos, não há realmente nenhuma distinção em termos de velocidade ou qualquer outra coisa - use aquele que parecer mais natural para você.

marc_s
fonte
4

Conforme mencionado por @marc_s, @Cloud, et al. eles são basicamente os mesmos para um intervalo fechado.

Mas quaisquer valores de tempo fracionário podem causar problemas com um intervalo fechado (maior ou igual e menor ou igual ) em oposição a um intervalo semiaberto (maior ou igual e menor que ) com um valor final após o último instante possível.

Portanto, para evitar que a consulta seja reescrita como:

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

Como BETWEENnão funciona para intervalos semiabertos, sempre analiso cuidadosamente qualquer consulta de data / hora que o utilize, pois provavelmente é um erro.

devstuff
fonte
4

Tenho uma ligeira preferência por BETWEENporque torna imediatamente claro para o leitor que você está verificando um campo para um intervalo . Isso é especialmente verdadeiro se você tiver nomes de campo semelhantes em sua tabela.

Se, digamos, nossa mesa tiver um transactiondatee um transitiondate, se eu ler

transactiondate between ...

Eu sei imediatamente que ambas as pontas do teste são contra esse campo.

Se eu ler

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

Preciso de um minuto extra para ter certeza de que os dois campos são iguais.

Além disso, à medida que uma consulta é editada ao longo do tempo, um programador desleixado pode separar os dois campos. Já vi muitas consultas que dizem algo como

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

Se eles tentarem fazer isso com um BETWEEN, é claro, será um erro de sintaxe e será corrigido imediatamente.

Jay
fonte
3

Acho que a única diferença é a quantidade de açúcar sintático em cada consulta. BETWEEN é apenas uma maneira inteligente de dizer exatamente o mesmo que a segunda consulta.

Pode haver alguma diferença específica de RDBMS da qual não estou ciente, mas realmente não acho.

pirocúmulo
fonte
2

Logicamente, não há diferença alguma. Em termos de desempenho, normalmente, na maioria dos SGBDs, não há diferença alguma.

mjv
fonte
2

Veja esta excelente postagem de Aaron Bertrand sobre por que você deve alterar o formato da string e como os valores limite são tratados em consultas de intervalo de datas.

Andy Jones
fonte
1
Link mudou-se para aqui
João Ciocca 22/06
1

Aviso Legal: Tudo abaixo é apenas anedótico e tirado diretamente de minha experiência pessoal. Qualquer pessoa que se sinta à vontade para conduzir uma análise empiricamente mais rigorosa é bem-vinda para realizá-la e votar contra, se eu for. Também estou ciente de que SQL é uma linguagem declarativa e você não deve considerar COMO seu código é processado ao escrevê-lo, mas, porque eu valorizo ​​meu tempo, eu sim.

Existem infinitas declarações logicamente equivalentes, mas considerarei três (ish).

Caso 1: duas comparações em uma ordem padrão (ordem de avaliação corrigida)

A> = MinBound AND A <= MaxBound

Caso 2: Açúcar sintático (a ordem de avaliação não é escolhida pelo autor)

A BETWEEN MinBound AND MaxBound

Caso 3: Duas comparações em uma ordem educada (ordem de avaliação escolhida no momento da escrita)

A> = MinBound AND A <= MaxBound

Ou

A <= MaxBound AND A> = MinBound

Na minha experiência, o Caso 1 e o Caso 2 não apresentam diferenças consistentes ou notáveis ​​no desempenho, pois ignoram o conjunto de dados.

No entanto, o Caso 3 pode melhorar muito os tempos de execução. Especificamente, se você estiver trabalhando com um grande conjunto de dados e tiver algum conhecimento heurístico sobre se A é mais provável que seja maior do que o MaxBound ou menor do que o MinBound, você pode melhorar os tempos de execução visivelmente usando o Caso 3 e ordenando as comparações adequadamente.

Um caso de uso que tenho é consultar um grande conjunto de dados históricos com datas não indexadas para registros dentro de um intervalo específico. Ao escrever a consulta, terei uma boa ideia se existem ou não mais dados ANTES do intervalo especificado ou DEPOIS do intervalo especificado e posso ordenar minhas comparações de acordo. Eu tive o tempo de execução reduzido pela metade, dependendo do tamanho do conjunto de dados, da complexidade da consulta e da quantidade de registros filtrados pela primeira comparação.

LanchPad
fonte
Hum, o que? O Caso 3 não compartilha a mesma lógica do Caso 1 e do Caso 2. Se você quiser ver se Aé maior do que ambos os limites, verifique se o Aé maior do que o MaxBound. Sua postagem precisa de alguns ajustes.
mickmackusa
Parece que cometi um erro de digitação nos operadores de igualdade. Boa pegada.
LanchPad de
0

Neste cenário col BETWEEN ... AND ...e col <= ... and col >= ...são equivalentes.


O SQL Standard define também o predicado T461 Symmetric BETWEEN :

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

O Transact-SQL não oferece suporte a esse recurso.

BETWEENrequer que os valores sejam classificados. Por exemplo:

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

<=>

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

Por outro lado:

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

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

Funciona exatamente como o normal, BETWEENmas após classificar os valores de comparação.

db <> demonstração de violino

Lukasz Szozda
fonte