Получение результатов между двумя датами в 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')