编写自定义聚合函数
Writing a custom aggregate function
最近我一直在练习和学习PL/pgSQL。我坚持创建自定义聚合函数。
下面的代码工作得很好,但我无法编写这种类型的聚合函数:
SELECT my_aggregate_function(column) from table;
这是"partially working custom aggregate"的代码:
CREATE OR REPLACE FUNCTION searchMinValue (numeric[]) RETURNS numeric AS $$
DECLARE
i numeric;
minVal numeric;
BEGIN
minVal := [1];
IF ARRAY_LENGTH(,1) > 0 THEN --Checking whether the array is empty or not
<<confrontoMinimo>>
FOREACH i IN ARRAY 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',;
--Raising exception if the parameter passed as argument points to null.
RAISE EXCEPTION 'Cannot find Max value. Parameter % is null',
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;
其中 table 是 Customers
并且该列是 salary
类型 numeric
。
你基本上做对了,但你的实现仍然存在一些问题:
如果 table 为空,您的聚合将出错。相反,它应该 return NULL
.
如果您聚合的第一个值是 NULL
,您的聚合将做错事。如果
minVal := [1];
将minVal
设置为NULL
,那么以后所有的比较minVal >= i
都会不是是TRUE
,最后的结果将是 NULL
,这不是您想要的。
您将所有值收集在一个数组中,如果您聚合许多行,该数组将变得非常大。首先,这会使您面临 运行 数组内存不足的危险,然后聚合的性能将达不到应有的水平。
在 SFUNC
中执行比较要好得多:从 INITCOND = NULL
开始,使用 STYPE = numeric
并在处理新值时执行聚合。 SFUNC
的相关部分如下所示:
IF IS NULL OR >
RETURN ;
ELSE
RETURN ;
END IF;
这样你就根本不需要 FINALFUNC
。
最近我一直在练习和学习PL/pgSQL。我坚持创建自定义聚合函数。
下面的代码工作得很好,但我无法编写这种类型的聚合函数:
SELECT my_aggregate_function(column) from table;
这是"partially working custom aggregate"的代码:
CREATE OR REPLACE FUNCTION searchMinValue (numeric[]) RETURNS numeric AS $$
DECLARE
i numeric;
minVal numeric;
BEGIN
minVal := [1];
IF ARRAY_LENGTH(,1) > 0 THEN --Checking whether the array is empty or not
<<confrontoMinimo>>
FOREACH i IN ARRAY 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',;
--Raising exception if the parameter passed as argument points to null.
RAISE EXCEPTION 'Cannot find Max value. Parameter % is null',
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;
其中 table 是 Customers
并且该列是 salary
类型 numeric
。
你基本上做对了,但你的实现仍然存在一些问题:
如果 table 为空,您的聚合将出错。相反,它应该 return
NULL
.如果您聚合的第一个值是
NULL
,您的聚合将做错事。如果minVal := [1];
将
minVal
设置为NULL
,那么以后所有的比较minVal >= i
都会不是是TRUE
,最后的结果将是NULL
,这不是您想要的。您将所有值收集在一个数组中,如果您聚合许多行,该数组将变得非常大。首先,这会使您面临 运行 数组内存不足的危险,然后聚合的性能将达不到应有的水平。
在
SFUNC
中执行比较要好得多:从INITCOND = NULL
开始,使用STYPE = numeric
并在处理新值时执行聚合。SFUNC
的相关部分如下所示:IF IS NULL OR > RETURN ; ELSE RETURN ; END IF;
这样你就根本不需要
FINALFUNC
。