web-dev-qa-db-ja.com

複合外部キーに別の一意制約が必要なのはなぜですか?

以下は、レコードが同じテーブル内の親レコードを参照できる単純なテーブルです。

CREATE TABLE foo (
    id         SERIAL  PRIMARY KEY,
    parent_id  INT     NULL,
    num        INT     NOT NULL,
    txt        TEXT    NULL,
    FOREIGN KEY (parent_id) REFERENCES foo(id)
);

他のフィールド値の1つ(num)が親レコードと子レコードで同一でなければならないという追加の要件により、複合外部キーがうまくいくはずだと思いました。最後の行を

    FOREIGN KEY (parent_id, num) REFERENCES foo(id, num)

そして得たエラー:参照されたテーブル "foo"の指定されたキーに一致する一意の制約はありません

この制約は簡単に追加できますが、参照されている列の1つ(id)が既に一意であることが保証されているのに、なぜ必要なのかわかりません。私の見たところ、新しい制約は冗長になります。

10
Zilk

これは、DBMSの制限事項です-私が知る限り、それらのすべてにおいて。列を追加するときだけでなく、列を再配置するときも同様です。 _(a1, a2)_にUNIQUE制約がある場合、本質的に冗長な_FOREIGN KEY_に一意の制約がない限り、_(a2, a1)_ that REFERENCES (a2, a1)を追加できません。

これを機能として追加することは、それほど難しくありません。

_(a)_にUNIQUE制約がある場合、_(a, b, c, ..., z)_または_(b,c, ...a, ...z)_の組み合わせもUNIQUEが保証されます。

または一般化:

_(a1, a2, ..., aN)_にUNIQUE制約がある場合、_(a1, a2, ..., aN, b1, b2, ..., bM)_の組み合わせまたは再配置もUNIQUEが保証されます。

要求されていないか、実装するのに十分高い優先度と見なされていないようです。

機能を実装するためのリクエストは、それぞれのチャネルでいつでも行うことができます。または、DBMSがPostgresのようなオープンソースの場合は、自分で実装することもできます。

11
ypercubeᵀᴹ

一般に、外部キーは(単なる複合ではなく)別のテーブルのある種の一意キーを指している必要があります。そうでない場合、リレーショナルデータの整合性はありません。

(id)に一意のキーがある一方で、(id、num)に一意のキーがないため、これは不満です。したがって、DBに関する限り、(id、num)のペアは一意であることが保証されていません。私たち人間は、それが一意であることを理解できますが、Postgresが「ああ、IDは一意であることがわかるように十分にスマートにするために追加する必要がある多くの追加コードがあると確信しています。 、したがって、id、numも一意である必要があります。

問題を修正するために2つの列に別の一意のインデックスを作成する必要がある場合に、そのコードを追加したとしたら、私は非常に驚きます。

明確にするために、彼らが追加しなければならないコードは、この単純なケースではありません...外部キーが4つ以上の列にあるケースなど、すべてのケースを処理する必要があります。きっとロジックはかなり複雑になります。

5
Joishi Bodio