4

Допустим, у вас есть следующие PostgreSQL разреженным таблица с перечнем дат бронирование:Совокупные непрерывные диапазоны дат

CREATE TABLE reserved_dates (
    reserved_days_id SERIAL NOT NULL, 
    reserved_date  DATE NOT NULL 
); 

INSERT INTO reserved_dates (reserved_date) VALUES 
    ('2014-10-11'), 
    ('2014-10-12'), 
    ('2014-10-13'), 
    -- gap 
    ('2014-10-15'), 
    ('2014-10-16'), 
    -- gap 
    ('2014-10-18'), 
    -- gap 
    ('2014-10-20'), 
    ('2014-10-21'); 

Как вы агрегировать эти даты в непрерывные диапазоны дат (диапазоны без пробелов)? Такие, как:

start_date | end_date 
------------+------------ 
2014-10-11 | 2014-10-13 
2014-10-15 | 2014-10-16 
2014-10-18 | 2014-10-18 
2014-10-20 | 2014-10-21 

Это то, что я придумал до сих пор, но я могу получить только start_date таким образом:

WITH reserved_date_ranges AS (
    SELECT reserved_date, 
      reserved_date 
      - LAG(reserved_date) OVER (ORDER BY reserved_date) AS difference 
    FROM reserved_dates 
) 
SELECT * 
FROM reserved_date_ranges 
WHERE difference > 1 OR difference IS NULL; 
+2

ключевого слова * календарь таблица *, в Вашем случае :: generate_series() LEFT JOIN YourTable, в основном. – wildplasser

+0

Хорошо, я восполняю промежутки между этими датами. Как получить диапазоны дат от этого? – Linas

ответ

6
SELECT min(reserved_date) AS start_date 
    , max(reserved_date) AS end_date 
FROM (
    SELECT reserved_date 
     , reserved_date - row_number() OVER (ORDER BY reserved_date)::int AS grp 
    FROM reserved_dates 
    ) sub 
GROUP BY grp 
ORDER BY grp; 
  1. Compute бегущая, разрыв меньше число в хронологическом порядке с помощью оконной функции row_number() - если только ваш reserved_days_id не имеет зазора и в хронологическом порядке, который обычно не случай.

  2. Вычесть, что от reserved_date в каждой строке (после преобразования в integer). Последовательные дни заканчиваются тем же значением даты grp, которое не имеет иной цели или значения, чем для формирования групп.

  3. Агрегат во внешнем запросе. Вуаля.

SQL Fiddle.

Подобные случаи:

+0

Спасибо Эрвин! – Linas

+0

Этот A кажется сложным для применения в общем случае для временных рядов с заданным разрешением, например. 2 дня или каждые 10 минут. Временные метки должны быть приведены к реальным значениям, а операции с плавающей точкой не точны. Есть ли альтернативы? – mlt

+0

Я возвращаю слова. Это решение работает со столбцами timestamp, похожими на 'extract (epoch from timestamp) - extract (epoch from interval '1day') * row_number() over (order by timestamp)' – mlt

Смежные вопросы