Получение результатов между двумя датами в PostgreSQL
у меня есть следующие таблицы:
+-----------+-----------+------------+----------+
| id | user_id | start_date | end_date |
| (integer) | (integer) | (date) | (date) |
+-----------+-----------+------------+----------+
поля start_date
и end_date
удерживают значения даты, такие как YYYY-MM-DD
.
запись из этой таблицы может выглядеть так: (1, 120, 2012-04-09, 2012-04-13)
.
Я должен написать запрос, который может получить все результаты, соответствующие определенному периоду.
проблема в том, что если я хочу получить результаты из 2012-01-01
to 2012-04-12
, Я получаю 0 результатов, хотя есть запись с start_date = "2012-04-09"
и end_date = "2012-04-13"
.
8 ответов
SELECT *
FROM mytable
WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE);
функции Datetime является соответствующим разделом в документах.
предполагая, что вы хотите все"перекрытие" периоды времени, т. е. все, что есть по крайней мере один день в общем.
попробуйте представить себе периоды времени на прямой линии времени и перемещать их перед вашими глазами и вы посмотреть необходимые условия.
SELECT *
FROM tbl
WHERE start_date <= '2012-04-12'::date
AND end_date >= '2012-01-01'::date;
это иногда быстрее для меня, чем OVERLAPS
- что является другим хорошим способом сделать это (как @Marco уже предоставил).
обратите внимание на тонкие разница (в документации):
OVERLAPS
автоматически принимает значение пары как начать. Каждый период времени считается полуоткрытым интервалstart <= time < end
, если начало и конец равны, в котором случай он представляет тот единственный момент времени. Это означает, например что два периода времени с общей конечной точкой не перекрываются.
смелый акцент шахта.
производительность
для больших столов право индекс может помочь производительности (много).
CREATE INDEX tbl_date_inverse_idx ON tbl(start_date, end_date DESC);
возможно, с другим (ведущим) столбцом индекса, если у вас есть дополнительные выборочные условия.
обратите внимание на обратный порядок из двух столбцов. Подробное объяснение:
просто имел тот же вопрос и ответил таким образом, если это может помочь.
select *
from table
where start_date between '2012-01-01' and '2012-04-13'
or end_date between '2012-01-01' and '2012-04-13'
чтобы запрос работал в любых настройках локали, рассмотрим форматирование даты сам себе:
SELECT *
FROM testbed
WHERE start_date >= to_date('2012-01-01','YYYY-MM-DD')
AND end_date <= to_date('2012-04-13','YYYY-MM-DD');
глядя на даты, для которых он не работает-те, где день меньше или равен 12 - мне интересно, разбирает ли он даты как находящиеся в формате гггг-ДД-ММ?
без обид, но для проверки производительности sql я выполнил некоторые из вышеупомянутых решений pgsql.
позвольте мне поделиться с вами статистикой лучших 3-х подходов к решению, с которыми я сталкиваюсь.
1) взял: 1.58 MS Avg
2) взял: 2.87 MS Avg
3) взял: 3,95 МС Avg
теперь попробуйте это :
SELECT * FROM table WHERE DATE_TRUNC('day', date ) >= Start Date AND DATE_TRUNC('day', date ) <= End Date
теперь это решение заняло: 1.61 Avg.
и лучшим решением является 1-й, предложенный Марко Мариани
SELECT *
FROM ecs_table
WHERE (start_date, end_date) OVERLAPS ('2012-01-01'::DATE, '2012-04-12'::DATE + interval '1');
вы должны использовать метод выборки части даты:
SELECT * FROM testbed WHERE start_date ::date >= to_date('2012-09-08' ,'YYYY-MM-DD') and date::date <= to_date('2012-10-09' ,'YYYY-MM-DD')