PL/pgSQL 中的 EXECUTE...USING 中忽略了 USING 部分

Posted

技术标签:

【中文标题】PL/pgSQL 中的 EXECUTE...USING 中忽略了 USING 部分【英文标题】:USING section ignored in EXECUTE...USING in PL/pgSQL 【发布时间】:2014-05-21 08:36:59 【问题描述】:

我尝试通过 EXECUTE..USING 动态创建一个序列,但将参数传递给它时遇到问题。根据documentation,我理解正确的形式应该是这样的:

CREATE OR REPLACE FUNCTION create_dyn_seq( /* some params */ ) 
RETURNS void AS $$
DECLARE
  _seq_name text;
  _min integer;
  _max integer;
BEGIN
  /*
    some code assigning the variables
    sample values:
    _seq_name := 'hu01/1/0_seq';
    _min := 101;
    _max := 500;
  */    
  EXECUTE 'CREATE SEQUENCE "' || _seq_name || '" MINVALUE $1 MAXVALUE $2 ' 
  USING _min::INT, _max::INT;
  RETURN;
END;
$$ LANGUAGE plpgsql;

我添加了引号,_seq_name 本身似乎很好。但是,当我插入这些值时,会引发以下错误:

ERROR:  syntax error at or near "$1"
LINE 1: CREATE SEQUENCE "hu01/1/0_seq" MINVALUE $1 MAXVALUE $2 

我还尝试了 EXECUTE 的另一种语法,建议 here:

EXECUTE 
  'CREATE SEQUENCE "' || _seq_name || '" MINVALUE ' || $1 || ' MAXVALUE ' || $2  
  USING _min::INT, _max::INT;

现在错误不同了:

ERROR:  syntax error at or near "hu01"
LINE 1: CREATE SEQUENCE "hu01/1/0_seq" MINVALUE hu01 MAXVALUE 1

美元符号现在可以转换,但 USING 部分中的变量被 _seq_name 变量的一部分覆盖。我尝试用下划线替换序列名称中的斜杠,但没有任何改变。

我也按照here的建议通过format()结合USING进行了尝试,但没有任何改变,出现同样的错误:

EXECUTE format('CREATE SEQUENCE %I MINVALUE $1 MAXVALUE $2 ', _seq_name) 
USING _min::INT, _max::INT;

EXECUTE format('CREATE SEQUENCE %I MINVALUE ' || $1 || ' MAXVALUE ' || $2, _nazev_seq) 
USING _min::INT, _max::INT;

然后我用 format() 参数完全替换了 USING 部分:

EXECUTE format('CREATE SEQUENCE %I MINVALUE %L MAXVALUE %L ', _seq_name, _min::INT, _max::INT);

现在我几乎到了我想去的地方,错误是不同的:

ERROR:  syntax error at or near "'101'"
LINE 1: CREATE SEQUENCE "hu01/1/0_seq" MINVALUE '101' MAXVALUE '500'...

我在“how to use integer within FORMAT()”上发现了一个问题,其中一个答案建议%s。现在可以了:

EXECUTE format('CREATE SEQUENCE %I MINVALUE %s MAXVALUE %s ', _seq_name, _min, _max);

但是,the other answer 建议在 USING 部分中包含整数,如果没有错误,我会这样做。我的“解决方案”感觉是一个肮脏的解决方法,我想把它做对,所以我的问题是:

为什么 USING 部分和美元符号转义值对我不起作用?

【问题讨论】:

这是有意的。 参数符号的另一个限制是它们只能在 SELECT、INSERT、UPDATE 和 DELETE 命令中使用。 postgresql.org/docs/current/static/… 【参考方案1】:
EXECUTE 'CREATE SEQUENCE "' || _seq_name || '" MINVALUE $1 MAXVALUE $2 ' 
USING _min::INT, _max::INT;

这不起作用,因为参数替换将起作用only within SELECT, INSERT, UPDATE, and DELETE commands:

对参数符号的另一个限制是它们只能在 SELECT、INSERT、UPDATE 和 DELETE 命令中使用。只有这些语句有执行计划,只有这些语句应该被参数化。

EXECUTE 'CREATE SEQUENCE "' || _seq_name || '" MINVALUE ' || $1 || ' MAXVALUE ' || $2  
USING _min::INT, _max::INT;

这行不通,因为在那种情况下$1 指的是函数的1st argument。

EXECUTE format('CREATE SEQUENCE %I MINVALUE %L MAXVALUE %L ', _seq_name, _min::INT, _max::INT);

这不起作用,因为CREATE SEQUENCE 语句的MINVALUEMAXVALUE 选项都只接受整数,而不接受文本(并且不会在ddl 中进行隐式转换)。

EXECUTE format('CREATE SEQUENCE %I MINVALUE %s MAXVALUE %s ', _seq_name, _min, _max);

只要_min & _max 是某种类型的整数,这是完全安全的。如果不是,请在此处使用显式强制转换。

【讨论】:

以上是关于PL/pgSQL 中的 EXECUTE...USING 中忽略了 USING 部分的主要内容,如果未能解决你的问题,请参考以下文章

循环通过 PL/PGSQL 中的 CURSOR 而不锁定表

PL/pgSQL 函数中的可选参数

执行 SELECT 语句并丢弃 PL/pgSQL 中的结果

PL/pgSQL 中的 EXECUTE...USING 中忽略了 USING 部分

如何在 PL/pgSQL 中的动态选择查询中使用迭代器变量?

PostgreSQL PL/pgSQL:存储在表中的查询(营业时间)