以多维数组为参数的plpgsql函数

plpgsql function taking a multi-dimensional array as parameter

我正在尝试 运行 在 select 查询中的多维数组列 (int[][]) 上使用 plpgsql 函数。

函数是这样的:

CREATE OR REPLACE FUNCTION public.reduce_to_percentages(int[][])
RETURNS float[] AS
$function$
DECLARE
  s int[];
  a float[];
BEGIN
    FOREACH s SLICE 1 IN ARRAY  LOOP
        a := a || s[2]::float / s[1]::float;
    END LOOP;
    RETURN a;
END;
$function$
LANGUAGE plpgsql VOLATILE;

以下查询有效:

SELECT reduce_to_percentages(ARRAY[ARRAY[100, 20], ARRAY[300, 50]]);

以下查询也是如此:

SELECT reduce_to_percentages((SELECT counts FROM objects LIMIT 1));

但以下查询为函数提供了一个 null 值,并在尝试 FOREACH 超过 </code> 时导致异常:</p> <pre><code>SELECT reduce_to_percentages(counts) FROM objects;

在函数体中检查参数是否不为空。如果你想 return 一个空数组作为空参数,那么在声明部分为变量 a 添加一个初始值(否则函数将 return 为空)。

CREATE OR REPLACE FUNCTION public.reduce_to_percentages(int[][])
RETURNS float[] AS
$function$
DECLARE
  s int[];
  a float[] = '{}';     -- initial value
BEGIN
    IF  IS NOT NULL THEN
        FOREACH s SLICE 1 IN ARRAY  LOOP
            a := a || s[2]::float / s[1]::float;
        END LOOP;
    END IF;
    RETURN a;
END;
$function$
LANGUAGE plpgsql VOLATILE;

我做了一个简单的测试。这是一个适度的设置:

create table test (val int[]);
insert into test
select (array[array[ri(100), ri(100)], array[ri(100), ri(100)]])
from generate_series(1, 1000000);

ri(100) 是我的函数 returning 1-100 之间的随机整数。 因此 table 包含一百万行,其中一列包含两个整数数组。 我尝试让测试尽可能简单和 典型

以下查询已使用 Erwin 函数执行 10 次,使用我的变体执行 10 次:

select sum(v[1]), sum(v[2])
from (
    select reduce_to_percentages(val) v
    from test
    ) s;

十次测试的平均执行时间:

  • 欧文函数 11940 毫秒
  • klin 函数 4750 毫秒

也许我的函数是一只鼻子上涂了口红的猪,但它是一个快速的。

可以 通过检查 NULL.
来修复错误 但那是给猪涂口红。重写函数以用基于集合的解决方案替换程序循环。通常更快(尤其是在外部查询的上下文中使用时)、更简单且自动空安全:

CREATE OR REPLACE FUNCTION public.reduce_to_percentages(int[])
  RETURNS float[] AS
$func$
SELECT ARRAY (SELECT [d][2]::float / [d][1]
              FROM   generate_subscripts(,1) d)
$func$  LANGUAGE sql IMMUTABLE;

相关:

  • Unnest array by one level

备注:

  • 股息投到float就足够了。 float / integer returns float 自动。

  • 没有数据类型int[][]。就 int[]。 Postgres 允许这种表示法,但忽略数组类型的附加数组维度,因为数据类型本身对于所有维度都是相同的。详情:

    • mapping postgresql text[][] type and Java type
  • 使函数 IMMUTABLE(因为它 )以获得更好的性能并允许索引。相关:

    • Does PostgreSQL support "accent insensitive" collations?

或者,您可以将函数声明为STRICT(同义词:RETURNS NULL ON NULL INPUT)。细微差别:它 returns NULL 用于 NULL 输入,而不是像上面那样的空数组 ('{}')。

CREATE OR REPLACE FUNCTION public.reduce_to_percentages(int[][])
  RETURNS float[] AS
$function$
 ...
$function$ LANGUAGE plpgsql IMMUTABLE <b>STRICT</b>;

The manual:

RETURNS NULL ON NULL INPUT or STRICT indicates that the function always returns null whenever any of its arguments are null. If this parameter is specified, the function is not executed when there are null arguments; instead a null result is assumed automatically.

但出于多种原因,上面的简单 SQL 函数更可取。