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_1test

ただし、format('create table %I', 'test.test_1')format 引数を単一の識別子として扱い、それに応じて引用符を付けて、 に評価し'create table "test.test_1"'ます。"test.test_1"これにより、デフォルトのスキーマ (おそらく) で呼び出されるテーブルが作成されますpublic

代わりに、スキーマ名とテーブル名を個別の識別子として扱う必要があります。テーブル名を次のように定義します。

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

%s... SQL 文字列を作成するときは、この値を直接 (つまりではなく で)置き換えてください%I

于 2016-09-15T22:05:43.893 に答える