¿El "entre" de MS SQL Server incluye los límites del rango?

234

Por ejemplo puede

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

seleccione 5 y 10 o están excluidos del rango?

Lea Verou
fuente

Respuestas:

258

El operador ENTRE es inclusivo.

De libros en línea:

ENTRE devuelve VERDADERO si el valor de test_expression es mayor o igual que el valor de begin_expression y menor o igual que el valor de end_expression.

Advertencia de fecha y hora

NB: Con DateTimes tienes que tener cuidado; si solo se da una fecha, el valor se toma a partir de la medianoche de ese día; para evitar tiempos faltantes dentro de su fecha de finalización, o repetir la captura de los datos del día siguiente a medianoche en varios rangos, su fecha de finalización debe ser 3 milisegundos antes de la medianoche del día posterior a su fecha de finalización. 3 milisegundos porque menos que esto y el valor se redondeará hasta la medianoche del día siguiente.

por ejemplo, para obtener todos los valores en junio de 2016, deberá ejecutar:

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

es decir

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

datetime2 y datetimeoffset

Restar 3 ms de una fecha te dejará vulnerable a las filas faltantes de la ventana de 3 ms. La solución correcta es también la más simple:

where myDateTime >= '20160601' AND myDateTime < '20160701'
DJ.
fuente
11
Al usar ENTRE para filtrar DateTimes entre dos fechas, también puede convertir el DateTime a una fecha, por ejemplo: donde CONVERT (DATE, MyDate) ENTRE '2017-09-01' y '2017-09-30' Este enfoque hace que el tiempo elemento de la fecha y hora irrelevante
Pete
1
Asegúrese de no tratar de restar 3 ms de una fecha; te perderás elementos de esos 3 ms. Y tampoco desea CONVERTuna fecha y hora para una fecha , ya que eso hará que los índices sean inútiles. Usa el estándar WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Además, asegúrese de usarlo yyyymmdd, ya yyyy-mm-ddque depende de la configuración regional y se interpretará mal según la mdy, dmy, ymd, ydm, myd, and dymconfiguración de su servidor .
Ian Boyd
254

Sí, pero tenga cuidado al usar entre fechas.

BETWEEN '20090101' AND '20090131'

realmente se interpreta como las 12 a.m., o

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

así que extrañará todo lo que ocurrió durante el día 31 de enero. En este caso, deberá usar:

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

o

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

ACTUALIZACIÓN : ¡Es completamente posible crear registros dentro de ese último segundo del día, con una fecha y hora tan tardía como 20090101 23:59:59.997!!

Por esta razón, BETWEEN (firstday) AND (lastday 23:59:59)no se recomienda el enfoque.

Use el myDate >= (firstday) AND myDate < (Lastday+1)enfoque en su lugar.

Buen artículo sobre este tema aquí .

BradC
fuente
1
Problemas similares con las cadenas también WHERE col BETWEEN 'a' AND 'z'excluirán la mayoría de las filas z, por ejemplo.
Martin Smith
8
Este punto es correcto, por supuesto; pero no debería ser sorprendente si estás trabajando con citas. Es análogo a señalar que BETWEEN 5 AND 10no incluye 10.2...
Andrzej Doyle
44
CASTing del datetimecomo DATEfuncionaría: CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
craig
2
@craig, eso es cierto, siempre y cuando esté utilizando SQL 2008 o superior, que es cuando se introdujo el tipo de datos Fecha. Además, esa sintaxis convertirá ese valor para cada fila, por lo que no podrá usar ningún índice en ese campo (si eso es un 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<- ¿no podría usarlo entonces AND '01/31/2009 23:59:59.99999999'o se requieren muchos 9's
wal
16

Ejemplo del mundo real de SQL Server 2008.

Datos fuente:

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

Consulta:

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

Ryan Rodemoyer
fuente
No recibí tu respuesta, para ser honesto. Tal vez mi proveedor de internet ha ocultado su captura de pantalla si publicó una.
anar khalilov
2
¿Por qué se ID = 3excluye la fila con ? Su Startvalor es igual al BETWEENvalor del límite superior, y BETWEENes un rango inclusivo, no un rango limitado superior exclusivo.
Dai
Mejor respuesta con resultados.
Sam
13

si acierta y realmente no quiere intentar agregar un día en el código, deje que la base de datos lo haga ...

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

Si incluye la porción de tiempo: asegúrese de que haga referencia a la medianoche. De lo contrario, simplemente puede omitir el tiempo:

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

y no te preocupes por eso.

Shaun
fuente
12

ENTRE (Transact-SQL)

Especifica un rango ( n ) ( inclusive ) para probar.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

Argumentos

test_expression

Es la expresión para probar en el rango definido por begin_expression y end_expression. test_expression debe ser del mismo tipo de datos que begin_expression y end_expression.

NOT

Especifica que el resultado del predicado sea negado.

begin_expression

Es cualquier expresión válida. begin_expression debe ser el mismo tipo de datos que test_expression y end_expression.

end_expression

Es cualquier expresión válida. end_expression debe ser el mismo tipo de datos que test_expression y begin_expression.

AND

Actúa como un marcador de posición que indica que test_expression debe estar dentro del rango indicado por begin_expression y end_expression.

Observaciones

Para especificar un rango exclusivo, use los operadores mayor que (>) y menor que (<). Si alguna entrada al predicado ENTRE o NO ENTRE es NULL, el resultado es DESCONOCIDO.

Valor del resultado

ENTRE devuelve VERDADERO si el valor de test_expression es mayor o igual que el valor de begin_expression y menor o igual que el valor de end_expression.

NO ENTRE devuelve VERDADERO si el valor de test_expression es menor que el valor de begin_expression o mayor que el valor de end_expression.

Russ Cam
fuente
3

Si el tipo de datos de la columna es datetime, puede hacer lo siguiente para eliminar el tiempo de datetime y comparar solo el rango de fechas.

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)
Kahlil Vanz
fuente
Esto funciona mejor que agregar +1 a la fecha de finalización. Estoy de acuerdo con Andrew Morton: si no es compatible, puede mejorar el rendimiento para cambiar el tipo de datos de la columna o agregar una segunda columna solo con fechas calculadas previamente.
Arno Peters
0

Sí incluye límites.

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
fuente
-3

Siempre he usado esto:

DONDE myDate ENTRE startDate AND (endDate + 1)

usuario2296528
fuente