Написание пользовательской агрегатной функции - PullRequest
1 голос
/ 08 апреля 2019

В последнее время я практикуюсь и изучаю PL / pgSQL.Я застрял при создании пользовательской агрегатной функции.

Код ниже работает просто отлично, но я не могу написать агрегатную функцию этого типа:

SELECT my_aggregate_function(column) from table;

Воткод «частично работающего пользовательского агрегата»:

CREATE OR REPLACE FUNCTION searchMinValue (numeric[]) RETURNS numeric   AS $$
  DECLARE 
     i numeric;
     minVal numeric;
  BEGIN
    minVal := $1[1];
    IF ARRAY_LENGTH($1,1) > 0 THEN --Checking whether the array is empty or not
  <<confrontoMinimo>>
   FOREACH i IN ARRAY $1 LOOP --Looping through the entire array, passed as parameter
       IF minVal >= i THEN
           minVal := i;
       END IF;
   END LOOP confrontoMinimo;
   ELSE
    RAISE NOTICE 'Invalid parameter % passed to the aggregate function',$1;
   --Raising exception if the parameter passed as argument points to null.
   RAISE EXCEPTION 'Cannot find Max value. Parameter % is null', $1
   USING HINT = 'You cannot pass a null array! Check the passed parameter';
END IF;
RETURN minVal;
END;
$$ LANGUAGE plpgsql;

CREATE AGGREGATE searchMinValueArray (numeric)
(
sfunc = array_append,
stype = numeric[],
finalfunc = searchMinValue,
initCond = '{}'
); 

 with w(v) as (select 5 union all select 2 union all select 3)
 select min(v) "Normal Aggregate", searchMinValueArray(v) "My Customed Aggregate" from w;

Как я уже говорил, я бы хотел вызвать свою функцию пользовательского агрегата следующим образом:

SELECT my_aggregate_function(column) from table;

гдетаблица Customers, а столбец salary типа numeric.

1 Ответ

0 голосов
/ 08 апреля 2019

Вы в основном делаете правильные вещи, но в вашей реализации все еще есть некоторые проблемы:

  1. Ваш агрегат выдаст ошибку, если таблица пуста.Скорее, он должен вернуть NULL.

  2. Если первое значение, которое вы агрегируете, равно NULL, то ваш агрегат будет действовать неправильно.если

    minVal := $1[1];
    

    устанавливает minVal на NULL, то все будущие сравнения minVal >= i будут не равны TRUE, а конечный результат будет NULL, чтоэто не то, что вам нужно.

  3. Вы собираете все значения в массив, который станет довольно большим, если вы соберете много строк.Сначала это подвергает вас риску исчерпания памяти с массивом, а затем производительность агрегата будет не такой хорошей, как могла бы быть.

    Гораздо лучше выполнить сравнение в SFUNC: начните с INITCOND = NULL, используйте STYPE = numeric и выполняйте агрегирование всякий раз, когда вы обрабатываете новое значение.Соответствующая часть SFUNC будет выглядеть следующим образом:

    IF $1 IS NULL OR $1 > $2
        RETURN $2;
    ELSE
        RETURN $1;
    END IF;
    

    Таким образом, вам вообще не понадобится FINALFUNC.

...