O "entre" do MS SQL Server inclui os limites do intervalo?


234

Por exemplo, pode

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

selecione 5 e 10 ou eles são excluídos do intervalo?

Respostas:


258

O operador BETWEEN é inclusivo.

Dos Livros Online:

BETWEEN retornará VERDADEIRO se o valor da expressão de teste for maior ou igual ao valor de expressão de início e menor ou igual ao valor de expressão de final.

DateTime Advertência

NB: Com o DateTimes, você deve ter cuidado; se apenas uma data for fornecida, o valor será obtido a partir da meia-noite desse dia; para evitar horas perdidas na data de término ou repetir a captura dos dados do dia seguinte à meia-noite em vários intervalos, a data de término deve ser de 3 milissegundos antes da meia-noite do dia seguinte à sua data de validade. 3 milissegundos porque menos do que isso e o valor será arredondado para meia-noite no dia seguinte.

por exemplo, para obter todos os valores em junho de 2016, você precisa executar:

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

ie

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

datetime2 e datetimeoffset

Subtrair 3 ms de uma data deixará você vulnerável a linhas ausentes da janela de 3 ms. A solução correta também é a mais simples:

where myDateTime >= '20160601' AND myDateTime < '20160701'

11
Ao usar BETWEEN para filtrar DateTimes entre duas datas, você também pode converter o DateTime para uma Data, por exemplo: where CONVERT (DATE, MyDate) ENTRE '2017-09-01' e '2017-09-30' Essa abordagem faz a hora elemento do DateTime irrelevante
— Pete

1
Certifique-se de não tentar subtrair 3 ms de uma data; você perderá itens desses 3 ms. E você também não deseja CONVERTum datetime para uma data , pois isso tornará os índices inúteis. Use o padrão WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Além disso, certifique-se de usar yyyymmdd, pois yyyy-mm-dddepende da localidade e será mal interpretado, dependendo da mdy, dmy, ymd, ydm, myd, and dymconfiguração do servidor .
— 22818 Ian Boyd

254

Sim, mas tenha cuidado ao usar entre datas.

BETWEEN '20090101' AND '20090131'

é realmente interpretado como 12h, ou

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

perderá tudo o que ocorreu durante o dia 31 de janeiro. Nesse caso, você terá que usar:

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!)

ATUALIZAÇÃO : É perfeitamente possível criar registros dentro desse último segundo do dia, com data e hora posteriores a 20090101 23:59:59.997!!

Por esse motivo, a BETWEEN (firstday) AND (lastday 23:59:59)abordagem não é recomendada.

Use a myDate >= (firstday) AND myDate < (Lastday+1)abordagem em seu lugar.

Bom artigo sobre esta questão aqui .


1
Problemas semelhantes com cadeias também WHERE col BETWEEN 'a' AND 'z'excluirão a maioria das linhas z, por exemplo.
— Martin Smith

8
Este ponto está certo, é claro; mas não deve ser surpreendente se você estiver trabalhando com essas datas. É análogo ao apontar que BETWEEN 5 AND 10não inclui 10.2...
— Andrzej Doyle

4
CASTing o datetimecomo DATEiria funcionar: CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
— Craig

2
@ Craig, isso é verdade, desde que você esteja usando o SQL 2008 ou superior, que é quando o tipo de dados Date foi introduzido. Além disso, essa sintaxe converterá esse valor para cada linha, portanto, não será possível usar nenhum índice nesse campo (se isso for um problema).
— 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<- você não poderia usar então AND '01/31/2009 23:59:59.99999999'ou são necessários muitos 9's
— 287

16

Exemplo do mundo real do SQL Server 2008.

Dados de origem:

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

Inquerir:

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

Resultados:

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

texto alternativo


Não recebi sua resposta, para ser sincero. Talvez meu provedor de internet tenha ocultado sua captura de tela se você postou uma.
— Anar khalilov

2
Por que a linha está ID = 3excluída? Seu Startvalor é igual ao BETWEENvalor do limite superior e BETWEENé um intervalo inclusivo, não um intervalo exclusivo do limite superior.
— Dai

Melhor resposta com resultados.
— Sam

13

se você acertar isso e realmente não quiser tentar adicionar um dia no código, deixe o banco de dados fazer isso ..

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

Se você incluir a parte da hora: verifique se ela faz referência à meia-noite. Caso contrário, você pode simplesmente omitir a hora:

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

e não se preocupe com isso.


12

ENTRE (Transact-SQL)

Especifica um intervalo ( n ) ( inclusivo ) a ser testado.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

Argumentos

test_expression

É a expressão a ser testada no intervalo definido por begin_expression e end_expression. test_expression deve ser o mesmo tipo de dados que begin_expression e end_expression.

NOT

Especifica que o resultado do predicado seja negado.

begin_expression

É qualquer expressão válida. begin_expression deve ser o mesmo tipo de dados que test_expression e end_expression.

end_expression

É qualquer expressão válida. end_expression deve ser o mesmo tipo de dados que test_expression e begin_expression.

AND

Atua como um espaço reservado que indica expressão de teste deve estar dentro do intervalo indicado por expressão de início e expressão de fim.

Observações

Para especificar um intervalo exclusivo, use os operadores maior que (>) e menor que (<). Se alguma entrada para o predicado BETWEEN ou NOT BETWEEN for NULL, o resultado será UNKNOWN.

Valor do resultado

BETWEEN retornará VERDADEIRO se o valor da expressão de teste for maior ou igual ao valor de expressão de início e menor ou igual ao valor de expressão de final.

NOT BETWEEN retorna TRUE se o valor de expressão_express for menor que o valor de expressão_início ou maior que o valor de expressão_exemplo.


3

Se o tipo de dados da coluna for datetime, você poderá fazer o seguinte para eliminar o tempo do datetime e comparar apenas o período.

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)

Isso funciona melhor do que adicionar +1 à data final. Concordo com Andrew Morton - se não for sargável, pode melhorar o desempenho para alterar o tipo de dados da coluna ou adicionar uma segunda coluna apenas com datas pré-calculadas.
— Arno Peters

0

Inclui 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

-3

Eu sempre usei isso:

ONDE myDate ENTRE startDate AND (endDate + 1)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.