2015-07-02 2 views
2

На 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 

В основном, один линейный выход для каждой «группы» смежных строк (когда таблица отсортирована на колонке с отметкой времени) с то же самое «рецепт». В выводе prod1_sum является суммой prod1 в «группе», prod2_avg является средним значением prod2 в той же «группе», а 2 последних столбца являются соответственно первой и последней отметками времени в группе. Очевидно, что существует несколько различных групп с одинаковым значением «рецепт», и я хочу, чтобы каждая строка была выбрана.

На данный момент у меня есть уродливый способ получить это на основе нескольких запросов и обработки данных за пределами БД, чего я действительно хочу избежать, и чего не стоит показывать.

Моя проблема - это «группировка» строк. Я знаю, как создать агрегатную функцию, которая будет делать то, что я хочу, если бы я мог применить ее к каждой группе отдельно. Я просмотрел функции Windows, но, похоже, это сгруппировало бы все значения по рецепту, не соответствующие принципу «смежных строк», который мне нужно уважать.

ответ

2

Вы можете использовать следующий запрос:

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 вычисляемого поля делает именно это.

Demo here

+0

Это абсолютно удивительным и на месте! То, как вы написали это, делает его совершенно ясным. Я буду копаться в документации, чтобы лучше понять детали (ROW_NUMBER() OVER, «t» после FROM mytable, ...), но теперь я на рельсах. Большое спасибо. –

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