我正在尝试用可选参数编写PL / pgSQL函数。它根据过滤的记录集(如果指定)执行查询,否则对表中的整个数据集执行查询。
例如(PSEUDO CODE):
CREATE OR REPLACE FUNCTION foofunc(param1 integer, param2 date, param2 date, optional_list_of_ids=[]) RETURNS SETOF RECORD AS $$
IF len(optional_list_of_ids) > 0 THEN
RETURN QUERY (SELECT * from foobar where f1=param1 AND f2=param2 AND id in optional_list_of_ids);
ELSE
RETURN QUERY (SELECT * from foobar where f1=param1 AND f2=param2);
ENDIF
$$ LANGUAGE SQL;
实现此功能的正确方法是什么?
顺便说一句,我想知道如何在另一个外部函数中调用这样的函数。我就是这样做的 - 它是正确的,还是有更好的方法?
CREATE FUNCTION foofuncwrapper(param1 integer, param2 date, param2 date) RETURNS SETOF RECORD AS $$
BEGIN
CREATE TABLE ids AS SELECT id from foobar where id < 100;
RETURN QUERY (SELECT * FROM foofunc(param1, param2, ids));
END
$$ LANGUAGE SQL
答案 0 :(得分:42)
自PostgreSQL 8.4(您似乎正在运行)以来,有default values for function parameters。如果您将参数设置为最后并提供默认值,则可以在调用中忽略它:
CREATE OR REPLACE FUNCTION foofunc(_param1 integer
, _param2 date
, _ids int[] DEFAULT '{}')
RETURNS SETOF foobar AS -- declare return type!
$func$
BEGIN -- required for plpgsql
IF _ids <> '{}'::int[] THEN -- exclude empty array and NULL
RETURN QUERY
SELECT *
FROM foobar
WHERE f1 = _param1
AND f2 = _param2
AND id = ANY(_ids); -- "IN" is not proper syntax for arrays
ELSE
RETURN QUERY
SELECT *
FROM foobar
WHERE f1 = _param1
AND f2 = _param2;
END IF;
END -- required for plpgsql
$func$ LANGUAGE plpgsql;
主要观点:
关键字DEFAULT
用于声明参数默认值。简短替代方案:=
。
我从凌乱的示例中删除了多余的param1
。
由于您返回SELECT * FROM foobar
,请将返回类型声明为RETURNS SETOF foobar
而不是RETURNS SETOF record
。具有匿名记录的后一种形式非常笨拙,您必须在每次调用时提供列定义列表。
我使用整数(int[]
)数组作为函数参数。相应地调整了IF
表达式和WHERE
子句。
IF
语句在纯SQL中不可用。必须是LANGUAGE plpgsql
。
使用或不使用_ids
:
SELECT * FROM foofunc(1, '2012-1-1'::date);
实际上相同:
SELECT * FROM foofunc(1, '2012-1-1'::date, '{}'::int[]);
您必须确保通话明确无误。如果你有另一个同名和两个参数的函数,Postgres可能不知道要选哪个。显式演员(就像我演示的那样)缩小了它。否则,无类型的字符串文字也可以工作,但显式永远不会伤害。
从另一个函数中调用:
CREATE FUNCTION foofuncwrapper(_param1 integer, _param2 date)
RETURNS SETOF foobar AS
$func$
DECLARE
_ids int[] := '{1,2,3}';
BEGIN
-- irrelevant stuff
RETURN QUERY
SELECT * FROM foofunc(_param1, _param2, _ids);
END
$func$ LANGUAGE plgpsql;
答案 1 :(得分:3)
在这个帖子上阐述Frank的回答:
VARIADIC
文章并不是唯一的论据,只是最后一个。
您可以将VARIADIC
用于可能采用零可变参数的函数,它只需要一点点小费,因为它需要一个不同的调用样式来实现零参数。你可以提供一个包装函数来隐藏丑陋。给出一个初始的varardic函数定义,如:
CREATE OR REPLACE FUNCTION foofunc(param1 integer, param2 date, param2 date, optional_list_of_ids VARIADIC integer[]) RETURNS SETOF RECORD AS $$
....
$$ language sql;
对于零参数,请使用如下的包装器:
CREATE OR REPLACE FUNCTION foofunc(integer, date, date) RETURNS SETOF RECORD AS $body$
SELECT foofunc($1,$2,$3,VARIADIC ARRAY[]::integer[]);
$body$ LANGUAGE 'sql';
或者直接用VARIADIC '{}'::integer[]
这样的空数组调用主func。包装纸很难看,但包含丑陋,所以我建议使用包装纸。
可以以可变形式进行直接调用:
SELECT foofunc(1,'2011-01-01','2011-01-01', 1, 2, 3, 4);
...或带有数组ctor的数组调用表单:
SELECT foofunc(1,'2011-01-01','2011-01-01', VARIADIC ARRAY[1,2,3,4]);
...或数组文本文字形式:
SELECT foofunc(1,'2011-01-01','2011-01-01', VARIADIC '{1,2,3,4}'::int[]);
后两种形式适用于空数组。
答案 2 :(得分:1)
你的意思是SQL Functions with Variable Numbers of Arguments?如果是这样,请使用VARIADIC。