Consulta Postgresql entre intervalos de datas

126

Estou tentando consultar meu banco de dados postgresql para retornar resultados onde uma data está em determinado mês e ano. Em outras palavras, gostaria de todos os valores para um mês-ano.

A única maneira que consegui fazer até agora é assim:

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

O problema com isso é que tenho que calcular a primeira data e a última data antes de consultar a tabela. Existe uma maneira mais simples de fazer isso?

obrigado

John
fonte
O intervalo é sempre um mês ou pode ser, que começa talvez no dia 15 e termine no dia 7 do mês seguinte?
frlan

Respostas:

202

Com datas (e horas), muitas coisas ficam mais simples se você usar >= start AND < end.

Por exemplo:

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

Nesse caso, você ainda precisa calcular a data de início do mês de que precisa, mas isso deve ser direto de várias maneiras.

A data de término também é simplificada; basta adicionar exatamente um mês. Não se meta com o dia 28, 30, 31, etc.


Essa estrutura também tem a vantagem de poder manter o uso de índices.


Muitas pessoas podem sugerir uma forma como a seguinte, mas não usam índices:

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

Isso envolve calcular as condições para cada linha na tabela (uma varredura) e não usar o índice para encontrar o intervalo de linhas que corresponderão (uma busca por intervalo).

MatBailie
fonte
1
A primeira abordagem precisa mexer com meses (em vez de dias) f.ex. 2014-12-01& 2015-01-01. O segundo também pode ser indexado, mas isso não é trivial, admito - EXTRACT()parece mais compatível.
Pozs
1
Você pode evitar cálculos de data em seu aplicativo usando intervalo. Ex: WHERE login_date> = '2014-02-01' AND login_date <'2014-02-01' :: data + INTERVAL '1 mês' Isto ainda usa índices enquanto simplifica seu código.
Baswell
53

Do PostreSQL 9.2 Tipos de intervalo são suportados. Então você pode escrever assim:

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

isto deve ser mais eficiente do que a comparação de strings

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

No caso de alguém pousar aqui ... desde o 8.1, você pode simplesmente usar:

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

Dos documentos:

BETWEEN SYMMETRIC é o mesmo que BETWEEN, exceto que não há nenhuma exigência de que o argumento à esquerda de AND seja menor ou igual ao argumento à direita. Se não for, esses dois argumentos são trocados automaticamente, de modo que um intervalo não vazio está sempre implícito.

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

Entre palavras-chave funciona excepcionalmente para uma data. ele assume que a hora é 00:00:00 (ou seja, meia-noite) para datas.

Chaudhary Sarimurrab
fonte
-14

Leia a documentação.

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

Usei uma consulta assim:

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

ou

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

Juanitos Ingenier.

Juan Garfias
fonte
2
Isso não responde exatamente à pergunta. A pergunta pede datas baseadas em mês e ano.
Carneiro