3

我正在尝试在 PostgreSQL 中创建新的聚合函数来代替sum()函数

我从这里的手册开始了我的旅程。

因为我想创建一个函数,它接受一个双精度值数组,对它们求和,然后做一些额外的计算,我首先创建了最终函数:

takes double precision as input and gives double precision as output    
DECLARE
      v double precision;
BEGIN
      IF tax > 256 THEN
            v := 256;
      ELSE
            v := tax;
      END IF;
      RETURN v*0.21/0.79;
END;

然后我想创建一个聚合函数,它接受一个双精度值数组,并为我之前的函数处理一个单一的双精度值。

CREATE AGGREGATE aggregate_ee_income_tax (float8[]) (
  sfunc = array_agg
 ,stype = float8
 ,initcond = '{}'
 ,finalfunc = eeincometax);

当我运行该命令时,我得到的是:

错误:函数array_agg(双精度,双精度[])不存在

我有点卡在这里,因为手册将array_agg()列为现有函数。我究竟做错了什么?

另外,当我运行时:

\da
                     List of aggregate functions
 Schema | Name | Result data type | Argument data types | Description 
--------+------+------------------+---------------------+-------------
(0 rows)

我的安装根本没有聚合函数?还是只列出用户定义的函数?

基本上我想了解的是:

1)我可以使用现有函数来总结我的数组值吗?

2) 我怎样才能知道函数的输入和输出数据类型?Docs 声称可以array_agg()接受任何类型的输入。

3)我自己的聚合函数有什么问题?

编辑 1

为了提供更多信息和更清晰地了解我正在努力实现的目标:

我对几个表有一个巨大的查询,如下所示:

SELECT sum(tax) ... from (SUBQUERY) as foo group by id

我想用我自己的聚合函数替换那个 sum 函数,这样我就不必在后端进行额外的计算——因为它们都可以在数据库级别完成。

编辑 2

接受蚂蚁的回答。由于最终解决方案来自评论,因此我将其发布在这里以供参考:

CREATE AGGREGATE aggregate_ee_income_tax (float8)
(
 sfunc = float8pl
,stype = float8
,initcond = '0.0'
,finalfunc = eeincometax
);
4

2 回答 2

3

数组 agg 是聚合函数而不是常规函数,因此不能用作新聚合的状态转换函数。您要做的是创建一个聚合函数,该函数具有与 array_agg 相同的状态转换函数和自定义最终函数。

不幸的是,array_agg 的状态转换函数是根据内部数据类型定义的,因此不能重用。幸运的是,核心中有一个现有功能已经可以满足您的需求。

CREATE AGGREGATE aggregate_ee_income_tax (float8)(
    sfunc = array_append,
    stype = float8[],
    initcond = '{}',
    finalfunc = eeincometax);

另请注意,您的类型混淆了,您可能希望将一组浮点数聚合到一个数组,而不是将一组数组聚合到一个浮点数。

于 2012-09-13T08:31:50.977 回答
3

除了@Ants 出色的建议:

1.)您的最终功能可以简化为:

CREATE FUNCTION eeincometax(float8)
  RETURNS float8 LANGUAGE SQL AS
$func$
SELECT (least($1, 256) * 21) / 79
$func$;

2.) 好像你在处理金钱?在这种情况下,我强烈建议使用类型numeric(首选)或money用于该目的。浮点运算通常不够精确。

3.) 聚合的初始条件可以简单地为0

CREATE AGGREGATE aggregate_ee_income_tax(float8)
(
  sfunc     = float8pl
 ,stype     = float8
 ,initcond  = 0
 ,finalfunc = eeincometax
);

4.)在您的情况下(least(sum(tax), 256) * 21) / 79可能比您的自定义聚合更快。PostgreSQL 提供的聚合函数是用 C 语言编写的,并针对性能进行了优化。我会用它来代替。

于 2012-09-14T19:37:23.690 回答