2011-02-09 24 views
9

DBの外部キーに苦労していますが、おそらく継承と関係がありますか?PostgreSQLの外部キーが存在しない、継承の問題?

-- table address 
CREATE TABLE address 
(
    pk_address serial NOT NULL, 
    fk_gadmid_0 integer NOT NULL, -- this table already exists, no problem here 
    street character varying(100), 
    zip character varying(10), 
    city character varying(50), 
    public boolean, 
    CONSTRAINT address_primarykey PRIMARY KEY (pk_address), 
    CONSTRAINT gadmid_0_primarykey FOREIGN KEY (fk_gadmid_0) 
     REFERENCES adm0 (gadmid_0) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE NO ACTION 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE address OWNER TO postgres; 

-- table stakeholder (parent) 
CREATE TABLE stakeholder 
(
    pk_stakeholder integer DEFAULT nextval('common_stakeholder_seq') NOT NULL, 
    fk_stakeholder_type integer NOT NULL, -- this table also exists, no problem here 
    name character varying(255) NOT NULL, 
    CONSTRAINT stakeholder_primarykey PRIMARY KEY (pk_stakeholder), 
    CONSTRAINT stakeholder_fk_stakeholder_type FOREIGN KEY (fk_stakeholder_type) 
     REFERENCES stakeholder_type (pk_stakeholder_type) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE NO ACTION 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE stakeholder OWNER TO postgres; 

-- table individual (child of stakeholder) 
CREATE TABLE individual 
(
    firstname character varying(50), 
    fk_title integer, -- this table also exists, no problem here 
    email1 character varying (100), 
    email2 character varying (100), 
    phone1 character varying (50), 
    phone2 character varying (50), 
    CONSTRAINT individual_primarykey PRIMARY KEY (pk_stakeholder), 
    CONSTRAINT title_foreignkey FOREIGN KEY (fk_title) 
     REFERENCES title (pk_title) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE CASCADE 
) INHERITS (stakeholder) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE individual OWNER TO postgres; 

-- link between stakeholder and address 
CREATE TABLE l_stakeholder_address 
(
    pk_l_stakeholder_address serial NOT NULL, 
    fk_stakeholder integer NOT NULL REFERENCES stakeholder, 
    fk_address integer NOT NULL REFERENCES address, 
    CONSTRAINT l_stakeholder_address_primarykey PRIMARY KEY (pk_l_stakeholder_address), 
    CONSTRAINT l_stakeholder_address_fk_stakeholder FOREIGN KEY (fk_stakeholder) 
     REFERENCES stakeholder (pk_stakeholder) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE NO ACTION, 
    CONSTRAINT l_stakeholder_address_fk_address FOREIGN KEY (fk_address) 
     REFERENCES address (pk_address) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE NO ACTION 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE l_stakeholder_address OWNER TO postgres; 

これまでのところ、何の問題:
だからここに基本的な設定です。そして、私はいくつかの値を追加してみました:

INSERT INTO individual (pk_stakeholder, fk_stakeholder_type, name, firstname, fk_title, email1, email2, phone1, phone2) 
    VALUES (1, 8, 'Lastname', 'Firstname', 1, '[email protected]', '', '', ''); 
INSERT INTO address (pk_address, fk_gadmid_0, street, zip, city, public) 
    VALUES (1, 126, 'Address', '', 'City', FALSE); 
INSERT INTO l_stakeholder_address (pk_l_stakeholder_address, fk_stakeholder, fk_address) 
    VALUES (DEFAULT, 1, 1); 

をそして最後に、私は、キー(fk_stakeholder)=(1)表の既存されていない「利害関係者」というエラー(SQL状態23503)を有する終わります。
最初の2つのインサートは大丈夫です、私はデータベースでそれらを見ることができます:

stakeholder: 
pk_stakeholder | ... 
---------------------- 
1    | ... 

address: 
pk_address | ... 
-------------------- 
1   | ... 

を私が間違っているのか?私はPostgreSQL(8.4を使用)ではなく、PGの問題であるかどうかはまだ分かりませんが、基本的なデータベース設計の理解が欠けているかもしれません...。
いずれにしても、今私は思っていたすべてのことをやってみましたが、PostgreSQL : Transaction and foreign key problemのようにFKを延期しようとしましたが、何とかうまくいきません。

答えて

6

あなたは非常に単純な(トリガーを使用して維持され、親と子の両方からすべてのプライマリキーと追加のテーブルindividual_pks (individual_pk integer primary key)を使用して、それを回避することができます - 削除の上でそれから、削除、挿入時にindividual_pksに挿入し、更新時に更新します(変更された場合はindividual_pk)。

次に、子の代わりに外部キーをこの追加のテーブルにポイントします。パフォーマンスの低下はありますが、行の追加/削除時のみです。

または、継承を忘れて古い方法(null許容列を含む1つの表)を実行します。

+0

あなたの答えはありがとう、私はそのように自分の問題を解決することができた。しかし、 'individual_pks'ではなく、stakeholderが親テーブルであるため、私はむしろ 'stakeholder_pk'を使用しました。したがって、「stakeholder_pk」は、「利害関係者」とその子どものすべての主キーを収集します。ありがとう! – Lukas

6

あなたの分析は正確です:それは継承のためです。外部キーをチェックするとき、子テーブルは考慮されません。

一般に、継承キーと外部キーはPostgreSQLでよく混在しません。大きな問題は、テーブル間でユニークな制約を設定できないことです。

Reference

+0

お返事ありがとうございます。私の理解は、子テーブルが、PK(継承されたもの以外)を持たず、FKが親テーブル(PKが正しく格納されている)を参照するため、ここでは関係ありませんでした。しかし、明らかに私は間違っている(私は正確にはわからないが)。だから、私が欲しいことをやり遂げる方法はありますか?おそらく、リンクテーブルのfk_stakeholderがステークホルダーのPKに存在するかどうかを確認するトリガーを使用していますか? – Lukas

+0

プライマリキーはここでは問題になりません。外部キーfk_stakeholderはテーブルのステークホルダーを指していますが、そこに一致する行はありません。テーブル個人の行は考慮されません。 –

+0

正直言って、私はまだそれを取得しません。外部キーは、子テーブルによって挿入されたために存在するstakeholder.pk_stakeholderを指します。私は問題がどこにあるのかと推測していますが、それでも行はそこにあります。上記の他のソリューションには、stakeholder_pk.pk_stakeholderがあります。私はこの問題で基本的な理解が欠けていると思います。しかし、何も気にしないで、私はあなたの時間をこれ以上使いこなすつもりはなく、Tometzkyによって提案されたソリューションを使用して動作するようです。とにかく、あなたの助けに感謝します。 – Lukas