我想创建一个PostgreSQL函数,它可以执行以下操作:
CREATE FUNCTION avg_purchases( IN last_names text[] DEFAULT '{}' )
RETURNS TABLE(last_name text[], avg_purchase_size double precision)
AS
$BODY$
DECLARE
qry text;
BEGIN
qry := 'SELECT last_name, AVG(purchase_size)
FROM purchases
WHERE last_name = ANY($1)
GROUP BY last_name'
RETURN QUERY EXECUTE qry USING last_names;
END;
$BODY$
但我在这里看到两个问题:
当我这样做时,这当前返回零行:
SELECT avg_purchases($${'Brown','Smith','Jones'}$$);
我错过了什么?
答案 0 :(得分:5)
这有效:
CREATE OR REPLACE FUNCTION avg_purchases(last_names text[] = '{}')
RETURNS TABLE(last_name text, avg_purchase_size float8)
AS
$func$
SELECT last_name, AVG(purchase_size)::float8
FROM purchases
WHERE last_name = ANY($1)
GROUP BY last_name
$func$ LANGUAGE sql;
呼叫:
SELECT * FROM avg_purchases('{foo,Bar,baz,"}weird_name''$$"}');
或(更新 - 使用dollar-quoting的示例):
SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
有关如何引用字符串文字的更多信息:
Insert text with single quotes in PostgreSQL
这里不需要动态SQL。
虽然可以将它包装到plpgsql函数中(这可能很有用),但是一个简单的SQL函数就可以正常工作了。
您有类型不匹配。
avg()
的结果可能是numeric
来保存精确的结果。我转向float8
使其工作,这只是double precision
的别名(您可以使用其中任何一个)。如果您需要完美的精度,请改用numeric
。GROUP BY last_name
想要一个简单的text
OUT参数而不是text[]
。VARIADIC
数组是一种有用的输入类型。如果您的客户端更容易,您还可以使用VARIADIC
输入参数,该参数允许将数组作为元素列表传递:
CREATE OR REPLACE FUNCTION avg_purchases(VARIADIC last_names text[] = '{}')
RETURNS TABLE(last_name text, avg_purchase_size float8)
AS
$func$
SELECT last_name, AVG(purchase_size)::float8
FROM purchases
JOIN (SELECT unnest($1)) t(last_name) USING (last_name)
GROUP BY last_name
$func$ LANGUAGE sql
致电:
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', '"}weird_name''$$"}');
或(用美元引用):
SELECT * FROM avg_purchases('foo', 'Bar', 'baz', $y$'"}weird_name'$$"}$y$);
请注意,标准Postgres仅允许最多100个元素。这是在编译时由preset option确定的:
max_function_args (integer)
报告函数参数的最大数量。它由构建服务器时
FUNC_MAX_ARGS
的值确定。默认值为100个参数。
当前缀为关键字VARIADIC
:
SELECT * FROM avg_purchases(VARIADIC '{1,2,3, ... 99,100,101}');
对于更大的数组(100+),我还会在子查询中使用unnest()
并在其中使用JOIN
,这样可以更好地扩展: