9

Oracleで次の2つのテーブルを取得します。

Create Table A
( A int, B int, C int,
  Constraint pk_ab Primary Key(A, B),
  Unique (C)
);

Create Table B
( D int, E int, F int,
  Constraint fk_d Foreign Key (D) References A(A),
  Constraint fk_e Foreign Key (E) References A(B)
);

このステートメントが機能しないのはなぜですか?もっと具体的に言うと、なぜそれが機能しないのですか?このタイプのリレーションを作成しようとしている理由は、将来、削除したいB.Dが、リレーションは保持したいということFK_Eです。

エラーが発生しました:

ORA-02270:この列リストに一致する一意キーまたは主キーがありません

4

3 に答える 3

14

「なぜこのステートメントが機能しないのですか?より具体的には、なぜ機能しないのですか?」

Aの主キーを2つの列(A、B)の複合として定義しました。PK_ABを参照する外部キーは、それらの列の数と一致する必要があります。これは、外部キーが、子テーブルの任意の行を所有する参照テーブルの単一の行を識別する必要があるためです。複合主キーは、列AAに重複する値を含めることができ、列ABに含めることができることを意味します。(A、B)の順列のみが一意です。したがって、参照する外部キーには2つの列が必要です。

Create Table B
( D int, E int, F int,
  Constraint fk_de Foreign Key (D,E) References A(A,B)
);

「テーブルBが参照するPKが複数あるため」

間違い。Bは、たまたま複数の列で構成される単一の主キーを参照します。

「たとえば、将来的にはBDを削除したいのですが、関係fk_eは保持します。」

それは意味がありません。このように考えてください。DはBのプロパティではなく、テーブルAへの依存を通じてBが継承する属性です。

この状況を回避する1つの方法は、代理(または合成)キーを使用することです。複合キーは多くの場合ビジネスキーであるため、それらの列はビジネスコンテキストで意味があります。意味のある列値の特徴の1つは、それらが変更される可能性があり、そのような変更を外部キーにカスケードすることは厄介になる可能性があることです。

代理キーの実装は次のようになります。

Create Table A
( id int not null, A int, B int, C int,
  Constraint pk_a Primary Key(ID),
  constraint uk_ab Unique (A,B)
);

Create Table B
( a_id int, F int,
  Constraint fk_n_a Foreign Key (A_ID) References A(ID)
);

もちろん、A(C)にはすでに単一の列制約があるため、投稿したスキーマを使用してこれを行うことができます。ただし、許可されている場合でも、主キーではなく一意の制約を参照することはお勧めできません。これは、固有の制約によってビジネスキーが強制されることが多いため、つまり、変更の可能性があるためですが、主に主キーの参照が業界標準であるためだと思います。

于 2013-01-27T05:59:45.820 に答える
1

テーブルを作成する前に、列Aとテーブルに2つの別々のインデックスを作成してみてくださいBB

CREATE INDEX a_idx ON A (A);
CREATE INDEX b_idx ON A (B);

しかし、おそらくあなたはテーブルに複合FKが必要ですB

Create Table B
( D int, E int, F int,
  Constraint fk_d Foreign Key (D,E) References A(A,B)
);
于 2013-01-27T03:08:33.967 に答える
0

外部キーは常に別のテーブルのPKを参照します。AもBも単独ではPKではありません。複数のPKがあります。

Constraint fk_d Foreign Key (D,E) References A(A,B)

また、データベースは部分的なnullの複数の外部キーを検証できないため、チェック制約もテーブルに追加する必要があると思います。

alter table B add constraint check_nullness
    check ( ( D is not null and E is not null ) or
                ( D is null and E is null ) )
于 2013-01-27T03:08:45.793 に答える