Как применить агрегатную функцию только к смежным строкам?
На PostgreSQL 9.4 я пытаюсь добиться того, что я буду называть "агрегатной функцией" для некоторых смежных строк. Пример:
Входные данные:
recipe prod1 prod2 timestamp
0 5 4 2015-07-02 08:10:34.357
0 2 7 2015-07-02 08:13:45.352
0 7 0 2015-07-02 08:16:22.098
1 3 2 2015-07-02 08:22:14.678
1 9 4 2015-07-02 08:22:56.123
2 2 6 2015-07-02 08:26:37.564
2 1 7 2015-07-02 08:27:33.109
2 0 8 2015-07-02 08:31:11.687
0 3 5 2015-07-02 08:40:01.345
1 4 2 2015-07-02 08:42:23.210
Желаемый результат:
recipe prod1_sum prod2_avg timestamp_first timestamp_last
0 14 3.6666 2015-07-02 08:10:34.357 2015-07-02 08:16:22.098
1 12 3 2015-07-02 08:22:14.678 2015-07-02 08:22:56.123
2 3 7 2015-07-02 08:26:37.564 2015-07-02 08:31:11.687
0 3 5 2015-07-02 08:40:01.345 2015-07-02 08:40:01.345
1 4 2 2015-07-02 08:42:23.210 2015-07-02 08:42:23.210
В основном, одна выходная строка для каждой "группы" смежных строк (при сортировке таблицы по столбцу timestamp) с одним и тем же значением "рецепта". В выходных данных prod1_sum-сумма prod1 в "группе", prod2_avg-среднее значение prod2 в той же" группе", и 2 последних столбца соответственно являются первыми и последние метки времени в группе. Очевидно, что существует несколько различных групп с одним и тем же значением "рецепта", и я действительно хочу получить выходную строку для каждой из них.
На данный момент у меня есть уродливый способ получения этого, основанный на нескольких запросах и большой обработке данных за пределами БД, чего я действительно хочу избежать, и который не стоит показывать.Моя проблема на самом деле заключается в "группировке" строк. Я знаю, как создать агрегатную функцию, которая делала бы то, что я хочу, если бы я мог применить это к каждой группе индивидуально. Я заглянул в функции windows, но, похоже, это сгруппирует все значения по рецепту, не согласующемуся с принципом "непрерывных строк", который я должен уважать.
1 ответ:
Вы можете использовать следующий запрос:
SELECT recipe, SUM(prod1) AS prod1_sum, AVG(prod2) AS prod2_avg, MIN(timestamp) AS timestamp_first, MAX(timestamp) AS timestamp_last FROM ( SELECT recipe, prod1, prod2, timestamp, ROW_NUMBER() OVER (ORDER BY timestamp) - ROW_NUMBER() OVER (PARTITION BY recipe ORDER BY timestamp) AS grp FROM mytable ) t GROUP BY recipe, grp ORDER BY timestamp_first
Хитрость здесь заключается в использовании функции окна
ROW_NUMBER
для идентификации островов непрерывныхrecipe
значений:grp
вычисляемое поле делает именно это.Демо здесь