2

問題: Postgresql では、テーブルtemp_person_twoが から継承されている場合、テーブルが変更さtemp_personれると、子テーブルのデフォルトの列値が無視されます。

複製方法:

まず、テーブルと子テーブルを作成します。子テーブルには、デフォルト値を持つ 1 つの列が必要です。

CREATE TEMPORARY TABLE temp_person (
    person_id SERIAL,
    name      VARCHAR
);

CREATE TEMPORARY TABLE temp_person_two (
    has_default character varying(4) DEFAULT 'en'::character varying NOT NULL
) INHERITS (temp_person);

次に、データを子テーブルにコピーするトリガーを親テーブルに作成します (これは悪い設計のように見えますが、これは問題を示すための最小限のテスト ケースです)。

CREATE FUNCTION temp_person_insert() RETURNS trigger
LANGUAGE plpgsql
AS '
BEGIN
INSERT INTO temp_person_two VALUES ( NEW.* );
RETURN NULL;
END;
';

CREATE TRIGGER temp_person_insert_trigger
    BEFORE INSERT ON temp_person
    FOR EACH ROW
    EXECUTE PROCEDURE temp_person_insert();

次に、データを親に挿入し、子からデータを選択します。データは正しいはずです。

INSERT INTO temp_person (name) VALUES ('ovid');
SELECT * FROM temp_person_two;
 person_id | name | has_default
-----------+------+-------------
         1 | ovid | en
(1 row )

最後に、関連のない新しい列を追加して、親テーブルを変更します。データを挿入しようとして、「not-null 制約」違反が発生するのを確認します。

ALTER TABLE temp_person ADD column foo text;
INSERT INTO temp_person(name) VALUES ('Corinna');
ERROR:  null value in column "has_default" violates not-null constraint
CONTEXT:  SQL statement "INSERT INTO temp_person_two VALUES (  $1 .* )"
PL/pgSQL function "temp_person_insert" line 2 at SQL statement

私のバージョン:

testing=# select version();
                                                version
-------------------------------------------------------------------------------------------------------
 PostgreSQL 8.4.17 on x86_64-pc-linux-gnu, compiled by GCC gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 64-bit
(1 row)
4

2 に答える 2

2

これは 9.3 までずっと存在しますが、修正するのは難しいでしょう。また、バグではなく単に望ましくない動作なのかどうかはわかりません。

制約はまだありますが、列の順序を見てください。

                                  Table "pg_temp_2.temp_person"
  Column   |       Type        |                            Modifiers                            
-----------+-------------------+-----------------------------------------------------------------
 person_id | integer           | not null default nextval('temp_person_person_id_seq'::regclass)
 name      | character varying | 
Number of child tables: 1 (Use \d+ to list them.)

                                  Table "pg_temp_2.temp_person_two"
   Column    |         Type         |                            Modifiers                            
-------------+----------------------+-----------------------------------------------------------------
 person_id   | integer              | not null default nextval('temp_person_person_id_seq'::regclass)
 name        | character varying    | 
 has_default | character varying(4) | not null default 'en'::character varying
Inherits: temp_person

ALTER TABLE
                                  Table "pg_temp_2.temp_person_two"
   Column    |         Type         |                            Modifiers                            
-------------+----------------------+-----------------------------------------------------------------
 person_id   | integer              | not null default nextval('temp_person_person_id_seq'::regclass)
 name        | character varying    | 
 has_default | character varying(4) | not null default 'en'::character varying
 foo         | text                 | 
Inherits: temp_person

効果的に行っているため、最初の例で機能します。

INSERT INTO temp_person_two (person_id,name)
VALUES (person_id, name)

しかし、新しい列が子テーブルに追加された場所を見てください-最後に! だからあなたはで終わる

INSERT INTO temp_person_two (person_id,name,has_default)
VALUES (person_id, name, foo)

あなたが望んでいたものではなく:

INSERT INTO temp_person_two (person_id,name,foo)...

では、ここでの正しい動作は何ですか? PostgreSQL が子テーブルの列をシャッフルした場合、コードが壊れる可能性があります。そうでない場合は、コードが壊れる可能性もあります。たまたま、PG コードを大幅に変更しない限り、最初のオプションを実行できるとは思えないため、中期的にはそうなりそうにありません。

教訓: INSERT 列名を明示的にリストします。

手作業で時間がかかる場合があります。正規表現を使った言語を知っていますか? ;-)

于 2013-10-07T17:59:32.913 に答える
0

バグではありません。NEW.*は、新しい行の各列の値に展開されるため、 を実行していますが、指定しなかった場合INSERT INTO temp_person_two VALUES ( NEW.person_id, NEW.name, NEW.foo )は最後になります (指定した場合は間違っています)。NULL

値の数が子テーブルのフィールドの数と一致しないため、新しい列を追加する前でも機能することに驚いています。おそらく、欠落している末尾の値のデフォルトを想定しています。

于 2013-10-07T15:16:33.100 に答える