返回与plpgsql函数中的输入数组元素匹配的行

Bri*_*n B 3 arrays postgresql plpgsql aggregate-functions postgresql-9.2

我想创建一个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$
Run Code Online (Sandbox Code Playgroud)

但我在这里看到两个问题:

  1. 我不清楚数组类型是最有用的输入类型.
  2. 当我这样做时,这当前返回零行:

    SELECT avg_purchases($${'Brown','Smith','Jones'}$$);
    
    Run Code Online (Sandbox Code Playgroud)

我错过了什么?

Erw*_*ter 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;
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT * FROM avg_purchases('{foo,Bar,baz,"}weird_name''$$"}');
Run Code Online (Sandbox Code Playgroud)

或者(更新 - 带美元报价的例子):

SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
Run Code Online (Sandbox Code Playgroud)
  • 有关如何引用字符串文字的更多信息:
    在PostgreSQL中插入带单引号的文本

  • 您不需要动态SQL.

  • 虽然你可以把它包装成一个plpgsql函数(这可能很有用),但是一个简单的SQL函数就可以正常工作了.

  • 你有类型不匹配.

    • 结果avg()可能是numeric保持精确的结果.我转而float8使它工作,这只是一个别名double precision(你也可以使用).如果您需要完美的精度,请numeric改用.
    • 既然你GROUP BY last_name想要一个普通的textOUT参数而不是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;
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT * FROM avg_purchases('foo', 'Bar', 'baz', '"}weird_name''$$"}');
Run Code Online (Sandbox Code Playgroud)

或者(以美元报价):

SELECT * FROM avg_purchases('foo', 'Bar', 'baz', $y$'"}weird_name'$$"}$y$);
Run Code Online (Sandbox Code Playgroud)

请注意,标准Postgres 最多只允许100个元素.这是在编译时通过预设选项确定的:

max_function_args (integer)

报告函数参数的最大数量.它由FUNC_MAX_ARGS构建服务器时的值决定.默认值为100个参数.

当前缀为关键字时,您仍然可以使用数组表示法调用它VARIADIC:

SELECT * FROM avg_purchases(VARIADIC '{1,2,3, ... 99,100,101}');
Run Code Online (Sandbox Code Playgroud)

对于更大的数组(100+),我也会unnest()在子查询中使用JOIN它,它往往会更好地扩展: