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

时间:2013-07-31 18:41:02

标签: arrays postgresql aggregate-functions plpgsql 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$

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

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

    SELECT avg_purchases($${'Brown','Smith','Jones'}$$);
    
  3. 我错过了什么?

1 个答案:

答案 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,这样可以更好地扩展: