外部キー列/制約の曖昧さの解消
したがって、外部キーの作成方法と FK の目的を理解しています。しかし、それらの使用方法を理解するのに問題があります。
外部キー制約を参照していると仮定すると、短い答えはそれらを使用しないことです。
そして、ここに長いものがあります:
列を他のテーブルへの外部キーと呼ぶことに慣れています。特に正規化プロセス中は、 「はテーブルへの外部キーです」user_purchase.i_id
items
などのフレーズが非常に一般的です。これは関係を説明するのに完全に有効な方法ですが、実装段階に達すると少し曖昧になる可能性があります。
句なしでテーブルを作成したとします。FOREIGN KEY
CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
);
関係に関しては、外部キー列がまだ実装されていることに注意してください。テーブル ( )を参照する列と、user
テーブル ( )id
を参照する別の列があります。この列はしばらく脇に置いておきます。次のデータを検討してください。items
i_id
name
user user_purchase items
| id username | | id i_id | | i_id name price |
| 23 john | | 55 10 | | 10 chocolate bar 3.42 |
| 55 mary | | 70 10 | | 33 mobile phone 82.11 |
| 70 fred | | 70 33 | | 54 toothpaste 8.67 |
| 55 10 | | 26 toy car 6.00 |
| 70 26 |
関係はそこにあります。これは、誰が何を購入したかuser_purchase
に関する情報を保持するテーブルによって実装されます。関連するレポートについてデータベースにクエリを実行する場合は、次のようにします。
select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
これが、関連するリレーションと外部キー列を使用する方法です。
では、次のようにするとどうなるでしょうか。
insert into user_purchase (id,i_id) values (23,99)
どうやら、これは無効なエントリです。のユーザーはいますがid=23
、 のアイテムはありませんi_id=99
。RDBMS はそれ以上のことを知らないので、それを可能にします。まだ。
ここで、外部キー制約の出番です。テーブル定義で指定することによりFOREIGN KEY (i_id) REFERENCES items(i_id)
、本質的に RDBMS に従うべきルールを与えます: 列に含まれていない値を持つエントリは受け入れられません。つまり、外部キー列が参照を実装する一方で、外部キー制約は参照整合性を強制します。user_purchase
i_id
items.i_id
ただし、select
FK 制約を定義したからといって、上記は変更されないことに注意してください。したがって、データを保護するために FK 制約を使用するのではなく、RDBMS が使用します。
冗長性
...複数の列が必要な場合はどうすればよいですか? 同じテーブルの異なる列に複数の外部キーを使用しないのはなぜですか?
自問してみてください: なぜそれが必要なのですか? 2 つの外部キーが同じ目的で使用される場合、冗長性によって最終的に問題が発生します。次のデータを検討してください。
user_purchase items
| id i_id name | | i_id name price |
| 55 10 chocolate bar | | 10 chocolate bar 3.42 |
| 70 10 chocolate bar | | 33 mobile phone 82.11 |
| 70 33 mobile phone | | 54 toothpaste 8.67 |
| 55 10 toothpaste | | 26 toy car 6.00 |
| 70 26 toy car |
この写真の何が問題になっていますか? ユーザー55
はチョコレート バーを 2 つ購入しましたか、それともチョコレート バーと歯磨き粉を購入しましたか? この種のあいまいさは、データの同期を維持するために多くの労力を必要とする可能性がありますが、外部キーの 1 つを保持するだけであれば不要です。name
実際、関係によって暗示されているため、列を完全に削除しないでください。
もちろん、複合外部キーを実装PRIMARY KEY(i_id,name)
し、テーブルを設定してitems
(または追加のインデックスを定義UNIQUE(i_id,name)
しても問題ありません) FOREIGN KEY(i_id,name) REFERENCES items(i_id,name)
、. このように、テーブルに存在する (i_id,name) カップルのみitems
が有効になりますuser_purchases
。まだ1 つの外部キーがあるという事実は別として、列がアイテムを識別するのに十分である場合、このアプローチはまったく不要ですi_id
(列について同じことは言えませんname
...)。
ただし、テーブルに対して複数の外部キーを使用することに対する規則はありません。実際、そのようなアプローチが必要な状況があります。次のデータを含むperson(id,name)
テーブルとテーブルを考えてみましょう。parent(person,father,mother)
person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
明らかに、parent
テーブルの 3 つの列はすべて への外部キーperson
です。ただし、同じリレーションではなく、 3 つの異なるリレーションの場合: 個人の親も個人であるため、対応する 2 つの列は同じテーブルを参照する必要がありますperson
。ただし、3 つのフィールドは同じ行の異なるを参照できるだけでなく、参照する必要があることに注意してください。これは、誰も自分の親ではなく、父親も母親でもないためです。person
parent