Solución:
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 debe 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 28, 30, 31, etc.
Esta estructura también tiene la ventaja de poder mantener el uso de índices.
Muchas personas pueden sugerir una forma como la siguiente, pero no no usar í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).
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
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, por lo que siempre se implica un rango no vacío.