5

我想创建一个执行以下操作的 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'}$$);
    

我错过了什么?

4

1 回答 1

8

这有效:

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''$$"}');

或者(更新 - 以美元报价为例):

SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
  • 有关如何引用字符串文字的更多信息:
    在 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;

称呼:

SELECT * FROM avg_purchases('foo', 'Bar', 'baz', '"}weird_name''$$"}');

或者(使用美元报价):

SELECT * FROM avg_purchases('foo', 'Bar', 'baz', $y$'"}weird_name'$$"}$y$);

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

max_function_args (integer)

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

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

SELECT * FROM avg_purchases(VARIADIC '{1,2,3, ... 99,100,101}');

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

于 2013-07-31T19:08:13.523 回答