我正在尝试在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
我不知道为什么会发生这种情况,在线提供的解决方案都没有帮助我。
答案 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
。
相关答案以及更多详情: