主キー・外部キーと整合性制約
主キー・一意性・参照の各制約について、どの SQL 操作が制約違反になるかを判定できるようになる。外部キーを定義する目的と、データ項目の命名規約では防げない問題も答えられるようになる。
「この操作はエラーになるか」は、表を見て手順どおりに確かめれば必ず正解できるので、確実に取れる得点源です。実務では「存在しない顧客IDの注文が入る」事故をデータベース側で止める仕組みであり、API 設計でいう入力検証をデータベースの層でかけるものと考えると分かりやすいです。
このレッスンで稽古する(用語チェック・過去問)結論:3つのルールで判定できる
このレッスンの問題は、次の3つのルールで判定できます。
- 主キー:値が重複してはいけない。NULL(値が無い状態)も入れられない
- 外部キー:外部キーの値は、参照先の表の主キーに実際にある値でなければならない
- 命名規約:名前と型はそろえられるが、取り得る値の範囲まではそろえられない
残りは、この3つを表と SQL に当てはめる作業です。
主キー:行を1つに特定するための番号
**主キー(Primary Key)**は、表の中の1行を確実に1つに特定するための列です。社員番号にたとえると、同じ番号の社員が2人いたり、番号が空欄の社員がいたりすると「誰のことか」が決まりません。
| 主キーの条件 | 正しいか |
|---|---|
| 値が重複しない(一意) | ○ 必須 |
| NULL(空)でない | ○ 必須 |
| 1列で構成する | × 複数列を組み合わせてもよい(複合キー) |
| 表の先頭の列にある | × どの位置の列でもよい |
| 検索条件に必ず主キーを指定する | × 主キー以外の列でも検索できる |
| 数値型の主キーは計算に使えない | × 計算にも使える |
試験で正解になるのは「重複しない」「空でない」のどちらかです。「1列だけ」「先頭の列」「計算できない」のような余計な制限が付いた選択肢は誤りです。
制約の種類と SQL での書き方
制約とは、表に入れてよいデータの条件をデータベースに登録し、条件を破る操作をエラーにして止める仕組みです。キーワードと制約名の対応がそのまま出題されます。
| 制約名 | SQL のキーワード | 内容 |
|---|---|---|
| 主キー制約(キー制約の一つ) | PRIMARY KEY | 重複なし+NULLなし |
| 一意性制約(キー制約の一つ) | UNIQUE | 重複なし。NULLは入れてもよい |
| 非NULL制約 | NOT NULL | NULLを入れられない |
| 参照制約(参照整合性制約) | FOREIGN KEY ~ REFERENCES | 外部キーの値が参照先の表に存在しなければならない |
| 検査制約 | CHECK | 値の条件(例:在庫数 >= 0) |
| 表明 | ASSERTION | 複数の表にまたがる条件 |
FOREIGN KEY と REFERENCES の組み合わせは参照制約と覚えます。キー制約(PRIMARY KEY・UNIQUE)や検査制約(CHECK)と取り違えさせる選択肢が出ます。
主キー制約違反の見抜き方:WHERE で何行が選ばれるか
UPDATE 文で主キーの列を書き換える問題では、WHERE の条件に当てはまる行が何行あるかを最初に数えます。2行以上が当てはまるのに主キーを1つの固定値に書き換えると、書き換え後の行どうしで値が重複してエラーになります。
| UPDATE の形 | 結果 |
|---|---|
| 主キーを既存の値に書き換える | 違反(既存の行と重複) |
| 当てはまる行が2行以上あり、主キーを同じ値に書き換える | 違反(書き換えた行どうしで重複) |
| 主キーを NULL に書き換える | 違反 |
| 当てはまる行が1行で、まだ使われていない値に書き換える | OK |
| 主キー以外の列(商品名など)だけを書き換える | OK |
注意点1:NULL と比較した条件は成り立たない。 在庫数が NULL の行は「在庫数 >= 20」に当てはまらないので、更新の対象になりません。
注意点2:UNIQUE 制約では NULL を含む組は重複とみなされない。 (A, B) の2列に UNIQUE 制約があっても、(AA01, NULL) や (NULL, NULL) の行は追加できます。違反になるのは、NULL を含まない組で値がまったく同じになる場合だけです。
外部キー:他の表の主キーを指す列
**外部キー(Foreign Key)**は、他の表の主キーの値を持つことで、2つの表の行を結び付ける列です。会員番号を書いて予約する仕組みにたとえると、会員名簿に載っていない番号での予約は受け付けない、というルールに当たります。
外部キーを定義する目的は「表と表のあいだで参照の一貫性(参照整合性)を保つ」ことだけです。次の選択肢はどれも外部キーの目的ではありません。
| ひっかけの選択肢 | 実際は何の話か |
|---|---|
| 関係する表を近くに格納して検索を速くする | 物理的な格納設計の話 |
| 壊れたレコードを表どうしの関係から復旧する | 障害回復(ログ・バックアップ)の話 |
| 削除と追加の繰り返しによる虫食い状態(フラグメンテーション)を防ぐ | 格納領域の再編成の話 |
用語を整理します。参照する側の表(例:注文)を子表、参照される側の表(例:顧客)を親表と呼びます。
どの操作が参照整合性を壊すか
判定の基準は、操作した後に、親表に存在しない値を指している子表の行ができるかどうかです。
| 操作 | 結果 |
|---|---|
| 子表に行を追加:外部キーの値が親表にある | OK |
| 子表に行を追加:外部キーの値が親表にない | 違反 |
| 子表の行を削除 | OK(参照している行が消えるだけ) |
| 親表の行を削除:子表から参照されていない行 | OK |
| 親表の行を削除:子表から参照されている行 | 違反(子表の行の参照先が無くなる) |
| 親表に行を追加 | OK |
データを新しく入れるときは、参照される側(親表)から先に入れます。表が3つ以上つながっているときは、参照の矢印を逆向きにたどった順番が入力の順番になります。
flowchart LR
A["資産(建物番号と部屋番号で部屋を参照)"] -->|"参照"| B["部屋(建物番号で建物を参照)"]
B -->|"参照"| C["建物"]
入力の順番は、矢印の終点から始めて 建物 → 部屋 → 資産 です。
データ項目の命名規約:防げることと防げないこと
命名規約とは、データ項目の名前の付け方を統一するルールです。区分語(例:「〜金額」は数値型、「〜年月日」は日付型、と決める語)を名前の末尾に付けるルールと、項目名と意味を登録した辞書で、名前と型の不統一を防ぎます。ただし、**取り得る値の範囲(ドメイン・定義域)**は名前からは決まらないので、命名規約だけではそろえられません。
| 起きる問題 | 命名規約で防げるか | 防ぐ仕組み |
|---|---|---|
| 同じ「〜年月日」に日付型と文字列型が混在する | ○ | 区分語ごとに型を決める |
| 「賞与金額」と「ボーナス金額」が同じ意味で並存する(異音同義語) | ○ | 辞書に登録して統一する |
| 「取引先」がコードなのか名前なのか分からない | ○ | 区分語を必ず付ける |
| 「受注金額」の取り得る値の範囲が表によって違う | × | ドメインの定義や検査制約が必要 |
「規約の(1)(2)で防げるものはどれか」を1つずつ消していき、最後に残る値の範囲が正解です。
試験での問われ方
- 主キーの性質:「重複しない」「空でない」が正解です。「1列だけ」「先頭の列」「検索に必須」「計算できない」は誤りです。
- 制約違反の判定:4つの SQL 文から1つ選ぶ形式です。WHERE に当てはまる行を数え、書き換え後の主キーが重複しないか、NULL にならないかを確かめます。
- SQL のキーワード:FOREIGN KEY と REFERENCES は参照制約です。
- 外部キーの目的:高速化・障害復旧・虫食い防止を混ぜた選択肢の中から、参照の一貫性を選びます。
- 参照整合性の判定:親表に無い値を子表に追加する操作が違反です。親表から先に入力します。
- 命名規約:防げないのは値の範囲(ドメイン)です。
UPDATE で主キーが重複するかを判定する
| 商品コード | 商品名 | 仕入先コード | 仕入単価 | 在庫数 |
|---|---|---|---|---|
| A111 | テレビ | S001 | 75,000 | 0 |
| A222 | デジタルカメラ | S002 | 50,000 | 50 |
| A333 | DVDプレーヤ | NULL | NULL | NULL |
| A444 | 洗濯機 | S004 | 45,000 | 20 |
ア DELETE FROM 商品 WHERE 仕入先コード IS NULL
イ INSERT INTO 商品 VALUES ('A555', '空気清浄機', 'S005', 60000, 50)
ウ UPDATE 商品 SET 商品コード = 'A666' WHERE 商品コード = 'A444'
エ UPDATE 商品 SET 商品コード = 'A777' WHERE 在庫数 >= 20
出典:令和8年度 基本情報技術者試験 科目A 公開問題 問7
解き方と答えを見る
- 主キーを確認する:PRIMARY KEY が付いているのは商品コード。値の重複と NULL が禁止される
- ア:仕入先コードが NULL の行は A333 の1行だけ。削除は主キーの重複を生まないので OK
- イ:A555 は表にまだ無い値なので、追加しても重複しない。OK
- ウ:WHERE 商品コード = 'A444' に当てはまるのは1行だけ。A666 は表に無い値なので OK
- エ:在庫数 >= 20 に当てはまる行を数える。A111 は0なので対象外、A222 は50なので対象、A333 は NULL なので条件が成り立たず対象外、A444 は20なので対象 → 当てはまるのは2行
- この2行の商品コードをどちらも 'A777' にすると、A777 の行が2行になって主キーが重複する → 制約違反
答え:エ(2行が同じ主キー 'A777' になるため実行エラーになる)
参照整合性を損なう操作を見つける
| 伝票番号 | 顧客番号 |
|---|---|
| 0001 | C005 |
| 0002 | K001 |
| 0003 | C005 |
| 0004 | D010 |
| 顧客番号 | 顧客名 |
|---|---|
| C005 | 福島 |
| D010 | 千葉 |
| K001 | 長野 |
| L035 | 宮崎 |
ア “顧客” 表の行 [L035 | 宮崎] を削除する。
イ “注文” 表に行 [0005 | D010] を追加する。
ウ “注文” 表に行 [0006 | F020] を追加する。
エ “注文” 表の行 [0002 | K001] を削除する。
解き方と答えを見る
- 子表は注文(外部キーは顧客番号)、親表は顧客(主キーは顧客番号)と確認する
- 親表にある顧客番号を書き出す:C005, D010, K001, L035
- ア:親表の L035 を削除する。注文表に L035 を参照している行は無いので OK
- イ:注文表に D010 の行を追加する。D010 は親表にあるので OK
- ウ:注文表に F020 の行を追加する。F020 は親表に無いので、存在しない顧客を指す注文になる → 違反
- エ:子表(注文)の行を削除する。参照している側が消えるだけなので OK
答え:ウ(顧客表に存在しない F020 を外部キーに入れることになる)
参照関係から入力の順番を決める
ア 資産 → 建物 → 部屋
イ 建物 → 部屋 → 資産
ウ 部屋 → 資産 → 建物
エ 部屋 → 建物 → 資産
出典:基本情報技術者試験 科目A免除 修了試験 20230122 実施分 問25
解き方と答えを見る
- 参照の向きを書き出す:資産は(建物番号、部屋番号)で部屋を参照する。部屋は建物番号で建物を参照する
- 参照の矢印をつなげる:資産 → 部屋 → 建物
- 参照される側を先に入力するというルールなので、矢印の終点から逆にたどる
- 建物(どの表も参照していない)→ 部屋(建物があれば入力できる)→ 資産(部屋があれば入力できる)
答え:イ(建物 → 部屋 → 資産)
要点(試験直前に読む)
- 主キーは「重複なし+NULLなし」。複数列で作ってもよく、表の先頭の列である必要もない
- UPDATE で主キーを書き換える問題は、WHERE に当てはまる行を数える。2行以上を同じ値にすると違反になる。NULL の行は比較条件に当てはまらない
- UNIQUE 制約は NULL を入れられ、NULL を含む組は重複とみなされない
- FOREIGN KEY と REFERENCES で指定するのは参照制約。目的は表と表のあいだの参照の一貫性を保つこと
- 親表に無い値を子表に追加すると違反。新しく入力するときは親表から先に入れる
- 命名規約で防げるのは型の混在・同義語・区分語の付け忘れ。値の範囲(ドメイン)は防げない
ひっかけ
- 「主キーは1列」「先頭の列」「計算できない」のように余計な制限が付いた選択肢は誤り。正解は「重複しない」「空でない」
- UPDATE の WHERE が主キー以外の列(在庫数・商品名など)だと、当てはまる行が複数になりやすい。主キーの列を1つの値に書き換える文を見たら、当てはまる行数を必ず数える
- NULL を含む行の INSERT を UNIQUE 制約違反だと思い込ませる。NULL を含む組は重複とみなされない
- 外部キーの目的として、高速化・障害復旧・虫食い防止を混ぜてくる。正解は参照の一貫性だけ
- 子表の削除や、参照されていない親表の行の削除は問題ない。違反になるのは、親表に無い値を子表に追加する操作と、参照されている親表の行の削除
用語(14)
表の中の1行を1つに特定するための列(または列の組み合わせ)で、値の重複と NULL が許されない。
⚠ 一意性制約(UNIQUE)とは、NULL を入れられない点が違う。
2つ以上の列を組み合わせて作るキー。
⚠ 「主キーは1列でなければならない」は誤り。複合キーを主キーにしてよい。
行を1つに特定できる最小限の列の組で、主キーにできる候補になるもの。
⚠ 候補キーの中から1つ選んだものが主キー。
値が入っていない・決まっていないことを表す特別な状態。
⚠ 0 や空文字とは別物。NULL との比較(>= など)は成り立たないので、WHERE の条件に当てはまらない。
指定した列(または列の組)の値が重複しないことを保証する制約。
⚠ 主キー制約と違って NULL を入れられ、NULL を含む組は重複とみなされない。
主キー列について、値が重複しないことと NULL でないことを保証する制約。
⚠ 一意性制約と合わせて「キー制約」と呼ぶ。参照制約とは別。
他の表の主キーの値を持ち、その表の行を参照する列。
⚠ 主キーと違い、外部キーは同じ値が何度出てきてもよい。
外部キーの値が、参照先の表の主キーに存在することを保証する制約で、FOREIGN KEY と REFERENCES で指定する。
⚠ キー制約(PRIMARY KEY・UNIQUE)や検査制約(CHECK)と、SQL のキーワードで見分ける。
子表の外部キーが、親表に存在する行だけを指している状態。
⚠ 外部キーの目的はこれだけ。高速化・障害復旧・虫食い防止は無関係。
列の値が指定した条件(範囲など)を満たすことを保証する制約。
⚠ 参照制約は他の表との関係を見るが、検査制約は自分の表の値の条件だけを見る。
複数の表にまたがる条件をデータベース全体の制約として宣言するもの。
⚠ 1つの表の値の条件を定める検査制約と区別する。
参照される側の表を親表、外部キーを持って参照する側の表を子表と呼ぶ。
⚠ 新しく入力するのは親表が先。削除で問題になるのは、参照されている親表の行。
あるデータ項目が取り得る値の範囲や種類。
⚠ データ型(数値型・日付型など)とは別。命名規約で型はそろえられるが、ドメインはそろえられない。
異音同義語は名前が違うのに意味が同じ項目、同音異義語は名前が同じなのに意味が違う項目。
⚠ どちらも項目名と意味を登録した辞書で防げる。命名規約で防げないのは値の範囲。
このレッスンの過去問
- 主キーの性質平成25年度 秋期 基本情報技術者試験 午前 問30
- 主キー制約違反の判定(UPDATE文)令和8年度 基本情報技術者試験 科目A 公開問題 問7
- 外部キー定義の目的(参照整合性)平成29年度 秋期 基本情報技術者試験 午前 問27
- 参照整合性制約による操作可否の判定平成24年度 秋期 基本情報技術者試験 午前 問31
- データ項目命名規約の限界平成30年度 秋期 基本情報技術者試験 午前 問27