2017-01-26 8 views
1

Я использую Greenplum DB, и я хотел бы вычислить медиану в окне, что-то вроде:Пользовательского Greenplum агрегатная функции с окном

SELECT avg(var1) OVER (PARTITION BY var2 ORDER BY datetime 
         ROWS BETWEEN 10 PRECEDING AND CURRENT ROW) FROM tbl... 

К сожалению медианы не реализованный в Postgres, так что я создал свой собственный агрегат используя этот пример: https://wiki.postgresql.org/wiki/Aggregate_Median

Проблема в том, что это работает, когда я использую весь столбец, но не в окне (с предложением OVER), возвращающем ошибку, которая должна быть определена как префикс. Документация Greenplum подтверждает, что: http://gpdb.docs.pivotal.io/4380/ref_guide/sql_commands/CREATE_AGGREGATE.html

Документация и роль префикса для меня не очень понятна. Есть ли у вас пример определения настраиваемой функции агрегации Postgres, поддерживающей окна?

ответ

0

Чтобы создать пользовательский агрегат в GPDB вам нужно определить PREFUNC, который не является параметром в обычных Postgres.

В обычном Postgres агрегату требуется начальное состояние (например, STYPE=numeric[]) и функция, которая сообщает ему, что делать, чтобы добавить новый элемент в текущее состояние (например, SFUNC=array_append). Но в распределенной системе, такой как GPDB, которая перемещает данные вокруг узлов, каким образом узел, принимающий состояние из двух мест (т. Е. Двух массивов), объединяет оба состояния? Такова роль PREFUNC. Затем, наконец, FINALFUNC можно вызвать в единственном объединенном состоянии и вернуть.

В примере вычисления медианы все, что вам нужно сделать, это добавить PREFUNC=array_cat, в определение совокупности, которое вы взяли с median example code. array_cat берет два массива и возвращает их как единый объединенный массив. Я пробовал это, и он работает для меня как для совокупности, так и для окна.

(Обратите внимание, что версия, которая принимает numeric[] работает, но по какой-то причине не anyarray один. Кажется, по причинам, не имеющих важное значение для создания окна/агрегатную функцию.)

Для получения дополнительной информации о агрегатах см. GPDB docs, о котором упоминал Лукаш.

+0

Он работает, спасибо за объяснение 'PREFUNC' – Lukasz

+0

Отлично, рад, что это было полезно @Lukasz. Если вы почувствуете, что ответ достойный, я бы очень признателен за его поддержку и [отмечаю его как принятый] (http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work). –

1

Я не знаю, будет ли это работать на Greenplum. Но в современных версиях Postgres вы можете использовать array_agg() как функцию окна. Таким образом, для особенно проблемы, бегущая медиана:

select (array_agg(var1) over (partition by var2 order by datetime 
           rows between 10 preceding and current row 
          )[6] as running_median 

EDIT:

Другой метод будет использовать подзапрос:

select t.*, 
     (select t2.var1 
     from t t2 
     where t2.var2 = t.var2 and t2.datetime < t.datetime 
     order by t2.datetime desc 
     offset 5 limit 1 
     ) running_median   
from t; 
+0

Greenplum основан на [PostgreSQL 8.2.15] (http://greenplum.org/gpdb-sandbox-tutorials/). Я думаю, что array_agg() не был доступен в этой версии. – McNets

+0

array_agg() находится в GPDB. –

+0

array_agg() работает, но с группой не с окном, я все еще получаю 'ERROR: агрегированные функции без prelimfn или invprelimfn еще не поддерживаются как функции окна – Lukasz