postgresql: параметризовать тип агрегации? - PullRequest
0 голосов
/ 29 мая 2011

Мне нужно предоставить ряд хранимых процедур, которые возвращают результат выполнения агрегатной функции для выбора значений в базе данных, т. Е. Среднего, суммы, минимума, максимума и т. Д. Выбор значений всегда выполняется впохожим образом.

Моя первая, наивная реализация состоит из одного хранимого процесса для каждого типа агрегатной функции, например, get_avg (...), get_sum (...).Функции, очевидно, имеют довольно много повторяющегося кода.Интересно, есть ли способ переместить агрегатный тип в параметр или около того, а затем использовать только один сохраненный процесс, например, get_aggregate (aggr_type, ...)

Единственный способ, который я могу придумать, насколькоРеализация pl / pgsql заключается в том, чтобы выбрать значения, которые должны входить в агрегат, а затем использовать их во всех предложениях if aggr_type == ... / else, которые существуют в агрегатных типах.Хотя это не очень гибко и требует изменения кода всякий раз, когда должен поддерживаться новый тип агрегата.

Есть ли способ параметризации имени функции в pl / pgsql?Может ли кто-нибудь придумать подход, который я не вижу?

1 Ответ

1 голос
/ 30 мая 2011

Технически вы можете использовать оператор execute в вашей функции plpgsql:

return query
execute $x$
select id, $x$ || quote_ident(agg_func) || $x$(col)::numeric as agg
from bar
$x$;

(правильный пример приведен ниже).Проблема в том, что это будет означать анализ / планирование вашего запроса при каждом вызове.

Иногда лучшим вариантом будет создание функции, которая создает различные необходимые функции.Примерно так:

create or replace function generate_agg_functions(_table regclass) returns void as $$
declare
  _agg_type text[] = '{sum, avg}';
  _ret_type regtype[] = '{numeric, numeric}';
  rec record;
begin
  for rec in select _agg_type[i] as agg_type, _ret_type[i] as ret_type
  from generate_subscripts(_agg_type, 1) i
  loop
  execute $x$
  create or replace function $x$ || quote_ident(_table || '_' || rec.agg_func) || $x$()
    returns table (id int, $x$ || quote_ident(rec.agg_type) || ' ' || ret_type || $x$)
  $def$
  begin
    return query
    select id,
           $x$ || quote_ident(rec.agg_type) || $x$(col)::$x$ || rec.ret_type || $x$
             as $x$ || quote_ident(rec.agg_type) || $x$
    from $x$ || _table || $x$;
  end;
  $def$ language plpgsql stable;
  $x$;
  end loop;
end;
$$ language plpgsql;

Писать немного сложнее, но в итоге вы не будете дублировать код, не ставя под угрозу производительность отдельных агрегатов.

...