資格道場 › レッスン一覧 › データベース
データベース・4/13・13分

関数従属と正規化(第1〜第3正規形)

ゴール

表の値や矢印の図から関数従属を読み取り、部分関数従属・推移的関数従属を見つけて第3正規形の表に分解できるようになる。正規化の目的と、第1〜第3正規形の違いも選択肢で見分けられるようになる。

データベース分野の科目Aでよく出る定番テーマで、第3正規形への分解だけでも公開過去問で38回観測されている(うち本試験系6回・免除32回)。実務では「同じ情報があちこちにあって、直し漏れでデータが食い違う」事故を防ぐ設計の基本になる。

このレッスンで稽古する(用語チェック・過去問)

結論:正規化は「1つの事実は1か所にだけ書く」ための作業

正規化とは、データの重複(冗長性)をなくすように表を分けることです。目的は格納効率ではなく、**データを登録・変更・削除するときに矛盾が起きないようにする(更新時異状の回避)**ことです。

たとえば注文表の各行に顧客の住所を書いていると、顧客が引っ越したときにその顧客の全注文行を直す必要があります。1行でも直し忘れると、同じ顧客に住所が2つある状態になります。住所を「顧客表」に1回だけ書いておけば、直す場所は1か所で済みます。

試験の正解の言い回しは「冗長性を排除して更新時異状を回避する」「データの重複を避け、保守・管理を容易にする」です。

分ける前:注文のたびに住所を書く注文番号顧客住所1C1新住所2C1新住所3C1旧住所1行だけ直し忘れ → 同じ顧客に住所が2つ分けた後:住所は顧客表に1回だけ顧客表注文表顧客住所C1新住所注文番号顧客1C12C13C1注文表の顧客からたどって住所を見る住所が変わっても直すのは1か所
注文表に住所を毎回書くと直し忘れで住所が2つになるが、顧客表に分けると直す場所は1か所で済む。

更新時異状は3種類

正規化していない表で起きる不具合をまとめて更新時異状(更新時異常)と呼びます。

異状 何が起きるか 例(注文表に顧客住所も入っている場合)
挿入時異状 登録したい情報があるのに登録できない まだ注文していない新規顧客の住所を登録できない
修正時異状 一部の行だけ直されて矛盾が残る 住所変更で一部の注文行だけ直してしまう
削除時異状 消したくない情報まで消える 注文を削除したら、その顧客の住所情報もなくなる

正規化の主な目的は、この3つを防ぐことです。「検索が速くなる」「記憶容量が減る」は主目的ではありません。むしろ表が増えるので、検索では結合(JOIN)が必要になります。

関数従属:X → Y の読み方と、表の値からの判定

関数従属 X → Y とは、「Xの値が決まれば、Yの値がただ1つに決まる」という関係です。例として、社員番号 → 社員名 があります。社員番号が分かれば社員名は1つに決まります。

表の値から判定するコツは、反例を1つ探すことです。

  • Xが同じ値の行を集める
  • その中でYが2種類以上あれば、X → Y は成立しない
  • どのXの値でもYが1種類だけなら、その表の中では成立する

Xの値が全部違うときは、反例がないので成立します。なお、行が重複していても判定には影響しません。

同じXの行を集めて、Yの種類を数えるXY10A20B10C20BX=10 の行Y は A と C → 2種類X=20 の行Y は B だけ → 1種類反例が1つあれば X → Y は成立しない
Xが同じ行を集め、その中でYが2種類以上あれば反例となり X → Y は成立しない。

3種類の従属を区別する(ここが正規化の核心)

まず用語を2つ押さえます。候補キーは、行を1つに特定できる最小の属性の組です(主キーはその中から選んだもの)。非キー属性は、どの候補キーにも含まれない属性です。

従属の種類 形 具体例 何正規形で解消するか
完全関数従属 複合キー全体 → Y(キーの一部だけでは決まらない) {注文番号, 商品番号} → 数量 問題なし(このまま残す)
部分関数従属 複合キーの一部 → Y {注文番号, 商品番号} のうち 商品番号 → 商品名 第2正規形で解消
推移的関数従属 キー → 非キーB → C(Bからキーは決まらない) 注文番号 → 顧客番号 → 顧客名 第3正規形で解消

見分け方は「矢印の出発点がどこか」です。出発点がキーの一部なら部分関数従属、非キー属性なら推移的関数従属です。

注意:主キーが1つの属性だけなら、部分関数従属は起こりえません(「キーの一部」が存在しないため)。

完全関数従属:出発点はキー全体注文番号商品番号数量問題なし(このまま残す)部分関数従属:出発点はキーの一部注文番号商品番号商品名第2正規形で解消推移的関数従属:出発点は非キー注文番号顧客番号顧客名キー非キー第3正規形で解消
矢印の出発点がキー全体か、キーの一部か、非キー属性かで3種類の従属を見分ける。

第1〜第3正規形の違い

正規形は階段のように積み上がります。第3正規形は第2正規形の条件も、第1正規形の条件も満たします。

正規形 条件(前の段の条件に加えて) 何を取り除いたか
第1正規形 1つのマスに値が1つだけ。繰返し項目がない 繰返し項目(1行に商品1・商品2・商品3…と並ぶ列)
第2正規形 非キー属性が、候補キー全体に完全関数従属する 部分関数従属
第3正規形 非キー属性が、候補キーに推移的関数従属しない 推移的関数従属
(参考)ボイス・コッド正規形 すべての関数従属の出発点が候補キー 第3正規形よりさらに厳しい形。基本情報では名前を知っておく程度でよい

第1正規形になっていない表(1つのマスに複数の値が入っている表)は、非正規形または入れ子型リレーションと呼ばれます。

分解の手順:矢印の出発点ごとに表を作る

関数従属が矢印の一覧で与えられたら、次の3ステップで第3正規形に分解できます。

  1. 矢印の出発点(決める側)ごとに表を1つ作る。出発点がその表の主キーになる
  2. その表に、出発点から直接矢印が出ている属性だけを入れる
  3. 別の表の主キーになった属性も、元の表に残す(外部キーとして表同士をつなぐため)

手順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) になります。

出発点 a・b・e ごとに表を作る表1(主キー a)abcdebfgheij表2(主キー b)表3(主キー e)表1の b・e は消さない(外部キー)消すと a から f や i にたどれない
出発点 a・b・e ごとに3つの表を作り、表1には b と e を外部キーとして残す。

試験での問われ方

  • 目的を問う:「格納効率の向上」「検索の効率化」「整合性制約の排除」「ロック待ちを減らす」は誤りです。正解は「冗長性の排除で更新時異状を回避」です。
  • 表の値から関数従属を選ぶ:選択肢ごとに反例(同じXでYが違う行)を探します。
  • 矢印の図から分解した表の組合せを選ぶ(最頻出):外部キーを残さない選択肢がひっかけです。
  • 推移的関数従属を選ぶ:与えられた矢印を本当につなげられるかを1本ずつ確かめます。
  • 何正規形かを問う:部分関数従属と推移的関数従属があるかを順に調べます。
  • 正規化の説明を選ぶ:分けた表の主キーが非キー属性(例:商品コード)なら推移的関数従属の解消、主キーの一部なら部分関数従属の解消です。
例題 1

表の値から、成立している関数従属を選ぶ

6 行だけから成る“配送”表において成立している関数従属はどれか。ここで,X→Y は,X は Y を関数的に決定することを表す。
配送表:
配送日部署 ID部署名配送先部品 ID数量
2016-08-21300第二生産部秋田事業所1342300
2016-08-21300第二生産部秋田事業所1342300
2016-08-25400第一生産部名古屋工場2346300
2016-08-25400第一生産部名古屋工場23461,000
2016-08-30500研究開発部名古屋工場234630
2016-08-30500研究開発部川崎事業所134230

ア 配送先 → 部品 ID
イ 配送日 → 部品 ID
ウ 部署 ID → 部品 ID
エ 部署名 → 配送先

出典:平成28年度 秋期 基本情報技術者試験 午前 問27

解き方と答えを見る
  1. 方針:選択肢ごとに、左辺が同じ値の行を集め、右辺が2種類以上ある反例を探す。反例が1つでもあれば不成立。
  2. イ 配送日 → 部品ID:2016-08-30 の2行で部品IDが 2346 と 1342 に分かれる。反例ありなので不成立。
  3. ウ 部署ID → 部品ID:部署ID 500 の2行で部品IDが 2346 と 1342 に分かれる。反例ありなので不成立。
  4. エ 部署名 → 配送先:研究開発部の2行で配送先が名古屋工場と川崎事業所に分かれる。反例ありなので不成立。
  5. ア 配送先 → 部品ID:秋田事業所の2行はどちらも 1342。名古屋工場の3行はすべて 2346。川崎事業所の1行は 1342。どの配送先でも部品IDは1種類なので成立。

答え:ア(配送先 → 部品ID)

例題 2

矢印の図から3つのテーブルに分解する(2017h29h_am#25 も同じ問題)

項目 a の値が決まれば項目 b の値が一意に定まることを,a → b で表す。例えば,社員番号が決まれば社員名が一意に定まるという表現は,社員番号 → 社員名である。この表記法に基づいて,図の関係が成立している項目 a 〜 j を,関係データベース上の三つのテーブルで定義する組合せとして,適切なものはどれか。
関数従属の図: a → b, a → c, a → d, a → e b → f, b → g, b → h e → i, e → j

ア テーブル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)

出典:平成26年度 春期 基本情報技術者試験 午前 問26

解き方と答えを見る
  1. 矢印の出発点を数える:a(→ b, c, d, e)、b(→ f, g, h)、e(→ i, j)の3つなので、表は3つになる。
  2. a を主キーとする表に、a から直接決まる b, c, d, e を入れる → (a, b, c, d, e)。
  3. b を主キーとする表 → (b, f, g, h)。f, g, h は a から見ると a → b → f という推移的関数従属なので、a の表から外す。
  4. e を主キーとする表 → (e, i, j)。i, j も a の表から外す。
  5. b と e は a の表に外部キーとして残す。これで3つの表を結合して元の情報に戻せる。
  6. ア・ウ・エは、b や e を a の表から外していたり、b, c, d, e を a と別の表にしていたりして、a と結合できない。

答え:イ:(a, b, c, d, e)・(b, f, g, h)・(e, i, j)

例題 3

注文記録を第3正規形に分解したときの「注文明細」を選ぶ

関係 “注文記録” の属性間に ①~⑥ の関数従属性があり,それに基づいて第 3 正規形まで正規化を行って,“商品”,“顧客”,“注文”,“注文明細” の各関係に分解した。関係 “注文明細” として,適切なものはどれか。ここで,{X, Y} は,属性 X と Y の組みを表し,X → Y は,X が Y を関数的に決定することを表す。また,実線の下線は主キーを表す。
注文記録 (注文番号,注文日,顧客番号,顧客名,商品番号,商品名,数量,販売単価) 〔関数従属性〕 ① 注文番号 → 注文日 ② 注文番号 → 顧客番号 ③ 顧客番号 → 顧客名 ④ {注文番号,商品番号} → 数量 ⑤ {注文番号,商品番号} → 販売単価 ⑥ 商品番号 → 商品名 (選択肢中の _..._ は原文で実線の下線(主キー)が引かれている属性。ア: 注文番号/イ: 注文番号,顧客番号/ウ: 注文番号,顧客番号,商品番号(それぞれ個別に下線)/エ: 注文番号,商品番号(それぞれ個別に下線))

ア 注文明細 (_注文番号_, 数量, 販売単価)
イ 注文明細 (_注文番号_, _顧客番号_, 数量, 販売単価)
ウ 注文明細 (_注文番号_, _顧客番号_, _商品番号_, 顧客名, 数量, 販売単価)
エ 注文明細 (_注文番号_, _商品番号_, 数量, 販売単価)

出典:平成27年度 秋期 基本情報技術者試験 午前 問27

解き方と答えを見る
  1. 主キーを確認する:1回の注文で複数の商品を買えるので、行を特定するには {注文番号, 商品番号} が必要。
  2. {注文番号, 商品番号} 全体で決まる属性(完全関数従属)は、④⑤より 数量・販売単価。これが注文明細に入る。
  3. 注文番号だけで決まる 注文日・顧客番号(①②)はキーの一部への部分関数従属なので、「注文」表に分ける。
  4. 商品番号だけで決まる 商品名(⑥)も部分関数従属なので、「商品」表に分ける。
  5. 顧客番号 → 顧客名(③)は 注文番号 → 顧客番号 → 顧客名 の推移的関数従属なので、「顧客」表に分ける。
  6. したがって注文明細は (注文番号, 商品番号, 数量, 販売単価) で、主キーは注文番号と商品番号の組。
  7. アは主キーが注文番号だけで、行を特定できない。イ・ウは顧客番号・顧客名が入っていて、推移的関数従属が残る。

答え:エ:注文明細(注文番号, 商品番号, 数量, 販売単価)※下線は注文番号と商品番号

例題 4

成立する推移的関数従属を選ぶ

次の関数従属を満足するとき,成立する推移的関数従属はどれか。ここで,“A → B”は B が A に関数従属していることを表し,“A→{B,C}”は,“A→B”かつ“A→C”が成立することを表す。
〔関数従属〕 {注文コード,商品コード}→{顧客注文数量,注文金額} 注文コード →{注文日,顧客コード,注文担当者コード} 商品コード →{商品名,仕入先コード,商品販売価格} 仕入先コード →{仕入先名,仕入先住所,仕入担当者コード} 顧客コード →{顧客名,顧客住所}

ア 仕入先コード → 仕入担当者コード → 仕入先住所
イ 商品コード → 仕入先コード → 商品販売価格
ウ 注文コード → 顧客コード → 顧客住所
エ 注文コード → 商品コード → 顧客注文数量

出典:令和5年度 基本情報技術者試験 科目A 公開問題 問6

解き方と答えを見る
  1. 方針:A → B → C の2本の矢印が、与えられた関数従属の中に両方あるかを確かめる。
  2. ア 仕入先コード → 仕入担当者コード は与えられているが、仕入担当者コード → 仕入先住所 はどこにもない。不成立。
  3. イ 仕入先コード → 商品販売価格 はない(商品販売価格を決めるのは商品コード)。不成立。
  4. エ 注文コード → 商品コード はない(1つの注文に複数の商品がありうる)。商品コード → 顧客注文数量 もない(数量を決めるのは注文コードと商品コードの組)。不成立。
  5. ウ 注文コード → 顧客コード は2行目にあり、顧客コード → 顧客住所 は5行目にある。1人の顧客は何度も注文するので、顧客コード → 注文コード は成り立たない。推移的関数従属の条件を満たす。

答え:ウ(注文コード → 顧客コード → 顧客住所)

例題 5

関係R(A, B, C, D) が何正規形まで満たすかを判定する

正規化されている関係R(A,B,C,D)において,属性Aが関係Rの唯一の候補キーであり,関数従属A→{B,C,D}とB→Dが成立するとき,関係Rはどのレベルの正規形の条件まで満足しているか。

ア 第1正規形
イ 第2正規形
ウ 第3正規形
エ 第4正規形

出典:基本情報技術者試験 科目A免除 修了試験 20260614 実施分 問19

解き方と答えを見る
  1. 前提:「正規化されている」とあるので、第1正規形は満たす。
  2. 第2正規形の判定:唯一の候補キーは A の1属性だけ。キーの一部が存在しないので、部分関数従属は起こりえない。よって第2正規形を満たす。
  3. 第3正規形の判定:A → B かつ B → D。B は候補キーではない非キー属性なので、A → B → D は推移的関数従属になる。
  4. 推移的関数従属が残っているので、第3正規形は満たさない。
  5. 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つだけ入り、繰返し項目がない表。
⚠ 繰返し項目を除いただけで満たすのは第1正規形まで。第2・第3正規形は従属関係の条件も必要。
第2正規形 だいにせいきけい
第1正規形で、さらに部分関数従属がない(非キー属性が候補キー全体に完全関数従属する)表。
⚠ 第3正規形は、さらに推移的関数従属もない表。
第3正規形 だいさんせいきけい
第2正規形で、さらに非キー属性の推移的関数従属がない表。
⚠ ボイス・コッド正規形は、すべての関数従属の出発点が候補キーという、より厳しい形。
ボイス・コッド正規形 Boyce-Codd Normal Form(BCNF)
すべての関数従属の決める側が候補キーになっている、第3正規形より厳しい正規形。
⚠ 選択肢に出ても、繰返し項目の除去や推移的関数従属の解消の答えにはならない。
入れ子型リレーション いれこがたりれーしょん
1つのマスの中に複数の値や表が入っている、第1正規形を満たさない表(非正規形)。
⚠ 入れ子型の解消は第1正規形化のこと。推移的関数従属の解消(第3正規形化)とは別。
外部キー がいぶきー
他の表の主キーを参照する属性で、分解した表どうしをつなぐもの。
⚠ 分解のときに外部キーを元の表から消すと、表を結合できなくなる。これが分解問題の典型的なひっかけ。

このレッスンの過去問

このレッスンで稽古する