Postgres plpgsql - 在动态创建语句中使用变量

Jmo*_*y38 11 postgresql dynamic-sql plpgsql

使用 Postgres pl/pgsql,我尝试使用动态 EXECUTE 命令创建一个表,例如:

 ...
 DECLARE
    tblVar varchar := "myTable";
 BEGIN
 EXECUTE 'CREATE TABLE $1 ( 
             foo integer NOT NULL, 
             bar varchar NOT NULL)'
 USING _tblVar;
 ...
Run Code Online (Sandbox Code Playgroud)

但是,我继续收到错误消息

错误:“$1”处或附近的语法错误

如果我不使用$1令牌,而是编写字符串,myTable它就可以正常工作。

对 CREATE 调用使用动态语句是否有限制?

Erw*_*ter 8

除了@filiprem 所写的内容之外,以下是您正确执行此操作的方法:

...
DECLARE
   tbl_var text := 'myTable';   -- I would not use mixed case names ..
BEGIN
EXECUTE '
CREATE TABLE ' || quote_ident(tbl_var) || '( 
   foo integer NOT NULL, 
   bar text NOT NULL)';
...
Run Code Online (Sandbox Code Playgroud)

使用quote_ident()以避免SQL注入或语法错误。它将引用带有非标准字符或保留字的名称。

我还用单引号替换了示例中字符串值周围的双引号


fil*_*rem 5

请参阅http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

请注意,参数符号只能用于数据值——如果要使用动态确定的表名或列名,则必须以文本方式将它们插入到命令字符串中。例如,如果需要针对动态选择的表执行前面的查询,则可以执行以下操作:

EXECUTE 'SELECT count(*) FROM '
    || tabname::regclass
    || ' WHERE inserted_by = $1 AND inserted <= $2'
   INTO c
   USING checked_user, checked_date;
Run Code Online (Sandbox Code Playgroud)

正如下面的评论中所指出的,强制转换方法并不总是可行的,尤其是对于 CREATE 语句。考虑format函数,例如:

EXECUTE format(
  'CREATE TABLE %I (%I %I, %I %I)',
  v_tabname,
  v_col1name, v_col1type,
  v_col2name, v_col2type);
Run Code Online (Sandbox Code Playgroud)

换句话说:

是的,有这样的限制。您不能为表/列名称使用参数 - 那是因为 Postgresql 需要能够在编译动态 SQL 语句时解析查询。解析器必须能够识别使用的关系。

旁注:可能此限制适用于其他 DBMS 中的动态 SQL,包括 Oracle:http : //download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDHGHIF