0

我们可以在不使用的情况下在 PostgreSQL 函数中进行选择EXECUTE吗?我正在尝试使用quote_ident()创建动态 SQL,但它不起作用。

CREATE OR REPLACE FUNCTION select_server(p_id text)
RETURNS integer AS $$ 
DECLARE 
   serialnum_value INTEGER; 
   STATEMENT TEXT;
BEGIN
  STATEMENT := 'tbl' || substr($1, 1, 4);  
  SELECT serialnum INTO serialnum_value FROM quote_ident(STATEMENT ) WHERE id = $1;
  RETURN serialnum;
END;

有人知道如何在不使用的情况下从 PostgreSQL 函数中的动态表中进行选择EXECUTE吗?

4

2 回答 2

1

根据 igor 的评论,您无法避免在这里执行。最好的替代方法是创建一个创建函数的函数,然后您可以根据需要调用该函数。例子:

create function gen_select_server(p_id text)
  returns boolean
as $gen$
begin
  execute $exec$
  create function $exec$ || quote_ident('select_server_' || p_id) || $exec$
    returns integer
  as $body$
  begin
    return serialnum
    from $exec$ || quote_ident('tbl_' || p_id) || $exec$
    where id = $exec$ || quote_literal('id_' || p_id) || $exec$;
  end;
  $body$ language plpgsql;
  $exec$;
  return true;
end;
$gen$ language plpgsql;

-- usage:
select gen_select_server('1234');   -- call this only once; uses execute
select * from select_server_1234(); -- no execute here

正如上面所强调的,它可能会与字符串分隔符混淆。另请注意,以上不是您的原始功能-主要是为了说明如何在大$exec$“字符串”块中正确引用事物。

据说,我建议坚持使用执行。或者使用 ORM,就此而言。维持这些微优化可能比表面上的性能提升更痛苦。

于 2013-10-02T12:45:28.513 回答
1

没有PL/pgSQL就无法执行动态 SQL EXECUTE。这就是让它首先充满活力的原因。

但是您可以大大简化您的功能:

CREATE OR REPLACE FUNCTION select_server(p_id text, OUT serial_value integer) AS
$func$ 
BEGIN
   EXECUTE 'SELECT serialnum FROM tbl' || left($1::text, 4)) || ' WHERE id = $1'
   USING $1
   INTO  serial_value;
END
$func$ LANGUAGE plpgsql STRICT;
  • 通常,您必须清理任何标识符。
    但是在这种特殊情况下您不需要 quote_ident(),因为唯一的动态组件是来自integer. SQL 注入和非法标识符都不可能以这种方式进行。

  • 使用子句将作为值传递。p_idUSING

  • 减少任务数量。这些在 plpgsql 中相对昂贵。您只需要一条 SQL 语句即可完成所有操作。

  • OUT参数有助于缩短语法。

  • 我还创建了函数STRICT( ),因为它作为输入RETURNS NULL ON NULL INPUT没有意义。NULL

  • left()比 略快substr()

于 2013-10-02T13:01:06.180 回答