编写自定义聚合函数

时间:2019-04-08 14:07:39

标签: postgresql aggregate-functions plpgsql

最近我一直在练习和研究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 :(得分:0)

您从根本上做对了事,但是您的实现仍然存在一些问题:

  1. 如果表为空,则汇总将出错。相反,它应该返回NULL

  2. 如果您要汇总的第一个值是NULL,则您的汇总将做错事情。如果

    minVal := $1[1];
    

    minVal设置为NULL,然后所有将来的比较minVal >= i不是TRUE,最终结果将为{{1 }},这不是您想要的。

  3. 您将所有值收集到一个数组中,如果您聚合许多行,该值将变得非常大。首先,这使您面临阵列用尽内存的危险,然后聚合的性能将不尽如人意。

    最好在NULL中执行比较:从SFUNC开始,使用INITCOND = NULL并在您处理新值时执行汇总。 STYPE = numeric的相关部分如下所示:

    SFUNC

    那样,您根本不需要IF $1 IS NULL OR $1 > $2 RETURN $2; ELSE RETURN $1; END IF;