如何在函数内部取消数组?

时间:2017-06-22 20:43:29

标签: arrays postgresql plpgsql

create or replace function pd.check(
    interval_ text[]) 

returns void as

$BODY$
BEGIN

EXECUTE '
drop table if exists check_;
create temp table check_ 
as
(
    select unnest(' || interval_ || ')
) ;
';
END;
$BODY$
LANGUAGE PLPGSQL volatile;

我正在以

运行它
select pd.check(ARRAY['2','3','4']);

它给了我一个错误:

  

运算符不是唯一的:未知||文本[]

     

提示:无法选择最佳候选运营商。您可能需要添加显式类型转换。

3 个答案:

答案 0 :(得分:2)

假设当前的Postgres 9.6,你的功能将如下:

CREATE OR REPLACE FUNCTION pd.check(interval_ text[]) 
  RETURNS void AS
$func$
BEGIN
   EXECUTE '
      DROP TABLE IF EXISTS pg_temp.check_;
      CREATE TEMP TABLE check_  AS
      SELECT unnest($1)'
   USING $1;                                -- pass as value
END
$func$  LANGUAGE plpgsql;

注释

  • 可以将参数值连接为字符串,但是您需要显式类型转换(因为连接无类型字符串文字text[]对Postgres来说是不明确的,它可能产生texttext[],因此错误!)并转义特殊字符以使其工作。 quote_literal()同时执行:quote_literal(interval_)。不过, 。 而是将参数传递为 ,而不是字符串。这样更快,更安全,并避免出现任何此类错误 请注意,命令字符串中的$1是指USING子句提供的第一个表达式,而不是函数参数。 $1的第二个实例实际上是指函数参数(不同的范围!)。

  • 注意,这种将值传递给DML语句的优越方式在这里起作用,因为它是包含的SELECT语句的一部分,但不适用于其他实用程序命令。详细说明:

  • 函数中的
  • drop table check_; 危险 。显然你想要定位临时表。但如果不存在,则search_path中的下一个同名表将被删除。潜在的灾难性损害。要定位临时表而不是其他目标,使用伪名称pg_temp进行架构限定。

  • CREATE TABLE AS围绕以下SELECT命令不需要括号。

  • VOLATILE是默认设置(对于此功能是正确的),我省略了噪音。

在这种特殊情况下,您不需要动态SQL。见@klin's answer。但EXECUTE仍然是计划缓存无法获得的查询的理想选择。

答案 1 :(得分:1)

您不需要动态SQL(执行):

create or replace function pd.check(interval_ text[]) 
returns void as
$body$
begin
    drop table if exists check_;
    create temp table check_
    as select unnest(interval_);
end;
$body$
language plpgsql volatile;

测试:

select pd.check(array['2','3','4']);
select * from check_;

 unnest 
--------
 2
 3
 4
(3 rows)    

答案 2 :(得分:1)

这与其他答案类似,但你真的不应该使用RETURNS VOID;你应该从函数本身返回一个集合。

[["2017/04/23", 972.5], ["2017/04/30", 2049],...

我做出的其他改变:

  1. 您不应该在与列本身不同的数据类型之后命名列,因此将interval_更改为interval_。
  2. 该功能实际上是IMMUTABLE,而不是VOLATILE,原样。