主キーと外部キーとは ― 候補キー・複合キーの違い
主キーは
主キーは行を1つに決める列、外部キーはほかの表の主キーを指す列
主キーとは、表の中で行を1つに決めるための列です。同じ値の行を2つ置けず、値が無いことを表すNULLも入れられません。
外部キーとは、ほかの表の主キーと同じ値を入れて、その表の行を指す列です。外部キーを決めておくと、指す先の無い値を入れる操作をDBMSが拒否します。表を設計するときも、SQLで制約を書くときも、外部キー違反のエラーの原因を探すときも、この2つの考え方が必要です。
例には、RDBの記事の顧客と注文の表を少し変えて使います。顧客の表には、候補キーの例にするメールアドレスの列を足しました。注文の表は、商品の列を注文日に替え、顧客103の注文を除いた3行にしました。
| 顧客ID | メールアドレス | 氏名 |
|---|---|---|
| 101 | misaki@example.com | 田中 美咲 |
| 102 | kenta@example.com | 佐藤 健太 |
| 103 | daisuke@example.com | 鈴木 大輔 |
| 注文ID | 顧客ID | 注文日 |
|---|---|---|
| 5001 | 101 | 2026-10-01 |
| 5002 | 102 | 2026-10-03 |
| 5003 | 101 | 2026-10-05 |
キーの種類は、行が1つに決まるかと、余分な列があるかで分かれる
表のキーは、どの列の組なら行を1つに決められるかによって呼び名が変わります。次の表に、顧客の表と、後で使う注文明細の表を例にして、キーの種類を並べました。
| キーの | 意味 | この |
|---|---|---|
| スーパーキー | 値を | 顧客ID+氏名 |
| 候補キー | 行が | 顧客ID、 |
| 主キー | 候補キーから | 顧客ID |
| 代替キー | 主キーに | メールアドレス |
| 複合キー | 2つ以上の | 注文明細の |
| 外部キー | ほかの | 注文の |
上の4つは、1つの表の中で行を決める列の組を、絞り込んだ順に並べています。複合キーは列の数に着目した呼び方で、候補キーや主キーが複合キーのこともあります。外部キーだけは、ほかの表とのつながりを表すキーです。
候補キーの中から1つを選んで主キーにする
顧客の表では、顧客IDの値を見れば行が1つに決まります。メールアドレスも、同じ値を2人が使わない決まりなら、行を1つに決められます。氏名は同姓同名の人がいるので、行を決められません。
顧客IDやメールアドレスのように、主キーになれる列の組を候補キーと呼びます。候補キーは、行を1つに決められ、しかも余分な列を含みません。顧客IDと氏名の組も行は決まりますが、氏名を外しても決まるので、候補キーではありません。
余分な列を含んでもよい組は、スーパーキーと呼びます。スーパーキーのうち、余分な列がないものが候補キーです。
候補キーが2つ以上あるときは、そのうち1つを選んで主キーにします。関係モデルを提案したCoddの1970年の論文も、余分な列のないキーが複数ある表では、1つを選んで主キーと呼ぶと書いています。選ばれなかった候補キーを、代替キーと呼びます。
主キーは1つだけで、代替キーにはUNIQUEとNOT NULLを付ける
SQLでは、主キーは1つの表に1つだけ置けます。PostgreSQLで2つの列にPRIMARY KEYを付けると、表を作る文がエラーになりました。そのため、代替キーにした列には、UNIQUEとNOT NULLを付けて重複とNULLを禁止します。
PostgreSQLの文書は、UNIQUEとNOT NULLを組み合わせた制約について、働きの上では主キーとほとんど同じだと説明しています。実際に、メールアドレスの列にこの2つを付けて、同じメールアドレスの顧客を追加すると、その文は拒否されました。制約の書き方は、CREATE TABLEと制約の記事にまとめました。
複合キーは、2つ以上の列の組で行を1つに決める
1回の注文で複数の商品を買うと、注文の中身は注文明細の表に1商品1行で入ります。この表では、注文IDにも商品IDにも同じ値が何度も現れます。2つを組にすると、行ごとに別の値になります。
このように2つ以上の列でできたキーを、複合キーと呼びます。SQLでは、PRIMARY KEY (注文ID, 商品ID) のように、列を並べて表制約として書きます。注文IDと商品IDが同じ行をもう1行入れようとすると、主キーの重複として拒否されます。
注文明細の注文IDは、注文の表の主キーを指す外部キーでもあります。複合キーの一部の列が、同時に外部キーになることもあります。Coddの1970年の論文の例でも、3つの列の組が主キーで、それぞれの列が外部キーでした。
複合キーの一部の列だけで決まる列があると、表の中に同じ値がくり返し入ります。その表の分け方は、正規化の記事で部分関数従属として説明しています。
外部キーは、親の表の主キーか候補キーを指す
外部キーを持つ側の表を子の表、指される側の表を親の表と呼びます。例では注文の表が子、顧客の表が親です。MySQLの文書も、この呼び方で外部キーを説明しています。親と子が同じ表のこともあります。社員の表で、上司の列が同じ表の社員番号を指す場合がその例です。
外部キーが指す先は、ふつうは親の表の主キーです。PostgreSQLでは、UNIQUEを付けた代替キーも指せます。同じ値が入りうる氏名の列を指そうとすると、外部キーを定義する文がエラーになりました。
主キーと違い、外部キーの値は複数の行で同じでかまいません。注文5001と5003は、どちらも顧客101を指しています。外部キーの列にNOT NULLを付けなければ、NULLも入れられます。
外部キーでつないだ2つの表は、結合して読めます。書き方はJOINの記事で説明しています。どの表に外部キーを置くかは、E-R図の記事で説明する1対多の関連から決まります。
外部キーがあると、親のない子の行と、子のある親の削除が拒否される
外部キーは、指す先の無い子の行を作らせません。この決まりを参照制約と呼びます。参照制約が働いていれば、表どうしのつながりは食い違いません。この状態を参照整合性と呼びます。
DBMSが確かめる相手は、どちらの表を操作するかで変わります。子の表に行を足すときや外部キーの値を変えるときは、親の表にその値があるかを確かめます。親の表の行を消すときや主キーの値を変えるときは、子の表からその行が指されていないかを確かめます。
子の表の行を消す操作では、何も確かめません。子の行が消えても、指す先の無い行は生まれないからです。親の表に行を足す操作でも、同じ理由で何も確かめません。
操作を選んで、受け付けられるか拒否されるかを確かめる
次の図では、最初に示した顧客と注文の表に、7つの操作を試せます。子の表への操作も、親の表への操作も選べます。図に出る結果は、PostgreSQLで同じ表に実行して確かめたものです。
顧客の表(親)
| 顧客ID | メールアドレス |
|---|---|
| 101 | misaki@example.com |
| 102 | kenta@example.com |
| 103 | daisuke@example.com |
注文の表(子)
| 注文ID | 顧客ID | 注文日 |
|---|---|---|
| 5001 | 101 | 2026-10-01 |
| 5002 | 102 | 2026-10-03 |
| 5003 | 101 | 2026-10-05 |
試す操作を選ぶ
INSERT INTO 注文 VALUES (5004, 101, '2026-10-07');子の表への操作DBMSが
○受け付けられる
外部キーの
INSERT INTO 注文 VALUES (5005, 104, '2026-10-07');子の表への操作DBMSが
×拒否される:参照制約に
追加すると、
INSERT INTO 注文 VALUES (5006, NULL, '2026-10-07');子の表への操作DBMSが
○受け付けられる
外部キーの
DELETE FROM 顧客 WHERE 顧客ID = 103;親の表への操作DBMSが
○受け付けられる
顧客103を
DELETE FROM 顧客 WHERE 顧客ID = 101;親の表への操作DBMSが
×拒否される:参照制約に
削除すると、
UPDATE 顧客 SET 顧客ID = 201 WHERE 顧客ID = 102;親の表への操作DBMSが
×拒否される:参照制約に
主キーの
DELETE FROM 注文 WHERE 注文ID = 5002;子の表への操作DBMSが
○受け付けられる
注文の
顧客101の削除と、顧客102の顧客IDの変更は、どちらも親の表への操作です。どちらの行も子の注文から指されているので、拒否されます。注文の無い顧客103なら削除できます。PostgreSQLもMySQLも、外部キーの動作を指定しないときは、子から指されている親の行の削除や主キーの変更をエラーにします。
親の行を消すと子の行も一緒に消える設定もあります。その書き方は、CREATE TABLEと制約の記事で触れています。
主キーには、番号を振る代理キーと、業務の値を使う自然キーがある
顧客IDのように、行を区別するためだけに振った番号を主キーにしたものを、代理キーまたはサロゲートキーと呼びます。メールアドレスのように、業務で使う値そのものを主キーにしたものは自然キーです。
自然キーは、値が後から変わることがあります。メールアドレスを主キーにすると、変えるたびに注文の表の外部キーも直さなければなりません。前の節で見たとおり、子から指されている主キーの値を変える文は、そのままでは拒否されます。
代理キーを主キーにすれば、メールアドレスを変えても顧客の表の1行が変わるだけです。PostgreSQLで試すと、注文から指されている顧客102のメールアドレスの変更は受け付けられました。メールアドレスの列はUNIQUEとNOT NULLを付けて代替キーにしておけば、同じ値の登録も防げます。
連番の値は、DBMSに振らせることもできます。PostgreSQLでは、GENERATED ALWAYS AS IDENTITY を付けた列が、行を追加するたびに値を作ります。番号の付け方そのものは、コード設計の記事で説明しています。
参考にした資料
- E. F. Codd "A Relational Model of Data for Large Shared Data Banks"(Communications of the ACM、1970年)(主キー・外部キーの定義)
- PostgreSQL 18 文書「Constraints」(主キー、UNIQUEとNOT NULL、外部キーが指せる列とNULL、削除と更新の既定の動作)
- PostgreSQL 18 文書「Identity Columns」(キーの値を作る列)
- MySQL 8.4 Reference Manual「FOREIGN KEY Constraints」(親の表・子の表、削除と更新の既定の動作)
練習問題(全5問)
正解:行が
候補キーは、
正解:代替キー
メールアドレスも
正解:注文IDと
注文IDだけでも
正解:注文から
注文から
正解:複数の
1人の
選んでから「採点する」を押すと、解説つきで答え合わせができます。
関連記事
おすすめの本 PR
セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

