4

私はPostgreSQLを初めて使用します。私は次のようなテーブルを持っています:

CREATE TABLE Person (
  ID SERIAL PRIMARY KEY,
  Name VARCHAR(32) NOT NULL DEFAULT '',
  Surname VARCHAR(32) NOT NULL DEFAULT '',
  Birthday DATE,
  Gender VARCHAR(8)
);

-- Student table inherits from person
CREATE TABLE Student (
  ID_Student SERIAL PRIMARY KEY,
  MajorDept VARCHAR(32),
) INHERITS(Person);

-- Student table inherits from person
CREATE TABLE Employee (
  ID_Employee SERIAL PRIMARY KEY,
  Position VARCHAR(32),
  Rank VARCHAR(32),
  Salary NUMERIC(12,2)
) INHERITS(Person);

-- Address table references person
CREATE TABLE Address (
  ID_Address SERIAL PRIMARY KEY,
  Person_id INTEGER REFERENCES Person(ID) NOT NULL,
  Email VARCHAR(32) UNIQUE,
  Country VARCHAR(32),
  CityCode INTEGER,
  City VARCHAR(32),
  AddressLine VARCHAR(60),
);

これらのテーブルによると、テーブルにデータを挿入したい場合Adress、Postgresはそのエラーを出します:

エラー:テーブル"address"の挿入または更新が外部キー制約"address_person_id_fkey"に違反しています詳細:キー(person_id)=(1)がテーブル"person"に存在しません。

私はPostgresでそれを学びました

インデックス(一意の制約を含む)と外部キーの制約は、単一のテーブルにのみ適用され、継承の子には適用されません。

私の質問は、トリガーを使用してこれをどのように修正できますか?サンプルコードは非常に便利です。

子テーブルにいくつかの行を挿入した後、「SELECT*FROMPerson;」でデータを確認できます。同じように。次のようになります。

人物テーブル

1;"Bill";"Smith";"1985-05-10";"male"
2;"Jenny";"Brown";"1986-08-12";"female"
3;"Bob";"Morgan";"1986-06-11";"male"
4;"Katniss";"Everdeen";"1970-08-12";"female"
5;"Peter";"Everdeen";"1968-08-12";"male"

学生テーブル

1;"Bill";"Smith";"1985-05-10";"male";1;"chemistry"
2;"Jenny";"Brown";"1986-08-12";"female";2;"physics"
3;"Bob";"Morgan";"1986-06-11";"male";3;"physics"

従業員テーブル

4;"Katniss";"Everdeen";"1970-08-12";"female";1;"Prof";"1";3500.00
5;"Peter";"Everdeen";"1968-08-12";"male";2;"Assist-Prof";"5";1800.00
4

2 に答える 2

5

外部キーは継承されません。外部キーがテーブルを指している場合person、同じ値がそのテーブルに存在する必要があります。継承の実装はPostgreSQLで制限されています、私はマニュアルの「警告」の章から引用します:

この場合、適切な回避策はありません。

これには、 @Muが提案したトリガーが含まれます。ON INSERT参照整合性を保証するには、トリガー以上のものが必要になります。私はそれを試みません。人を削除するとどうなりますか?IDを変更しますか?

継承は一切使わないと思います。それでも必要な場合、または必要な場合は、データモデルにいくつかの変更を提案します。

  • 1)emailアドレステーブルに含めるべきではありません。アドレスや人とは何の関係もありません。テーブルに移動しますperson。置き忘れの理由は、一意性を強制したいためかもしれません。継承をまったく使用しないもう1つの理由。

  • 2)列id_studentid_employeeは冗長です。代わりに、継承された列idを主キーとして使用してください。子テーブルに制約を追加するだけです。

    CONSTRAINT student_pkey PRIMARY KEY (id)
    CONSTRAINT employee_pkey PRIMARY KEY (id)
    

    idこれにより、継承ツリーの列で重複する可能性のある2つのソースのうちの1つも排除されます。(もう1つは、またはstudentに存在するIDを引き続き入力できることです。継承システムのもう1つの注意点です。したがって、手動で挿入または変更しないでください。列のデフォルトとシーケンスのままにします。employeepersonid

  • 3)「自然な」モデルは、との間にn:mの関係を持つことaddressですperson。あなたのモデルではperson_address、address_idがテーブルaddressを参照person_idし、外部キー制約(元の問題)のみを夢見ている追加のテーブルを使用してそれを実装します。

    あなたがそれを持っている方法では、住所に複数の人が住むことは決してできません。多分それはあなたの目的には十分です。このようにして、アドレス全体をpersonテーブルに埋め込んで(そして学生と従業員にそれを継承させる)、外部キーの問題を完全に回避することもできます。

于 2011-12-12T04:40:38.070 に答える
5

まず、次のようなものでFKを取り除きます。

alter table address drop constraint address_person_id_fkey

address_person_id_fkeyそれが制約がないことについて不平を言う場合は、FKが何と呼ばれるかを調べるためにを使用\d address;してください。psql

次に、このような単純なトリガーでうまくいくはずです。

create or replace function pseudo_fk_for_address() returns trigger as $$
begin
    if not exists(select 1 from person where id = new.person_id) then
        raise exception 'No such person: %', new.person_id;
    end if;
    return new;
end;
$$ language plpgsql;

そして、次のように添付します。

create trigger pseudo_fk_for_address_trigger before insert or update on address 
for each row execute procedure pseudo_fk_for_address();

person次に、 (そこから継承するテーブルを含む)に存在しない誰かのアドレスを追加しようとすると、次のようなエラーが発生します。

playpen=> insert into address (person_id, email, country, citycode, city, addressline) values (3, 'ab', 'b', 2, 'c', 'd');
ERROR:  No such person: 3

参照がぶら下がらないように、BEFORE DELETEトリガーを追加するとperson、基本的な構造はほとんど同じになります。address.person_idBEFOREDELETEトリガーもサポートするためにインデックスをオンにする必要がある場合があります。

参照:

于 2011-12-12T03:08:58.677 に答える