関数従属と正規化(第1〜第3正規形)
表の値や矢印の図から関数従属を読み取り、部分関数従属・推移的関数従属を見つけて第3正規形の表に分解できるようになる。正規化の目的と、第1〜第3正規形の違いも選択肢で見分けられるようになる。
データベース分野の科目Aでよく出る定番テーマで、第3正規形への分解だけでも公開過去問で38回観測されている(うち本試験系6回・免除32回)。実務では「同じ情報があちこちにあって、直し漏れでデータが食い違う」事故を防ぐ設計の基本になる。
このレッスンで稽古する(用語チェック・過去問)結論:正規化は「1つの事実は1か所にだけ書く」ための作業
正規化とは、データの重複(冗長性)をなくすように表を分けることです。目的は格納効率ではなく、**データを登録・変更・削除するときに矛盾が起きないようにする(更新時異状の回避)**ことです。
たとえば注文表の各行に顧客の住所を書いていると、顧客が引っ越したときにその顧客の全注文行を直す必要があります。1行でも直し忘れると、同じ顧客に住所が2つある状態になります。住所を「顧客表」に1回だけ書いておけば、直す場所は1か所で済みます。
試験の正解の言い回しは「冗長性を排除して更新時異状を回避する」「データの重複を避け、保守・管理を容易にする」です。
更新時異状は3種類
正規化していない表で起きる不具合をまとめて更新時異状(更新時異常)と呼びます。
| 異状 | 何が起きるか | 例(注文表に顧客住所も入っている場合) |
|---|---|---|
| 挿入時異状 | 登録したい情報があるのに登録できない | まだ注文していない新規顧客の住所を登録できない |
| 修正時異状 | 一部の行だけ直されて矛盾が残る | 住所変更で一部の注文行だけ直してしまう |
| 削除時異状 | 消したくない情報まで消える | 注文を削除したら、その顧客の住所情報もなくなる |
正規化の主な目的は、この3つを防ぐことです。「検索が速くなる」「記憶容量が減る」は主目的ではありません。むしろ表が増えるので、検索では結合(JOIN)が必要になります。
関数従属:X → Y の読み方と、表の値からの判定
関数従属 X → Y とは、「Xの値が決まれば、Yの値がただ1つに決まる」という関係です。例として、社員番号 → 社員名 があります。社員番号が分かれば社員名は1つに決まります。
表の値から判定するコツは、反例を1つ探すことです。
- Xが同じ値の行を集める
- その中でYが2種類以上あれば、X → Y は成立しない
- どのXの値でもYが1種類だけなら、その表の中では成立する
Xの値が全部違うときは、反例がないので成立します。なお、行が重複していても判定には影響しません。
3種類の従属を区別する(ここが正規化の核心)
まず用語を2つ押さえます。候補キーは、行を1つに特定できる最小の属性の組です(主キーはその中から選んだもの)。非キー属性は、どの候補キーにも含まれない属性です。
| 従属の種類 | 形 | 具体例 | 何正規形で解消するか |
|---|---|---|---|
| 完全関数従属 | 複合キー全体 → Y(キーの一部だけでは決まらない) | {注文番号, 商品番号} → 数量 | 問題なし(このまま残す) |
| 部分関数従属 | 複合キーの一部 → Y | {注文番号, 商品番号} のうち 商品番号 → 商品名 | 第2正規形で解消 |
| 推移的関数従属 | キー → 非キーB → C(Bからキーは決まらない) | 注文番号 → 顧客番号 → 顧客名 | 第3正規形で解消 |
見分け方は「矢印の出発点がどこか」です。出発点がキーの一部なら部分関数従属、非キー属性なら推移的関数従属です。
注意:主キーが1つの属性だけなら、部分関数従属は起こりえません(「キーの一部」が存在しないため)。
第1〜第3正規形の違い
正規形は階段のように積み上がります。第3正規形は第2正規形の条件も、第1正規形の条件も満たします。
| 正規形 | 条件(前の段の条件に加えて) | 何を取り除いたか |
|---|---|---|
| 第1正規形 | 1つのマスに値が1つだけ。繰返し項目がない | 繰返し項目(1行に商品1・商品2・商品3…と並ぶ列) |
| 第2正規形 | 非キー属性が、候補キー全体に完全関数従属する | 部分関数従属 |
| 第3正規形 | 非キー属性が、候補キーに推移的関数従属しない | 推移的関数従属 |
| (参考)ボイス・コッド正規形 | すべての関数従属の出発点が候補キー | 第3正規形よりさらに厳しい形。基本情報では名前を知っておく程度でよい |
第1正規形になっていない表(1つのマスに複数の値が入っている表)は、非正規形または入れ子型リレーションと呼ばれます。
分解の手順:矢印の出発点ごとに表を作る
関数従属が矢印の一覧で与えられたら、次の3ステップで第3正規形に分解できます。
- 矢印の出発点(決める側)ごとに表を1つ作る。出発点がその表の主キーになる
- その表に、出発点から直接矢印が出ている属性だけを入れる
- 別の表の主キーになった属性も、元の表に残す(外部キーとして表同士をつなぐため)
手順3が最大のひっかけです。たとえば a → b、b → f のとき、表(a, b) と 表(b, f) に分けます。表(a) から b を消すと、a と f をつなげなくなります。
flowchart LR
A["a(主キー)"] --> B["b"]
A --> C["c"]
A --> D["d"]
A --> E["e"]
B --> F["f, g, h"]
E --> I["i, j"]
この図では、出発点は a・b・e の3つなので表も3つです。答えは (a, b, c, d, e)・(b, f, g, h)・(e, i, j) になります。
試験での問われ方
- 目的を問う:「格納効率の向上」「検索の効率化」「整合性制約の排除」「ロック待ちを減らす」は誤りです。正解は「冗長性の排除で更新時異状を回避」です。
- 表の値から関数従属を選ぶ:選択肢ごとに反例(同じXでYが違う行)を探します。
- 矢印の図から分解した表の組合せを選ぶ(最頻出):外部キーを残さない選択肢がひっかけです。
- 推移的関数従属を選ぶ:与えられた矢印を本当につなげられるかを1本ずつ確かめます。
- 何正規形かを問う:部分関数従属と推移的関数従属があるかを順に調べます。
- 正規化の説明を選ぶ:分けた表の主キーが非キー属性(例:商品コード)なら推移的関数従属の解消、主キーの一部なら部分関数従属の解消です。
表の値から、成立している関数従属を選ぶ
| 配送日 | 部署 ID | 部署名 | 配送先 | 部品 ID | 数量 |
|---|---|---|---|---|---|
| 2016-08-21 | 300 | 第二生産部 | 秋田事業所 | 1342 | 300 |
| 2016-08-21 | 300 | 第二生産部 | 秋田事業所 | 1342 | 300 |
| 2016-08-25 | 400 | 第一生産部 | 名古屋工場 | 2346 | 300 |
| 2016-08-25 | 400 | 第一生産部 | 名古屋工場 | 2346 | 1,000 |
| 2016-08-30 | 500 | 研究開発部 | 名古屋工場 | 2346 | 30 |
| 2016-08-30 | 500 | 研究開発部 | 川崎事業所 | 1342 | 30 |
ア 配送先 → 部品 ID
イ 配送日 → 部品 ID
ウ 部署 ID → 部品 ID
エ 部署名 → 配送先
解き方と答えを見る
- 方針:選択肢ごとに、左辺が同じ値の行を集め、右辺が2種類以上ある反例を探す。反例が1つでもあれば不成立。
- イ 配送日 → 部品ID:2016-08-30 の2行で部品IDが 2346 と 1342 に分かれる。反例ありなので不成立。
- ウ 部署ID → 部品ID:部署ID 500 の2行で部品IDが 2346 と 1342 に分かれる。反例ありなので不成立。
- エ 部署名 → 配送先:研究開発部の2行で配送先が名古屋工場と川崎事業所に分かれる。反例ありなので不成立。
- ア 配送先 → 部品ID:秋田事業所の2行はどちらも 1342。名古屋工場の3行はすべて 2346。川崎事業所の1行は 1342。どの配送先でも部品IDは1種類なので成立。
答え:ア(配送先 → 部品ID)
矢印の図から3つのテーブルに分解する(2017h29h_am#25 も同じ問題)
ア テーブル1 (a)
テーブル2 (b, c, d, e)
テーブル3 (f, g, h, i, j)
イ テーブル1 (a, b, c, d, e)
テーブル2 (b, f, g, h)
テーブル3 (e, i, j)
ウ テーブル1 (a, b, f, g, h)
テーブル2 (c, d)
テーブル3 (e, i, j)
エ テーブル1 (a, c, d)
テーブル2 (b, f, g, h)
テーブル3 (e, i, j)
解き方と答えを見る
- 矢印の出発点を数える:a(→ b, c, d, e)、b(→ f, g, h)、e(→ i, j)の3つなので、表は3つになる。
- a を主キーとする表に、a から直接決まる b, c, d, e を入れる → (a, b, c, d, e)。
- b を主キーとする表 → (b, f, g, h)。f, g, h は a から見ると a → b → f という推移的関数従属なので、a の表から外す。
- e を主キーとする表 → (e, i, j)。i, j も a の表から外す。
- b と e は a の表に外部キーとして残す。これで3つの表を結合して元の情報に戻せる。
- ア・ウ・エは、b や e を a の表から外していたり、b, c, d, e を a と別の表にしていたりして、a と結合できない。
答え:イ:(a, b, c, d, e)・(b, f, g, h)・(e, i, j)
注文記録を第3正規形に分解したときの「注文明細」を選ぶ
ア 注文明細 (_注文番号_, 数量, 販売単価)
イ 注文明細 (_注文番号_, _顧客番号_, 数量, 販売単価)
ウ 注文明細 (_注文番号_, _顧客番号_, _商品番号_, 顧客名, 数量, 販売単価)
エ 注文明細 (_注文番号_, _商品番号_, 数量, 販売単価)
解き方と答えを見る
- 主キーを確認する:1回の注文で複数の商品を買えるので、行を特定するには {注文番号, 商品番号} が必要。
- {注文番号, 商品番号} 全体で決まる属性(完全関数従属)は、④⑤より 数量・販売単価。これが注文明細に入る。
- 注文番号だけで決まる 注文日・顧客番号(①②)はキーの一部への部分関数従属なので、「注文」表に分ける。
- 商品番号だけで決まる 商品名(⑥)も部分関数従属なので、「商品」表に分ける。
- 顧客番号 → 顧客名(③)は 注文番号 → 顧客番号 → 顧客名 の推移的関数従属なので、「顧客」表に分ける。
- したがって注文明細は (注文番号, 商品番号, 数量, 販売単価) で、主キーは注文番号と商品番号の組。
- アは主キーが注文番号だけで、行を特定できない。イ・ウは顧客番号・顧客名が入っていて、推移的関数従属が残る。
答え:エ:注文明細(注文番号, 商品番号, 数量, 販売単価)※下線は注文番号と商品番号
成立する推移的関数従属を選ぶ
ア 仕入先コード → 仕入担当者コード → 仕入先住所
イ 商品コード → 仕入先コード → 商品販売価格
ウ 注文コード → 顧客コード → 顧客住所
エ 注文コード → 商品コード → 顧客注文数量
出典:令和5年度 基本情報技術者試験 科目A 公開問題 問6
解き方と答えを見る
- 方針:A → B → C の2本の矢印が、与えられた関数従属の中に両方あるかを確かめる。
- ア 仕入先コード → 仕入担当者コード は与えられているが、仕入担当者コード → 仕入先住所 はどこにもない。不成立。
- イ 仕入先コード → 商品販売価格 はない(商品販売価格を決めるのは商品コード)。不成立。
- エ 注文コード → 商品コード はない(1つの注文に複数の商品がありうる)。商品コード → 顧客注文数量 もない(数量を決めるのは注文コードと商品コードの組)。不成立。
- ウ 注文コード → 顧客コード は2行目にあり、顧客コード → 顧客住所 は5行目にある。1人の顧客は何度も注文するので、顧客コード → 注文コード は成り立たない。推移的関数従属の条件を満たす。
答え:ウ(注文コード → 顧客コード → 顧客住所)
関係R(A, B, C, D) が何正規形まで満たすかを判定する
ア 第1正規形
イ 第2正規形
ウ 第3正規形
エ 第4正規形
出典:基本情報技術者試験 科目A免除 修了試験 20260614 実施分 問19
解き方と答えを見る
- 前提:「正規化されている」とあるので、第1正規形は満たす。
- 第2正規形の判定:唯一の候補キーは A の1属性だけ。キーの一部が存在しないので、部分関数従属は起こりえない。よって第2正規形を満たす。
- 第3正規形の判定:A → B かつ B → D。B は候補キーではない非キー属性なので、A → B → D は推移的関数従属になる。
- 推移的関数従属が残っているので、第3正規形は満たさない。
- D を R から外して (B, D) を別の表にすれば、第3正規形になる。
答え:イ(第2正規形)
要点(試験直前に読む)
- 正規化の目的は「冗長性を排除して更新時異状(挿入・修正・削除)を回避すること」。検索の高速化や容量削減は主目的ではない。
- 第1正規形=繰返し項目なし、第2正規形=部分関数従属なし、第3正規形=推移的関数従属なし。
- 矢印の出発点がキーの一部なら部分関数従属、非キー属性なら推移的関数従属。主キーが1属性なら部分関数従属は起こらない。
- 表の値から関数従属を判定するときは、同じXでYが違う反例を1つ探す。
- 分解は「矢印の出発点ごとに1表」。出発点の属性は元の表に外部キーとして残す。
ひっかけ
- 「格納効率の向上」「検索の効率化」「整合性制約の排除」は正規化の目的ではない。正解の決め手は「更新時異状の回避」「重複を避けて保守を容易に」。
- 分解の組合せ問題では、b や e のような中継の属性を元の表から外した選択肢が罠。外部キーとして残っているかを必ず確認する。
- 推移的関数従属を選ぶ問題では、選択肢の矢印2本が与えられた従属に本当にあるかを1本ずつ確かめる。もっともらしい連鎖でも、1本でも無ければ不成立。
- 「何正規形か」の問題で、候補キーが1属性なのに部分関数従属を疑って第1正規形と答えない。1属性キーなら第2正規形までは自動的に満たす。
- 分けた表の主キーが商品コードのような非キー属性なら、推移的関数従属の解消(第3正規形化)。部分関数従属(第2正規形化)と取り違えない。
用語(15)
データの重複がなくなるように表を分け、更新時異状を防ぐ設計作業。
⚠ 目的は「検索の高速化」や「記憶容量の削減」ではない。結合が増えるので、検索はむしろ遅くなることもある。
同じ事実が複数の行や表に重複して記録されている状態。
冗長な表で、挿入・修正・削除のときに登録できない・矛盾する・消えすぎるといった不具合が起きること。
⚠ 「整合性制約」は異状を防ぐためのルール。正規化で整合性制約を排除するわけではない。
Xの値が決まるとYの値がただ1つに決まる関係で、X → Y と書く。
⚠ 表の値で判定するときは、同じXでYが違う行が1つでもあれば不成立。
Yが複合キー全体で初めて決まり、キーの一部だけでは決まらない従属。
⚠ 部分関数従属は、キーの一部だけでYが決まる場合。
非キー属性が、複合キーの一部の属性だけで決まってしまう従属。
⚠ 推移的関数従属との違いは矢印の出発点。キーの一部から出ていれば部分、非キー属性から出ていれば推移的。主キーが1属性なら部分関数従属は起こらない。
A → B かつ B → C が成り立ち、B → A は成り立たないときの A → C の従属。
⚠ 部分関数従属と混同しやすい。中継役のBが非キー属性なら推移的関数従属。
表の行を1つに特定できる、最小の属性の組。
⚠ 主キーは、候補キーの中から1つ選んだもの。
どの候補キーにも含まれない属性。
⚠ 外部キーであっても、候補キーに含まれなければ非キー属性として扱う(例:受注明細の商品コード)。
各マスに値が1つだけ入り、繰返し項目がない表。
⚠ 繰返し項目を除いただけで満たすのは第1正規形まで。第2・第3正規形は従属関係の条件も必要。
第1正規形で、さらに部分関数従属がない(非キー属性が候補キー全体に完全関数従属する)表。
⚠ 第3正規形は、さらに推移的関数従属もない表。
第2正規形で、さらに非キー属性の推移的関数従属がない表。
⚠ ボイス・コッド正規形は、すべての関数従属の出発点が候補キーという、より厳しい形。
すべての関数従属の決める側が候補キーになっている、第3正規形より厳しい正規形。
⚠ 選択肢に出ても、繰返し項目の除去や推移的関数従属の解消の答えにはならない。
1つのマスの中に複数の値や表が入っている、第1正規形を満たさない表(非正規形)。
⚠ 入れ子型の解消は第1正規形化のこと。推移的関数従属の解消(第3正規形化)とは別。
他の表の主キーを参照する属性で、分解した表どうしをつなぐもの。
⚠ 分解のときに外部キーを元の表から消すと、表を結合できなくなる。これが分解問題の典型的なひっかけ。
このレッスンの過去問
- 正規化の目的(更新時異状の回避)平成26年度 秋期 基本情報技術者試験 午前 問28
- 第1正規形の定義(反復項目の除去)基本情報技術者試験 科目A免除 修了試験 200907 実施分 問32
- 関数従属性の成立判定(表の値から)平成28年度 秋期 基本情報技術者試験 午前 問27
- 関数従属性に基づく第3正規形への分解平成29年度 春期 基本情報技術者試験 午前 問25
- 推移的関数従属の特定(正規化理論)令和5年度 基本情報技術者試験 科目A 公開問題 問6