Consulta de Postgresql entre rangos de fechas

126

Estoy tratando de consultar mi base de datos postgresql para devolver resultados donde una fecha está en cierto mes y año. En otras palabras, me gustaría todos los valores para un mes-año.

La única forma en que he podido hacerlo hasta ahora es así:

SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN '2014-02-01' AND '2014-02-28'

El problema con esto es que tengo que calcular la primera fecha y la última fecha antes de consultar la tabla. ¿Existe una forma más sencilla de hacer esto?

Gracias

Juan
fuente
¿El intervalo es siempre de un mes o podría ser que empiece quizás en el día 15 y termine el día 7 del mes siguiente?
frlan

Respuestas:

202

Con fechas (y horas) muchas cosas se vuelven más simples si usa >= start AND < end.

Por ejemplo:

SELECT
  user_id
FROM
  user_logs
WHERE
      login_date >= '2014-02-01'
  AND login_date <  '2014-03-01'

En este caso, aún necesita calcular la fecha de inicio del mes que necesita, pero eso debería ser sencillo de varias maneras.

La fecha de finalización también se simplifica; solo agregue exactamente un mes. No jugar con el 28, 30, 31, etc.


Esta estructura también tiene la ventaja de poder mantener el uso de índices.


Muchas personas pueden sugerir un formulario como el siguiente, pero no utilizan índices:

WHERE
      DATEPART('year',  login_date) = 2014
  AND DATEPART('month', login_date) = 2

Esto implica calcular las condiciones para cada fila de la tabla (un escaneo) y no usar el índice para encontrar el rango de filas que coincidirán (una búsqueda de rango).

MatBailie
fuente
1
El primer enfoque necesita jugar con meses (en lugar de días) p. Ej. 2014-12-01& 2015-01-01. El segundo también se puede indexar, pero eso no es trivial, lo admito, EXTRACT()parece más compatible.
pozs
1
Puede evitar los cálculos de fecha en su aplicación utilizando intervalo. Por ejemplo: WHERE login_date> = '2014-02-01' AND login_date <'2014-02-01' :: date + INTERVAL '1 month' Esto todavía usa índices mientras simplifica su código.
baswell
53

Desde PostreSQL 9.2 , se admiten los tipos de rango . Entonces puedes escribir esto como:

SELECT user_id
FROM user_logs
WHERE '[2014-02-01, 2014-03-01]'::daterange @> login_date

esto debería ser más eficiente que la comparación de cadenas

Ana María Martínez Gómez
fuente
23

En caso de que alguien aterrice aquí ... desde 8.1, simplemente puede usar:

SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN SYMMETRIC '2014-02-01' AND '2014-02-28'

De los documentos:

BETWEEN SYMMETRIC es lo mismo que BETWEEN excepto que no hay ningún requisito de que el argumento a la izquierda de AND sea menor o igual que el argumento de la derecha. Si no es así, esos dos argumentos se intercambian automáticamente, de modo que siempre se implica un rango no vacío.

HayrolR
fuente
-1
SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN '2014-02-01' AND '2014-03-01'

Entre palabra clave funciona excepcionalmente para una cita. asume que la hora es a las 00:00:00 (es decir, medianoche) para las fechas.

Chaudhary Sarimurrab
fuente
-14

Lea la documentación.

http://www.postgresql.org/docs/9.1/static/functions-datetime.html

Usé una consulta como esa:

WHERE
(
    date_trunc('day',table1.date_eval) = '2015-02-09'
)

o

WHERE(date_trunc('day',table1.date_eval) >='2015-02-09'AND date_trunc('day',table1.date_eval) <'2015-02-09')    

Ingeniero Juanitos.

Juan Garfias
fuente
2
Esto no responde exactamente a la pregunta. La pregunta solicita fechas basadas en mes y año.
Ram