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