EXECUTE of SELECT ... INTO 未实现

EXECUTE of SELECT ... INTO is not implemented

我正在尝试 运行 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

我不知道为什么会这样,none 在线提供的解决方案对我有帮助。

而不是

execute 'select 1 into i'    -- error

你应该使用

execute 'select 1' into i

错误信息是这个函数中最少的问题。考虑完全重写。

假设列 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 ().*', _partition)
   USING NEW;

   RETURN NULL;
END
$func$  LANGUAGE plpgsql;

要点

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

  • 忽略 ‘p’ 中的印刷引号 - 这些可能只是 c/p 人工制品。

  • plpgsql 中的赋值相对昂贵。调整您的编程风格并减少变量和赋值。

  • 不要将整行转换为其文本表示形式,连接然后再将其转换回去。这是不必要的昂贵、复杂和容易出错的。将 value 直接在 USING 子句中传递给 EXECUTE,就像演示的那样。

  • 在完成之前不要发出通知。 RAISE 在出现可能导致误导性日志条目的异常情况下不会回滚。

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

更详细的相关答案:

  • How to check if a table exists in a given schema

  • Creating a trigger for child table insertion returns confusing error

  • INSERT with dynamic table name in trigger function

  • How does the search_path influence identifier resolution and the "current schema"