私は SQL (SQLite を使用して) を学び始めたばかりで、いつ外部キーを使用する必要があるかを理解しようとしています。私に説明された方法は、繰り返しデータが発生するたびに外部キーを使用し、ID を保存してスペースを節約することでした。私が作成しているデータベースには、数千のレコードがあり、カテゴリと郡がリストされています (おそらく、各列に数十個の一意のものがあります)。したがって、郡名と主キー ID を使用して郡用に別のテーブルを作成し、カテゴリでも同じことを行うことができます。そして、データベースが約 5% 小さくなることに疑いの余地はありません。でもメリットはそれだけ?他のすべてをより複雑にしているようです。郡とカテゴリの ID を追加しますが、それ以外の場合は必要ありません。phpLiteAdminでテーブルを見ると、カテゴリ/郡名の代わりに数字が表示されるだけなので、視覚化するのが難しくなります. この状況で外部キーを使用して別のテーブルを作成する利点は何ですか? それとも、それを行わずに、すべてのデータ (繰り返しとすべて) を 1 つのテーブルに保持する必要がありますか? また、郡/カテゴリテーブルを数値の主キーのない1つの列にすることはまったく意味があります.とにかくそれらはすべて一意になるのでしょうか? 少なくとも phpLiteAdmin にフルネームが表示されます。前もって感謝します!この状況で外部キーを使用して別のテーブルを作成する利点は何ですか? それとも、それを行わずに、すべてのデータ (繰り返しとすべて) を 1 つのテーブルに保持する必要がありますか? また、郡/カテゴリテーブルを数値の主キーのない1つの列にすることはまったく意味があります.とにかくそれらはすべて一意になるのでしょうか? 少なくとも phpLiteAdmin にフルネームが表示されます。前もって感謝します!この状況で外部キーを使用して別のテーブルを作成する利点は何ですか? それとも、それを行わずに、すべてのデータ (繰り返しとすべて) を 1 つのテーブルに保持する必要がありますか? また、郡/カテゴリテーブルを数値の主キーのない1つの列にすることはまったく意味があります.とにかくそれらはすべて一意になるのでしょうか? 少なくとも phpLiteAdmin にフルネームが表示されます。前もって感謝します!
5 に答える
外部キーを使用している場合。参照整合性とも呼ばれます。
2 つのテーブルがあるとします。最初のテーブルは account_user で、2 番目のテーブルは account_user_detail です。したがって、account_user テーブルには、account_id の account_number の主キーがあります。また、account_user_detail テーブルには、アカウント所有者のアドレスの詳細が含まれます。したがって、両方のテーブルを関連付ける場合、account_number または account_id は同じになります。したがって、2 番目のテーブルの主キーの値を使用して、外部キーを定義します。外部キーは、2 番目のテーブルの account_number の値が、同じ口座番号を持つ最初のテーブルの Xyz 氏の参照であることを識別します。
したがって、外部キーは、両方のテーブルに共通で同じ一意の値を共有する列を持つ 2 つのテーブルを結合するために使用されます。
これを確認できます:
SQL 外部キー制約は、テーブル間に「存在する」関係を強制するために使用されます。
編集:-
外部キー制約が存在するのは、参照される行が存在することを保証するためです。
また、wikiには次のように書かれています: -
データベース設計の重要な部分の 1 つは、外部キーを使用して 1 つのテーブルから別のテーブルを参照することにより、実世界のエンティティ間の関係がデータベースに反映されるようにすることです[9]。データベース設計のもう 1 つの重要な部分は、データベースの正規化です。この正規化では、テーブルが分割され、外部キーによってテーブルの再構築が可能になります。
このスレッドもチェックしてください。
外部キー制約は、列または列のセットに存在できる値を制限するために使用されます。たとえば、結婚を考えてみましょう。
CREATE TABLE person
(person_id INTEGER NOT NULL PRIMARY KEY
, name varchar NOT NULL
);
CREATE TABLE marriage
( person1 INTEGER NOT NULL PRIMARY KEY
, person2 INTEGER NOT NULL UNIQUE
, comment varchar
, CONSTRAINT marriage_1 FOREIGN KEY (person1) REFERENCES person(person_id)
, CONSTRAINT marriage_2 FOREIGN KEY (person2) REFERENCES person(person_id)
, CONSTRAINT order_in_court CHECK (person1 < person2)
);
-- add some data ...
INSERT INTO person(person_id,name) values (1,'Bob'),(2,'Alice'),(3,'Charles');
INSERT INTO marriage(person1,person2, comment) VALUES(1,2, 'Crypto marriage!') ; -- Ok
INSERT INTO marriage(person1,person2, comment) VALUES(2,1, 'Not twice!' ) ; -- Should fail
INSERT INTO marriage(person1,person2, comment) VALUES(3,3, 'No you dont...' ) ; -- Should fail
INSERT INTO marriage(person1,person2, comment) VALUES(2,3, 'OMG she did it again.' ) ; -- Should fail (does not)
INSERT INTO marriage(person1,person2, comment) VALUES(3,4, 'Non existant persons are not allowed to marry !' ) ; -- Should fail
SELECT p1.name, p2.name, m.comment
FROM marriage m
JOIN person p1 ON m.person1 = p1.person_id
JOIN person p2 ON m.person2 = p2.person_id
;
上記の DDL は、結婚をモデル化しようとします (一部失敗します)。モデル化する制約は次のとおりです。
- 結婚できるのは実在する人だけ
- 結婚は2人の異なる人の間でのみ存在できます
- 人は一度しか結婚できない
出力:
INSERT 0 3
INSERT 0 1
ERROR: new row for relation "marriage" violates check constraint "order_in_court"
ERROR: new row for relation "marriage" violates check constraint "order_in_court"
INSERT 0 1
ERROR: insert or update on table "marriage" violates foreign key constraint "marriage_2"
DETAIL: Key (person2)=(4) is not present in table "person".
name | name | comment
-------+---------+-----------------------
Bob | Alice | Crypto marriage!
Alice | Charles | OMG she did it again.
(2 rows)
国名が「United States of America」の場合、これは 24 バイトです。外部キーを使用する場合は、2 ~ 4 バイトしか必要ありません。それは大きな違いです。
国名を検索する場合、文字列全体ではなく数字のみを照合する必要があるため、非常に高速になります。
また、country_id フィールドでインデックスを使用すると、はるかに小さくなります。
追加された複雑さについてのご指摘は理解できます。あなたの場合、外部キーを使用しなくても問題はありませんが、そうすべきではありません。最終的にはそれらが必要になるので、このテーマについて準備し、経験を積んでおく必要があります。
でもメリットはそれだけ?
いいえ。
外部キーは、ほとんどのプログラミング言語のポインターまたは参照と論理的に似ています。何も参照することができずに、データをコピーするだけでデータ構造を作成しようとすることを想像してみてください。外部キーのないデータベースも同様に問題があります。
物事を参照する機能がなければ、すべてのコピーが最新の状態に保たれていることを確認する必要があります。1 つのコピーが更新され、もう 1 つのコピーが更新されないというバグがある場合、事実上データが破損し、どちらのコピーが正しいかわからなくなります。
冗長性の回避は、主にスペースに関するものではなく、データの整合性に関するものです。データベースの正規化 (外部キーなしでは実行できませんでした) の全体的な目的は、冗長性を回避し、データの整合性を保護することです。
あなたの特定のケースでは...
- カテゴリ (または国) は、メイン テーブルのどの行にも接続されていなくても存在できる必要がありますか?
- このカテゴリが接続されているメイン テーブルの行とは別に、カテゴリに存在する必要があるデータはありますか?
- 個別に実行する必要がある操作 (名前の変更など) はありますか?
いずれかの答えが「はい」の場合、カテゴリを別のルックアップ テーブルに入れる必要があります。このルックアップ テーブルが自然 (名前) キーを使用するか、代理 (ID) キーを使用するかは別の問題です。いくつかの長所と短所をここにリストします。