Запрос Postgresql между диапазонами дат

126

Я пытаюсь запросить мою базу данных postgresql, чтобы вернуть результаты, где дата находится в определенном месяце и году. Другими словами, мне нужны все значения за месяц-год.

Единственный способ, которым я смог это сделать, таков:

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

Проблема в том, что мне нужно вычислить первую и последнюю дату перед запросом таблицы. Есть способ сделать это попроще?

Спасибо

Джон
источник
Всегда ли интервал составляет месяц или может быть, вы начинаете, может быть, 15-го числа и заканчиваете 7-го числа следующего месяца?
frlan

Ответы:

202

С датами (и временем) многие вещи становятся проще, если вы используете >= start AND < end.

Например:

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

В этом случае вам все равно нужно рассчитать дату начала нужного вам месяца, но это должно быть прямо любым способом.

Дата окончания также упрощена; просто добавьте ровно один месяц. Никаких проблем с 28-м, 30-м, 31-м и т. Д.


Эта структура также имеет то преимущество, что она может поддерживать использование индексов.


Многие люди могут предложить такую ​​форму, как следующая, но они не используют индексы:

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

Это включает в себя вычисление условий для каждой отдельной строки в таблице (сканирование) и отказ от использования индекса для поиска диапазона строк, которые будут соответствовать (поиск диапазона).

MatBailie
источник
1
При первом подходе нужно возиться с месяцами (а не днями), например. 2014-12-01& 2015-01-01. Второй тоже можно проиндексировать, но, признаю, это нетривиально - EXTRACT()кажется более совместимым.
pozs
1
Вы можете избежать вычисления даты в вашем приложении, используя интервал. например: WHERE login_date> = '2014-02-01' AND login_date <'2014-02-01' :: date + INTERVAL '1 month' Это по-прежнему использует индексы, упрощая ваш код.
Baswell
53

Начиная с PostreSQL 9.2 поддерживаются типы диапазонов . Вы можете написать это так:

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

это должно быть более эффективным, чем сравнение строк

Ана Мария Мартинес Гомес
источник
23

На всякий случай кто-нибудь приземлится здесь ... начиная с 8.1 вы можете просто использовать:

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

Из документов:

BETWEEN SYMMETRIC то же самое, что BETWEEN, за исключением того, что не требуется, чтобы аргумент слева от AND был меньше или равен аргументу справа. Если это не так, эти два аргумента автоматически меняются местами, так что всегда подразумевается непустой диапазон.

HayrolR
источник
-1
SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN '2014-02-01' AND '2014-03-01'

Ключевое слово Between работает исключительно для даты. предполагается, что время для дат - 00:00:00 (т.е. полночь).

Чаудхари Саримурраб
источник
-14

Прочтите документацию.

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

Я использовал такой запрос:

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

или

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

Хуанитос Инжениер.

Хуан Гарфиас
источник
2
Это не совсем ответ на вопрос. Вопрос запрашивает даты в зависимости от месяца и года.
Ram