SQL BETWEEN é um operador usado para especificar um intervalo de valores a serem testados. O valor retornado pode ser inclusivo ou dentro do intervalo. Ou pode estar fora do intervalo se você adicionar o operador NOT antes dele. Funciona para datas, datas com hora, números e strings.
Você pode usá-lo em cláusulas WHERE para o seguinte:
- SELECIONAR,
- INSERIR (com SELECIONAR)
- ATUALIZAR,
- e EXCLUIR.
Também funciona para cláusulas HAVING junto com GROUP BY.
Mas se você não tomar cuidado, o SQL BETWEEN pode deixá-lo maluco ao usá-lo, especialmente com datas com hora.
Não se preocupe, no entanto. Temos exemplos para lidar com as pegadinhas no uso do SQL BETWEEN. Mas antes disso, os dados de amostra que usei vieram de NOAA . Você pode solicitar dados meteorológicos gratuitamente deles. Usei os registros de temperatura por hora para os Estados Unidos no ano de 2010. Em seguida, importei os dados CSV para o SQL Server usando o SQL Server Management Studio. Renomeei as colunas e adicionei um índice não clusterizado.
Vamos começar.
Usando SQL BETWEEN com datas e horas
Este deve ser o item mais pesquisado quando se trata de SQL BETWEEN. Usaremos exemplos para explicar como funciona.
Dica nº 1:para colunas DATETIME, especifique a data e a hora
USO ERRADO
Vamos começar com o uso errado para enfatizar este ponto. O seguinte uso de BETWEEN com colunas DATETIME fornecerá resultados inesperados.
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010' AND '01/02/2010'
AND Latitude = 41.995
AND Longitude = -87.9336;
A consulta retorna dados de 2 dias de uma estação meteorológica próxima ao Aeroporto Internacional O'Hare em Chicago. Você pode notar o intervalo entre um valor mais baixo (01/01/2010) e um valor mais alto (01/02/2010). Aqui está o conjunto de resultados na Figura 1.
Figura 1 . Conjunto de resultados de uma consulta usando datas SQL BETWEEN 2.
Mas onde está o problema?
Deve ser um registro de hora em hora por 2 dias. Por isso, o conjunto de resultados deve ter 48 registros. Mas observe que são apenas 24. O problema está no elemento time do DateHour coluna. Quando você não especifica a hora em uma coluna DATETIME, ela assume 00:00 ou 12:00 AM. Além disso, observe que os dados começaram em 1º de janeiro de 2010, à 01h00, e não às 00h00.
Então, internamente, o SQL Server usou DateHour ENTRE '01/01/2010 00:00:00.000′ E '01/02/2010 00:00:00.000′ . Como nós sabemos?
A DATA É REALMENTE UMA STRING
Está certo.
Os valores de data entre aspas simples não são realmente datas, mas strings . O SQL Server usa a conversão implícita para converter a string em DATETIME. Após a conversão, a parte da hora será anexada à data.
Vamos inspecionar com Incluir plano de execução real . Pressione Ctrl-M no SQL Server Management Studio e execute novamente o exemplo anterior.
Quando o Plano de Execução for exibido, clique com o botão direito do mouse em Buscar Índice operador e selecione Propriedades . Veja a Figura 2.
Figura 2 . Conversão implícita de uma string para DATETIME. Ele está oculto no Plano de Execução de uma consulta usando BETWEEN.
Em seguida, expanda Buscar predicados . As partes em caixa da Figura 2 mostram a conversão implícita das 2 strings para DATETIME. Como a conversão implícita é feita internamente , os novatos ficam confusos porque suas expectativas no conjunto de resultados não são atendidas.
USO CORRETO
O exemplo abaixo retornará os registros por hora entre 8h e 12h de 2 de janeiro de 2010.
SELECT * FROM TemperatureData
WHERE DateHour BETWEEN '01/02/2010 08:00' AND '01/02/2010 12:00'
AND Latitude = 41.995
AND Longitude = -87.9336;
Você precisa especificar a parte do tempo, especialmente quando as datas são as mesmas. Ou seus resultados esperados não acontecerão.
Para retornar os registros do dia inteiro, isso não funcionará:
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour = '06/01/2010'
AND Latitude = 41.995
AND Longitude = -87.9336;
Ele retornará apenas 1 registro – o de 1º de junho de 2010, às 00:00. Mas usando BETWEEN com os horários especificados, você pode retornar o registro de cada hora do dia inteiro. Veja o próximo exemplo.
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '06/01/2010 00:00' AND '06/01/2010 23:00'
AND Latitude = 41.995
AND Longitude = -87.9336;
Observe que especifiquei apenas até 23:00. Se seus dados usarem qualquer hora do dia, use 23h59 ou 23h59 no valor mais alto do intervalo. Especifique os segundos também se você precisar disso.
Dica 2:considere o tipo de dados DATE
Se você não precisar da parte do tempo, considere o tipo de dados DATE. E você evitará os problemas mencionados acima.
SQL ENTRE com números
Passemos aos números.
Dica 3:inclua a parte decimal para valores não inteiros
SELECT
DateHour
,[Hourly_Heating_Degree_Hours]
FROM TemperatureData
WHERE DateHour BETWEEN '06/01/2010' AND '06/5/2010 23:00'
AND [Hourly_Heating_Degree_Hours] BETWEEN 5.0 AND 7.0
AND Latitude = 41.995
AND Longitude = -87.9336;
Observe a adição de outra condição envolvendo números. Os resultados serão ainda limitados a 5 e 7 graus.
Ao usar os tipos de dados DECIMAL, MONEY ou FLOAT, especifique a parte decimal mesmo que seja zero, como 52,00 ou 10,0000. Dessa forma, você evita a conversão implícita para os tipos de dados DECIMAL, MONEY ou FLOAT de destino.
SQL BETWEEN com Strings
Dica 4:para strings, o intervalo é baseado no agrupamento
Com strings, BETWEEN avalia valores com base em ordem alfabética. ‘A’ é o menor e ‘Z’ é o maior. Você também pode dizer que, em geral, a avaliação é baseada no agrupamento. Porque o inglês não é o único idioma que o SQL Server suporta. Agrupamento fornece regras de classificação, distinção entre maiúsculas e minúsculas e acentos. Vamos usar o AdventureWorks banco de dados para este exemplo. Confira o código abaixo e o resultado na Figura 3.
USE AdventureWorks
GO
SELECT
LastName
,FirstName
,MiddleName
FROM Person.Person
WHERE Lastname BETWEEN 'Spanaway' AND 'Splane'
ORDER BY LastName;
Figura 3 . Conjunto de resultados de uma consulta usando BETWEEN com strings.
O intervalo abrange o sobrenome Spanaway . Mas onde está Plano ? É inexistente no banco de dados. Então, o resultado só chegou até Spicer .
SQL BETWEEN Dicas para todos os tipos de dados suportados
Esteja você usando BETWEEN para datas, números ou strings, há coisas comuns das quais você deve estar ciente. Isso pode ser senso comum, mas ainda acontece por engano. Leia como isso pode acontecer.
Dica 5:os valores inicial e final não podem ser NULL
BETWEEN precisa de valores iniciais e finais para o intervalo. Cada um deve ter um valor que não seja NULL. Há um exemplo com um valor final NULL abaixo.
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010' AND NULL;
Isso pode acontecer se você chamar a instrução SELECT de um aplicativo ou procedimento armazenado e não a validar corretamente.
Dica 6:o valor inicial não pode ser maior que o valor final
Nada também será retornado se ambos os valores não forem NULL, mas o intervalo for invertido. Aqui está um exemplo.
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '01/30/2010' AND '01/01/2010';
Além das datas, as seguintes expressões também não retornarão um resultado:
- valor ENTRE 100 E -200. Porque -200 é menor que 100.
- trabalha ENTRE 'Zookeeper' E 'Accountant'. Porque 'Z' é maior que 'A'.
Dica 7:os valores de intervalo devem ser os mesmos tipos de dados
Às vezes, os controles da interface do usuário têm uma saída inesperada. Ou simplesmente pegamos a propriedade errada. E se não verificarmos antes de passá-lo para o SQL Server, pode ocorrer uma situação como esta:
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '06/01/2010' AND 'Saturday, June 5, 2010'
AND Latitude = 41.995
AND Longitude = -87.9336;
Ocorrerá um erro de conversão de uma cadeia de caracteres para uma data.
Portanto, a lição da Dica 5 a 7 é validar os valores inicial e final do intervalo .
Dica 8:use NOT BETWEEN para excluir valores
Considere outro exemplo.
SELECT
MONTH(DateHour) AS [Month]
,round(AVG([Hourly_Heating_Degree_Hours]),2) AS AverageTemperature
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010 00:00' AND '06/30/2010 23:00'
AND DateHour NOT BETWEEN '05/01/2010 00:00' AND '05/31/2010 23:00'
AND Latitude = 41.995
AND Longitude = -87.9336
GROUP BY MONTH(DateHour);
Isso retornará a média mensal de janeiro a junho, mas excluirá maio. A exclusão dos registros de maio de 2010 é possível por NOT BETWEEN. Aqui está o conjunto de resultados na Figura 4.
Figura 4 . Conjunto de resultados de uma consulta usando NOT BETWEEN.
SQL BETWEEN em comparação com outros operadores
Dica 9:Use IN se você precisar de uma lista e não de um intervalo
O operador IN determina se um valor corresponde a qualquer valor em uma lista ou subconsulta. Enquanto isso, usar NOT IN verifica se um valor não corresponde.
Os operadores BETWEEN e IN filtram dados com base em vários valores. Mas a diferença está no conjunto de valores que estão sendo correspondidos. BETWEEN usa um intervalo. Mas IN usa valores separados por vírgulas em uma lista ou linhas em uma subconsulta.
Verifique o exemplo abaixo.
SELECT
DateHour
,[Hourly_Heating_Degree_Hours]
FROM TemperatureData
WHERE DateHour BETWEEN '06/01/2010' AND '06/5/2010 23:00'
AND [Hourly_Heating_Degree_Hours] IN (5.2, 6, 7, 3.7)
AND Latitude = 41.995
AND Longitude = -87.9336;
Veja a lista de valores usados por IN. Não precisa ser uma lista de valores crescentes. O último valor da lista (3,7) também é o menor entre os números.
Dica 10:Escolha entre BETWEEN ou>=com <=
Em tempo de execução, o SQL Server converte BETWEEN em>=com operadores <=. Como nós sabemos?
Observe o código abaixo.
SELECT
DateHour
,AVG(Hourly_Heating_Degree_Hours) AS AverageTemp
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010 08:00' AND '01/01/2010 12:00'
GROUP BY DateHour;
SELECT
DateHour
,AVG(Hourly_Heating_Degree_Hours) AS AverageTemp
FROM TemperatureData
WHERE DateHour >= '01/01/2010 08:00'
AND DateHour <= '01/01/2010 12:00'
GROUP BY DateHour;
Ambas as consultas terão o mesmo conjunto de resultados da Figura 5.
Figura 5 . Resultado definido usando BETWEEN ou>=com <=.
Eles também possuem o mesmo plano de execução, conforme visto na Figura 6.
Figura 6 . Plano de execução de 2 consultas comparando o uso dos operadores BETWEEN e>=e <=.
Mas aqui está a coisa.
Observe o primeiro Índice Buscar operador na Figura 6. Em seguida, veja o Procurar predicados . Você vê a palavra-chave BETWEEN? Não há nenhum, certo? Porque é convertido para>=com operadores <=. Esses são os operadores presentes em Procurar predicados .
Mas há mais.
Se você passar o mouse sobre o segundo Busca de índice operador, você verá as mesmas propriedades que a primeira Pesquisa de índice .
Então, parece que o operador BETWEEN é um atalho para>=com <=operadores . Você digitará mais se usar o último. Você verá a mesma conversão acontecer quando BETWEEN for usado em números e strings.
No final, cabe a você usar BETWEEN ou os operadores>=e <=. O tempo de conversão necessário para converter BETWEEN é insignificante. Mas se você ainda não quiser esse tempo extra e insignificante, use os operadores>=e <=.
Resumo
SQL BETWEEN é bom para buscar dados inclusive do intervalo. E não é tão difícil de usar. Até os valores DATETIME são gerenciáveis com BETWEEN. Apenas certifique-se de cobrir a parte do tempo corretamente. Também é equivalente a usar>=com <=. Cabe a você qual você prefere usar.
Você pode marcar esta página para obter dicas do SQL BETWEEN para datas, números e strings quando precisar.
Se você tiver alguns truques usando BETWEEN que não abordamos, você pode compartilhá-los conosco na seção de comentários. E se você gostou deste artigo, compartilhe-o pressionando os botões de mídia social.
Boa codificação a todos!