2017-02-19 6 views
1

Учитывая таблицу со строками, как:В таблице, содержащей строку диапазонов дат, из каждой строки, генерирует одну строки в день, содержащего часы использования

+----+-------------------------+------------------------+ 
| ID |  StartDate  |  EndDate   | 
+----+-------------------------+------------------------+ 
| 1 | 2016-02-05 20:00:00.000 | 2016-02-07 5:00:00.000 | 
+----+-------------------------+------------------------+ 

Я хочу, чтобы произвести таблицу, как это:

+----+------------+----------+ 
| ID | Date | Duration | 
+----+------------+----------+ 
| 1 | 2016-02-05 |  4 | 
| 1 | 2016-02-06 |  24 | 
| 1 | 2016-02-07 |  5 | 
+----+------------+----------+ 

Это вопрос в стиле интервью. Мне интересно, как я могу заняться этим. Можно ли это сделать только с помощью стандартного синтаксиса SQL-запросов? Или это процедурный язык, например pl/pgSQL, для выполнения такого запроса?

ответ

0

Основная идея заключается в следующем:

SELECT date_trunc('day', dayhour) as dd,count(*) 
FROM (VALUES (1, '2016-02-05 20:00:00.000'::timestamp, '2016-02-07 5:00:00.000'::timestamp) 
    ) v(ID, StartDate, EndDate), lateral 
    generate_series(StartDate, EndDate, interval '1 hour') g(dayhour) 
GROUP BY dd 
ORDER BY dd; 

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

SELECT date_trunc('day', dayhour) as dd,count(*) 
FROM (VALUES (1, '2016-02-05 20:00:00.000'::timestamp, '2016-02-07 5:00:00.000'::timestamp) 
    ) v(ID, StartDate, EndDate), lateral 
    generate_series(StartDate, EndDate - interval '1 hour', interval '1 hour') g(dayhour) 
GROUP BY dd 
ORDER BY dd; 

Технически lateral не требуется (и в этом случае, я заменит запятую cross join). Однако это пример бокового соединения, поэтому быть явным является хорошим.

Следует также отметить, что вышеизложенное является самым простым методом. Однако group by замедляет запрос. Существуют и другие методы, которые не требуют генерации серии за каждый час.

+0

Спасибо! Я смог изменить это, чтобы работать с таблицей из нескольких записей. Просто чтобы проверить, правильно ли я это понимаю. Я понимаю, что generate_series создает таблицу временных меток на основе начала/конца/интервала. В общем случае предложение FROM будет соединяться с двумя таблицами. Поскольку generate_series относится к определенным столбцам в строке, кажется, что он создает таблицу для каждой строки и пересекает только эту строку с серией, генерируемой из нее? – ddtemplar

+0

@ ddtemplar. , , Ваше понимание верное. В общем случае в SQL, когда вы хотите применить функцию таблицы к каждой строке, вы выполняете «боковое соединение». Postgres давайте вам делать это без «бокового» ключевого слова. –

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

  • Нет связанных вопросов^_^