SQL "entre" no inclusivo


Tengo una consulta como esta:

SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'

Pero esto no da resultados a pesar de que hay datos sobre el 1er.

created_at parece que 2013-05-01 22:25:19, sospecho que tiene que ver con el tiempo? ¿Cómo se podría resolver esto?

Funciona bien si hago rangos de fechas más grandes, pero también debería (inclusive) funcionar con una sola fecha.

Author: abatishchev, 2013-05-03

7 answers

It is inclusive. Estás comparando fechas con fechas. La segunda fecha se interpreta como medianoche cuando el día comienza.

Una forma de arreglar esto es:

SELECT *
FROM Cases
WHERE cast(created_at as date) BETWEEN '2013-05-01' AND '2013-05-01'

Otra forma de arreglarlo es con comparaciones binarias explícitas

SELECT *
FROM Cases
WHERE created_at >= '2013-05-01' AND created_at < '2013-05-02'

Aaron Bertrand tiene una larga entrada de blog sobre fechas ( aquí ), donde discute este y otros temas de fechas.

 215
Author: Gordon Linoff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-02 21:20:43

Se ha asumido que la segunda referencia de fecha en la sintaxis BETWEEN se considera mágicamente como el "final del día", pero esto no es cierto.

Es decir, esto se esperaba:

SELECT * FROM Cases 
WHERE created_at BETWEEN the beginning of '2013-05-01' AND the end of '2013-05-01'

Pero lo que realmente sucede es esto:

SELECT * FROM Cases 
WHERE created_at BETWEEN '2013-05-01 00:00:00+00000' AND '2013-05-01 00:00:00+00000'

Que se convierte en el equivalente de:

SELECT * FROM Cases WHERE created_at = '2013-05-01 00:00:00+00000'

El problema es uno de percepciones / expectativas sobre BETWEEN que incluye TANTO el valor inferior como los valores superiores en el rango, pero no{[10]]} mágicamente hacer una fecha el " principio de "o"el final de".

BETWEEN debe evitarse al filtrar por intervalos de fechas.

Siempre use el >= AND < en su lugar

SELECT * FROM Cases 
WHERE (created_at >= '20130501' AND created_at < '20130502')

Los paréntesis son opcionales aquí, pero pueden ser importantes en consultas más complejas.

 29
Author: Used_By_Already,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-21 23:57:30

Necesitas hacer una de estas dos opciones:

  1. Incluya el componente time en su condición between: ... where created_at between '2013-05-01 00:00:00' and '2013-05-01 23:59:59' (no recomendado... véase el último párrafo)
  2. Use desigualdades en lugar de between. Ten en cuenta que entonces tendrás que añadir un día al segundo valor: ... where (created_at >= '2013-05-01' and created_at < '2013-05-02')

Mi preferencia personal es la segunda opción. También, Aaron Bertrand tiene una explicación muy clara sobre por qué debe usarse.

 13
Author: Barranka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:12

Simplemente use la marca de tiempo como fecha:

SELECT * FROM Cases WHERE date(created_at)='2013-05-01' 
 4
Author: Balinti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-12 19:13:21

Encuentro que la mejor solución para comparar un campo datetime con un campo date es la siguiente:

DECLARE 
@StartDate DATE = '5/1/2013'
,@EndDate DATE = '5/1/2013'

SELECT *
FROM Cases
WHERE 
DATEDIFF(DAY,created_at,@StartDate) <=0 
AND DATEDIFF(DAY,created_at,@EndDate)>=0

Esto es equivalente a una instrucción inclusive between, ya que incluye tanto la fecha de inicio como la de finalización, así como las que se encuentran entre ellas.

 4
Author: Ted,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-24 16:14:02
cast(created_at as date)

Eso solo funcionará en 2008 y versiones más recientes de SQL Server

Si está utilizando una versión anterior, utilice

convert(varchar, created_at, 101)
 0
Author: Ali Adravi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-18 12:18:52

Puede usar la función date() que extraerá la fecha de una datetime y le dará el resultado como fecha inclusiva:

SELECT * FROM Cases WHERE date(created_at)='2013-05-01' AND '2013-05-01'
 0
Author: abhishek kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-22 07:51:34