SELECT ... INTO的EXECUTE未实现

时间:2015-10-13 15:32:22

标签: postgresql triggers plpgsql dynamic-sql partitioning

我正在尝试在PostrgeSQL中运行此函数:

CREATE OR REPLACE FUNCTION create_partition_and_insert()
RETURNS trigger AS
$BODY$
DECLARE
partition VARCHAR(25);
_date text;
BEGIN
EXECUTE 'SELECT REPLACE(' || quote_literal(NEW.date) || ',''-'',''_'') into _date';
partition := TG_RELNAME || '_' || _date || ‘p’;
IF NOT EXISTS(SELECT relname FROM pg_class WHERE relname=partition) THEN
RAISE NOTICE 'A partition has been created %',partition;
EXECUTE 'CREATE TABLE ' || partition || ' (check (date = ''' || NEW.date || ''')) INHERITS (' || TG_RELNAME || ');';
END IF;
EXECUTE 'INSERT INTO ' || partition || ' SELECT(' || TG_RELNAME || ' ' || quote_literal(NEW) || ').*;';
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql;

但是在运行时我得到的是错误:

ERROR:  EXECUTE of SELECT ... INTO is not implemented
HINT:  You might want to use EXECUTE ... INTO or EXECUTE CREATE TABLE ... AS instead.
CONTEXT:  PL/pgSQL function create_partition_and_insert() line 6 at EXECUTE statement

我不知道为什么会发生这种情况,在线提供的解决方案都没有帮助我。

2 个答案:

答案 0 :(得分:12)

而不是

execute 'select 1 into i'    -- error

你应该使用

execute 'select 1' into i

答案 1 :(得分:4)

错误消息是此函数中最少的问题。考虑完全重写。

假设列date实际上是数据类型date

CREATE OR REPLACE FUNCTION create_partition_and_insert()
  RETURNS trigger AS
$func$
DECLARE
   _partition text := quote_ident(TG_RELNAME
                               || to_char(NEW.date,'_YYYY_MM_DD"p"'));
BEGIN
   IF NOT EXISTS(SELECT relname FROM pg_class WHERE relname = _partition) THEN
      EXECUTE format('CREATE TABLE %s (CHECK (date = %L)) INHERITS (%I);'
                   , _partition, NEW.date, TG_RELNAME);

      RAISE NOTICE 'A new partition has been created: %', _partition;
   END IF;

   EXECUTE format('INSERT INTO %s SELECT ($1).*', _partition)
   USING NEW;

   RETURN NULL;
END
$func$  LANGUAGE plpgsql;

重点

  • 您根本不需要第一个语句中的动态SQL(源或语法错误)。实际上,您不需要整个语句也不需要变量。我从根本上简化了名称连接。 Details for to_char() in the manual.

  • 忽略‘p’中的印刷引号 - 这些可能只是c / p文物。

  • 在plpgsql中,赋值相对较贵。调整您的编程风格并减少变量和分配。

  • 不要将整行转换为文本表示,连接然后再将其转换回来。这是不必要的昂贵,复杂和容易出错。将直接传递到USING子句中,如EXECUTE所示。

  • 请勿在通知完成前提出通知。如果异常导致可能误导日志条目,则不会回滚RAISE

  • 如果您的数据库中有多个架构(这很常见),那么您的代码仍然不安全。您需要对表名进行架构限定,或SET为函数search_path

相关答案以及更多详情: