2

按照这个问题的建议,我正在使用该to_regclass函数来检查表是否存在,如果不存在则创建它。但是,如果表是在当前事务中创建的,似乎to_regclass仍然返回null

这种行为是预期的吗?或者这是一个错误?

细节

这是一个错误的简短示例:

begin;
create schema test;
create table test.test ( id serial, category integer );

create or replace function test.test_insert () returns trigger as $$
declare
    child_table_name text;
    table_id     text;
begin
    child_table_name = concat('test.test_', text(new.category));
    table_id = to_regclass(child_table_name::cstring);
    if table_id is null then
        execute format('create table %I ( primary key (id), check ( category = %L ) ) inherits (test.test)', child_table_name, new.category);
    end if;
    execute format ('insert into %I values ($1.*)', child_table_name) using new;
    return null;
end;
$$ language plpgsql;

create trigger test_insert before insert on test.test for each row execute procedure test.test_insert();

insert into test.test (category) values (1);
insert into test.test (category) values (1);
insert into test.test (category) values (1);
commit;
4

1 回答 1

2

%I错误地使用了格式说明符。

如果您的类别是1,那么您最终会调用to_regclass('test.test_1'),即检查test_1模式中的表test

但是,format('create table %I', 'test.test_1')会将格式参数视为单个标识符并相应地引用它,评估为'create table "test.test_1"'. 这将创建一个"test.test_1"在您的默认架构中调用的表(可能public)。

相反,您需要将架构和表名视为单独的标识符。将您的表名定义为:

child_table_name = format('test.%I', 'test_' || new.category);

...并且在构建 SQL 字符串时,只需直接替换此值(即用%s而不是%I)。

于 2016-09-15T22:05:43.893 回答