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

时间:2016-06-10 16:56:18

标签: arrays postgresql null plpgsql

我试图在选择查询中的多维数组列(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 $1 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 $1时导致异常:

SELECT reduce_to_percentages(counts) FROM objects;

2 个答案:

答案 0 :(得分:2)

在函数体中只检查参数是否为空。如果要为null参数返回一个空数组,则在declare部分为变量a添加一个初始值(否则该函数将返回null)。

CREATE OR REPLACE FUNCTION public.reduce_to_percentages(int[][])
RETURNS float[] AS
$function$
DECLARE
  s int[];
  a float[] = '{}';     -- initial value
BEGIN
    IF $1 IS NOT NULL THEN
        FOREACH s SLICE 1 IN ARRAY $1 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)是我的函数,返回1-100之间的随机整数。 因此,该表包含一百万行,其中一列包含两个整数的两个数组。 我尝试了尽可能简单的测试和典型的

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

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

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

  • Erwin的功能11940 ms
  • klin的功能4750 ms

也许我的功能是它的鼻子上有口红的猪,但速度很快。

答案 1 :(得分:2)

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

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

相关:

注意:

或者 ,您可以将您的函数声明为STRICT(同义词:RETURNS NULL ON NULL INPUT)。次要差异:它为NULL输入返回NULL,而不是像上面那样返回空数组('{}')。

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

The manual:

  

RETURNS NULL ON NULL INPUTSTRICT表示该功能   每当任何参数为null时,它总是返回null。如果这   指定参数,有时不执行该功能   null参数;而是自动假设空结果。

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