简体   繁体   English

编写自定义聚合函数

[英]Writing a custom aggregate function

Lately I've been practicing and studying PL/pgSQL. 最近,我一直在练习和研究PL / pgSQL。 I'm stuck on creating a custom aggregate function. 我坚持创建自定义聚合函数。

The code below works just fine, but I'm not able to write an aggregate function of this type: 下面的代码工作正常,但是我无法编写这种类型的聚合函数:

SELECT my_aggregate_function(column) from table;

Here is the code of the "partially working custom aggregate": 这是“部分工作的自定义聚合”的代码:

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;

As I said before, I'd like to call my custom aggregate function in this way: 如前所述,我想以这种方式调用自定义聚合函数:

SELECT my_aggregate_function(column) from table;

where the table is Customers and the column is salary of type numeric . 其中表是Customers ,列是numeric类型的salary

You are fundamentally doing the right thing, but there are still some problems with your implementation: 您从根本上做对了事情,但是您的实现仍然存在一些问题:

  1. Your aggregate will error out if the table is empty. 如果表为空,则汇总将出错。 Rather, it should return NULL . 相反,它应该返回NULL

  2. If the first value you are aggregating is NULL , your aggregate will do the wrong thing. 如果您要聚合的第一个值是NULL ,那么您的聚合将做错事。 if 如果

     minVal := $1[1]; 

    sets minVal to NULL , then all future comparisons minVal >= i will not be TRUE , and the end result will be NULL , which is not what you want. minVal设置为NULL ,则所有将来的比较minVal >= i 都不TRUE ,最终结果为NULL ,这不是您想要的。

  3. You collect all values in an array, which will become quite big if you aggregate many rows. 您将所有值收集在一个数组中,如果您聚合许多行,该值将变得非常大。 First this puts you in danger of running out of memory with the array, and then the performance of the aggregate will not be as good as it could be. 首先,这使您面临阵列用尽内存的危险,然后聚合的性能将不尽如人意。

    It is much better to perform the comparison in SFUNC : start with INITCOND = NULL , use STYPE = numeric and perform the aggregation whenever a you process a new value. 最好在SFUNC执行比较:以INITCOND = NULL开头,使用STYPE = numeric并在您处理新值时执行聚合。 The relevant part of SFUNC would look like this: SFUNC的相关部分如下所示:

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

    That way you don't need a FINALFUNC at all. 这样,您根本不需要FINALFUNC

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM