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


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).


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


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.


-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.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.