【问题标题】:Return rows matching elements of input array in plpgsql function在 plpgsql 函数中返回匹配输入数组元素的行
【发布时间】:2013-08-01 10:43:09
【问题描述】:

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

我错过了什么?

【问题讨论】:

  • 在返回类型中使用 text[] 是一个错字。我把它留在这里是因为接受的答案提到了这个错误。
  • 原来另一个大错误是调用语法(根据@Erwin的帖子纠正问题后)需要SELECT avg_purchases($${Brown,Smith,Jones}$$)SELECT avg_purchases('{Brown,Smith,Jones}')

标签: arrays postgresql aggregate-functions plpgsql postgresql-9.2


【解决方案1】:

这行得通:

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

【讨论】:

  • 实际上这些在实践中将是大数组,所以我特别热衷于您的 unnest() 建议。
猜你喜欢
  • 2021-07-06
  • 1970-01-01
  • 2012-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-16
  • 1970-01-01
  • 2013-01-22
相关资源
最近更新 更多