応用情報 科目A #13:データベースのキー・関数従属性・正規化

応用情報技術者試験の科目Aに必要な候補キー・主キー・外部キー、属性閉包、完全・部分・推移関数従属、更新時異状、第1〜第3正規形と無損失分解、BCNFの境界を、例題とオリジナル演習問題5問で学びます。

応用情報技術者試験科目Aデータベース正規化関数従属

AP科目A・第13回 · 2026年度・シラバスVer.7.2に基づく独立した学習資料です。IPAとの提携はなく、合格を保証しません。 シリーズ一覧を見る

IPAとは無関係の独自学習ノートであり、第三者の解説の転載はなく、過去問題も使用しておらず、合格を保証するものではありません。

学習インデックス

1. 公式の出題範囲

  • 出典:IPA 応用情報技術者試験(レベル3)シラバス Ver.7.2 — https://www.ipa.go.jp/shiken/syllabus/omgdg50000005kq5-att/syllabus_ap_ver7_2.pdf(2026-10-21確認、データベース設計・正規化はPDF 42–43ページ(印刷38–39ページ)、データ中心設計はPDF 67ページ(印刷63ページ))
  • 階層マッピング:
    • 大分類3 技術要素 › 中分類9 データベース › 2. データベース設計
      • (1) データ分析 — 用語例:データ重複の排除
      • (2) データベースの設計 › ③ データベースの論理設計 — 主キー・外部キー、一貫性制約(一意性制約、参照制約、検査制約)
      • (3) データの正規化 — 第1正規形,第2正規形,第3正規形など;用語例:完全関数従属、部分関数従属、推移関数従属
      • (4) データベースのパフォーマンス設計 — 非正規化
    • 大分類4 開発技術 › 中分類12 システム開発技術 › 2. 設計 › (9)ソフトウェア設計手法 › ② データ中心設計 — データ中心設計の用語例:正規化、一事実一箇所
  • BCNFについて: シラバスの表現は「第1正規形,第2正規形,第3正規形など」です。BCNFを明示的には挙げていません。本ノートではBCNFを、この「など」に対する補足的な深掘りとしてのみ扱います。
  • 今回の範囲外: SQLの構文・問合せ(AP14)。スキーマと関数従属性は関係表記のみで書きます。

2. 用語対照表(KO / JA / EN)

한국어 日本語 English
후보키 候補キー candidate key
주키(기본키) 主キー primary key
외래키 外部キー foreign key
슈퍼키 スーパーキー superkey
주요 속성(키 속성) / 비주요 속성 主属性(キー属性)/非キー属性 prime / non-prime attribute
함수 종속 関数従属性 functional dependency (FD)
결정자 / 종속자 決定項 / 従属項 determinant / dependent
속성 폐포 属性閉包 attribute closure
완전 함수 종속 完全関数従属 full functional dependency
부분 함수 종속 部分関数従属 partial functional dependency
이행 함수 종속 推移関数従属 transitive functional dependency
갱신 이상 / 삽입 이상 / 삭제 이상 更新時異状 / 挿入時異状 / 削除時異状 update / insertion / deletion anomaly
정규형 正規形 normal form
무손실 분해 無損失分解 lossless(-join) decomposition
종속성 보존 従属性保存 dependency preservation
참조 무결성 参照整合性(参照制約) referential integrity
비정규화 非正規化 denormalization

3. メイン例題と前提

ENROLLMENT_RAW(StudentID, CourseID, StudentName, CourseTitle,
               InstructorID, InstructorName, Grade)

関数従属性の集合 F:

  1. StudentID -> StudentName
  2. CourseID -> CourseTitle, InstructorID
  3. InstructorID -> InstructorName
  4. (StudentID, CourseID) -> Grade

業務上の前提:1つのIDは1人の学生を識別する。1科目には1つの科目名と1人の担当教員がいる。1つの教員IDには1つの氏名がある。1人の学生は1科目につき最大1つの成績をもつ。値はすべて単純値(出発時の関係はすでに1NF)。これ以外の自明でない関数従属性は仮定しない。

サンプル行(異状の説明用):

StudentID CourseID StudentName CourseTitle InstructorID InstructorName Grade
S01 C10 Kim Database I7 Tanaka A
S02 C10 Lee Database I7 Tanaka B
S01 C20 Kim Networks I8 Sato B

4. キーと属性閉包

定義

  • スーパーキー: その値で関係のすべての属性が決まる属性集合。
  • 候補キー: 極小のスーパーキー。どの属性を1つ除いてもスーパーキーでなくなる。
  • 主キー: 組(タプル)の識別のために選んだ1つの候補キー(NULL不可、一意)。
  • 外部キー: その値が参照先の関係の候補キー/一意キーの値と一致しなければならない属性集合(通常は主キーだが、必ずしもそうとは限らない)。参照整合性を保証する。

閉包アルゴリズム

X⁺の求め方:Xから始め、Fの各 Y -> Z について、Yが現在の集合に含まれればZを加える。1周しても新たに加わるものがなければ終了。

{StudentID, CourseID}+:

手順 適用したFD 手順後の集合
開始 — {StudentID, CourseID}
1 StudentID -> StudentName + StudentName
2 CourseID -> CourseTitle, InstructorID + CourseTitle, InstructorID
3 InstructorID -> InstructorName + InstructorName
4 (StudentID, CourseID) -> Grade + Grade
次の周 追加なし 7属性すべて
  • {CourseID}+ = {CourseID, CourseTitle, InstructorID, InstructorName} のみ。
  • {StudentID}+ = {StudentID, StudentName} のみ。

(StudentID, CourseID) が唯一の候補キーである理由

  1. StudentIDとCourseIDは、Fのどの関数従属性の右辺にも現れないため、他の属性から導けない。どのキーも両方を必ず含む。
  2. {StudentID, CourseID}+ は7属性すべて → スーパーキー。
  3. どちらを除いても失敗(上の {StudentID}+、{CourseID}+ は不完全)→ 極小。
  4. 他のスーパーキーはこの組に属性を加えたものなので、極小ではない。

したがってFのもとで (StudentID, CourseID) は唯一の候補キーであり、これを主キーとして選ぶ。主属性:StudentID、CourseID。非キー属性:残りの5つ。

5. 関数従属性の分類

複合候補キー K = (StudentID, CourseID) を基準として:

種類 従属 理由
完全関数従属 K -> Grade StudentID単独でもCourseID単独でもGradeは決まらない。
部分関数従属 StudentID -> StudentName 非キー属性がKの真部分集合に従属する。
部分関数従属 CourseID -> CourseTitle, InstructorID 同様に、Kの一部が決定項。
推移関数従属 CourseID -> InstructorID -> InstructorName InstructorNameは非キー属性InstructorIDを経由してCourseIDに従属する。

正確さのためのメモ:

  • CourseID -> InstructorName は与えられたFDではなく、推移律で導出された従属である。元の関係では、InstructorNameはKの一部に部分的かつ推移的に従属する。導出された従属をすべて直接の(与えられた)FDと呼ばないこと。
  • 2NFの関係 COURSE_2NF(7節)ではCourseIDがキーなので、CourseID -> InstructorID -> InstructorName は非キー属性を経由した、キーに対する非キー属性の推移従属である。
  • 決定項 = 左辺、従属項 = 右辺。「X -> Y」は「XがYを決定する/YはXに関数従属する」と読む。

6. 更新時異状

3つとも、冗長性(同じ事実を複数行に保持)と事実の混在(学生・科目・教員・履修の事実が1つの関係に混在)から生じる。

  • 更新時異状: Tanaka(I7)が2行に保持されている。1行だけ氏名を変えるとデータが矛盾する。
  • 挿入時異状: I9が担当する新科目C30は、誰かが履修するまで登録できない。主キー (StudentID, CourseID) がそろっている必要があるため(StudentIDにNULL不可)。
  • 削除時異状: S01がC20の履修を取り消し、それがC20の最後の履修なら、行の削除とともに「C20 = Networks、担当 I8 Sato」という事実も消える。

7. 1NF → 2NF → 3NF

  • 第1正規形(1NF): すべての属性値が単純値(繰返しグループなし)。ENROLLMENT_RAWはすでに1NFだが、上の異状はそのまま残る。1NFだけでは部分・推移従属は除去されない。
  • 第2正規形(2NF): 1NFであり、すべての非キー属性がすべての候補キーに完全関数従属する(部分関数従属なし)。
  • 第3正規形(3NF): 2NFであり、どの非キー属性も候補キーに推移関数従属しない。同値な判定:自明でないすべての X -> A について、Xがスーパーキーであるか、Aが主属性である。
  • BCNF: 自明でないすべての X -> A について、Xがスーパーキー(「Aが主属性」の例外をなくしたもの)。

2NFへの分解(部分関数従属の除去)

STUDENT(StudentID PK, StudentName)
COURSE_2NF(CourseID PK, CourseTitle, InstructorID, InstructorName)
ENROLLMENT(StudentID PK/FK, CourseID PK/FK, Grade)   -- 複合PK (StudentID, CourseID)

ENROLLMENTから部分関数従属はなくなった。しかしCOURSE_2NFには推移関数従属 CourseID -> InstructorID -> InstructorName が残っている(教員氏名が科目ごとに繰り返される)。

3NF/最終分解(推移関数従属の除去)

STUDENT(StudentID PK, StudentName)
INSTRUCTOR(InstructorID PK, InstructorName)
COURSE(CourseID PK, CourseTitle, InstructorID FK -> INSTRUCTOR.InstructorID)
ENROLLMENT(StudentID FK -> STUDENT.StudentID,
           CourseID  FK -> COURSE.CourseID,
           Grade,
           PK(StudentID, CourseID))

FKの向き:「多」側が「1」側を参照する — ENROLLMENT → STUDENT、ENROLLMENT → COURSE、COURSE → INSTRUCTOR。

各表に射影したFDのもとで、すべての決定項はスーパーキーである(STUDENTのStudentID、INSTRUCTORのInstructorID、COURSEのCourseID、ENROLLMENTの (StudentID, CourseID))。したがって最終の各表は3NFかつBCNFである。

最終スキーマは各事実を1か所に保持する(一事実一箇所):Tanakaの氏名はINSTRUCTORで1回変更すればよく、C30は履修なしでCOURSEに登録でき、履修を削除しても科目データは消えない。

性能に関するメモ: 正規化で常に問合せが速くなるわけではない — 参照時に結合が増えることがある。非正規化は、整合性の要件を理解したうえで測定に基づいて意図的に選ぶ性能上のトレードオフであり、既定の選択ではない。

8. 無損失分解と従属性保存

判定基準: RをR1とR2に分解するとき、(R1 ∩ R2) -> R1 または (R1 ∩ R2) -> R2 がFから導けるなら無損失(共通属性が少なくとも一方のキー)。

段階的な2分割:

段階 分解 R1 ∩ R2 確認 結果
1 RAW → STUDENT + REST1(StudentID, CourseID, CourseTitle, InstructorID, InstructorName, Grade) StudentID StudentID -> {StudentID, StudentName} = STUDENT全体 無損失
2 REST1 → COURSE_2NF + ENROLLMENT CourseID CourseID -> {CourseID, CourseTitle, InstructorID, InstructorName} = COURSE_2NF全体 無損失
3 COURSE_2NF → COURSE + INSTRUCTOR InstructorID InstructorID -> {InstructorID, InstructorName} = INSTRUCTOR全体 無損失

各段階が無損失なので、段階的な最終分解はFのもとで無損失である。キー・外部キーの条件を満たすデータであれば、自然結合 ENROLLMENT ⋈ STUDENT ⋈ COURSE ⋈ INSTRUCTOR は元の組を正確に復元する — 失われる組も、余分な(見せかけの)組もない。

従属性保存 — Fのすべての関数従属性を、最終の1つの表の中で検査できる:

FD 検査する表
StudentID -> StudentName STUDENT
CourseID -> CourseTitle, InstructorID COURSE
InstructorID -> InstructorName INSTRUCTOR
(StudentID, CourseID) -> Grade ENROLLMENT

9. BCNFの境界(補足的な深掘り)

(シラバスの「第3正規形など」に対する補足的な深掘りであり、シラバスにBCNFという名称はない。)

TEACH(Student, Subject, Instructor)
FD(これのみ): (Student, Subject) -> Instructor
               Instructor -> Subject
  • 候補キー:(Student, Subject) と (Student, Instructor) — {Student, Instructor}+ は Instructor -> Subject でSubjectが加わる。すべての属性が主属性。
  • Instructor -> Subject:Subjectは主属性 → 3NFを満たす。Instructorはスーパーキーでない → BCNFに違反。
  • BCNF分解:INSTRUCTOR_SUBJECT(Instructor, Subject) と STUDENT_INSTRUCTOR(Student, Instructor)。共通属性InstructorがINSTRUCTOR_SUBJECT全体を決定するので無損失。
  • トレードオフ: (Student, Subject) -> Instructor はもはや1つの関係に収まらないため、保存されない。これを守るには追加の制約や検査が必要になることがある。すべてのBCNF分解がすべての従属性を保存するわけではない。一方、3NFへの分解は常に無損失かつ従属性保存となるように行える。

10. クイックシート

  • 候補キー = 極小のスーパーキー、主キー = 選んだ候補キー、外部キー → 他の関係の候補キー/一意キー(参照整合性)。
  • X⁺:新たに加わるものがなくなるまでFを繰り返し適用。X⁺ = 全属性 → Xはスーパーキー。
  • どのFDの右辺にも現れない属性 → すべてのキーに含まれる。
  • 完全:キー全体に従属。部分:複合キーの一部に従属。推移:キー → 非キー → 非キー。
  • 1NF 単純値 → 2NF 部分従属なし → 3NF 推移従属なし(Xスーパーキー または A主属性)→ BCNF(Xスーパーキー)。
  • 無損失な2分割:(R1 ∩ R2) -> R1 または -> R2。
  • 従属性保存:各FDを1つの表の中で検査できる。
  • メイン例題の最終形:STUDENT、INSTRUCTOR、COURSE(→INSTRUCTOR)、ENROLLMENT(→STUDENT、→COURSE)。

11. よくある落とし穴

  • 「1NFなら異状はない」— 誤り。ENROLLMENT_RAWは1NFだが3つの異状がすべてある。
  • 極小でないスーパーキー(例:StudentID, CourseID, Grade)を候補キーと呼ぶ。
  • 単一属性のキーでも部分従属があると考える — 部分従属は複合キーでのみ生じる。
  • InstructorID -> InstructorName を「部分従属」と呼ぶ — InstructorIDはKの一部ではない。
  • 「外部キーは必ず主キーを参照する」— 候補キー/一意キーを参照する(通常は主キー)。
  • どちらも決定しない属性(共通属性なし、重複しうる氏名など)で分解する → 見せかけの組が生じる。
  • 「BCNF分解は常に従属性を保存する」— 誤り(TEACH)。
  • 「正規化は常に性能を上げる」— 誤り。非正規化は測定に基づくトレードオフ。

12. 練習問題(5問・オリジナル)

本ノートのために作成したオリジナル問題であり、IPAの過去問題ではありません。

問1

FのもとでのENROLLMENT_RAWについて、正しい記述はどれか。

  • ア {CourseID}+ が7属性すべてを含むので、CourseID単独が候補キーである。
  • イ {StudentID, CourseID}+ は7属性すべてを含み、{StudentID}+ と {CourseID}+ は含まないので、(StudentID, CourseID) は候補キーである。
  • ウ (StudentID, CourseID, Grade) は閉包が7属性すべてを含むので、候補キーである。
  • エ InstructorIDがInstructorNameを決定するので、(StudentID, InstructorID) も候補キーである。

正解:イ

  • ア 誤り。{CourseID}+ = {CourseID, CourseTitle, InstructorID, InstructorName}。StudentID、StudentName、Gradeが含まれない。
  • イ 正しい。閉包が完全で、どちらを除いても閉包が不完全になるので、極小のスーパーキーである。
  • ウ 誤り。スーパーキーではあるが極小でない。Gradeを除ける。
  • エ 誤り。{StudentID, InstructorID}+ = {StudentID, StudentName, InstructorID, InstructorName}。CourseIDはどの右辺にもないので導けない。

問2

K = (StudentID, CourseID) を基準とした分類として、正しいものはどれか。

  • ア StudentIDはKの一部なので、K -> Grade は部分関数従属である。
  • イ StudentNameは非キー属性なので、StudentID -> StudentName は推移関数従属である。
  • ウ K -> Grade は完全、StudentID -> StudentName は部分であり、InstructorNameは非キー属性InstructorIDを経由してCourseIDに推移的に従属する。
  • エ InstructorIDはKの一部なので、InstructorID -> InstructorName はKに対する部分関数従属である。

正解:ウ

  • ア 誤り。GradeはK全体を必要とし、どちらか一方だけでは決まらないので完全関数従属である。
  • イ 誤り。決定項StudentIDはKの真部分集合で、間に非キー属性がないので、推移ではなく部分関数従属である。
  • ウ 正しい。3つの分類はすべて定義と一致する(CourseID -> InstructorID -> InstructorName が推移の連鎖)。
  • エ 誤り。InstructorIDはKの一部ではなく非キー属性である。このFDは推移の連鎖の2つ目の環である。

問3

PK/FKの向きも含めて、正しい3NFの最終分解はどれか。

  • ア STUDENT(StudentID PK, StudentName), COURSE(CourseID PK, CourseTitle, InstructorID, InstructorName), ENROLLMENT(StudentID FK, CourseID FK, Grade, PK(StudentID, CourseID))
  • イ STUDENT(StudentID PK, StudentName), INSTRUCTOR(InstructorID PK, InstructorName, CourseID FK -> COURSE), COURSE(CourseID PK, CourseTitle), ENROLLMENT(StudentID FK, CourseID FK, Grade, PK(StudentID, CourseID))
  • ウ STUDENT(StudentID PK, StudentName), INSTRUCTOR(InstructorID PK, InstructorName), COURSE(CourseID PK, CourseTitle, InstructorID FK -> INSTRUCTOR), ENROLLMENT(StudentID PK, CourseID FK -> COURSE, Grade)
  • エ STUDENT(StudentID PK, StudentName), INSTRUCTOR(InstructorID PK, InstructorName), COURSE(CourseID PK, CourseTitle, InstructorID FK -> INSTRUCTOR), ENROLLMENT(StudentID FK -> STUDENT, CourseID FK -> COURSE, Grade, PK(StudentID, CourseID))

正解:エ

  • ア 誤り。2NFまでしか進んでいない。COURSEに CourseID -> InstructorID -> InstructorName が残る。
  • イ 誤り。FKの向きが逆。InstructorID -> CourseID はFにない(1人の教員が複数科目を担当しうる)うえ、CourseID -> InstructorID を1つの表で検査できなくなる。
  • ウ 誤り。StudentID単独はENROLLMENTのキーではなく(1人の学生が複数科目を履修)、STUDENTへのFKも欠けている。
  • エ 正しい。すべてのFDが1つの表に収まり、すべての決定項がキーであり、FKが「多」側から「1」側を向いている。

問4

分解の段階が無損失であることを正しく証明しているものはどれか。

  • ア COURSE_2NFを COURSE(CourseID, CourseTitle, InstructorID) と INSTRUCTOR(InstructorID, InstructorName) に分けるのは、共通属性InstructorIDがINSTRUCTORのすべての属性を決定するので無損失である。
  • イ ENROLLMENT_RAWを STUDENT と REST1 に分けるのは、2つの関係の組数が等しいので無損失である。
  • ウ ENROLLMENT_RAWを R1(StudentID, StudentName, Grade) と R2(CourseID, CourseTitle, InstructorID, InstructorName) に分けるのは、それぞれが独自の決定項をもつので無損失である。
  • エ COURSE_2NFを (CourseID, CourseTitle, InstructorName) と (InstructorID, InstructorName) に分けるのは、共通属性がInstructorNameなので無損失である。

正解:ア

  • ア 正しい。(R1 ∩ R2) = InstructorID であり、InstructorID -> R2 がFから導ける。
  • イ 誤り。組数は判定基準ではない(STUDENTは通常、組数が少ない)。正しい根拠は StudentID -> STUDENT である。
  • ウ 誤り。共通属性がないので結合は直積となり、見せかけの組が生じる。学生と科目の対応が失われる。
  • エ 誤り。InstructorName -> InstructorID はFにない(氏名は重複しうる)ので、共通属性はどちらも決定しない。

問5

FDが (Student, Subject) -> Instructor と Instructor -> Subject のみである TEACH(Student, Subject, Instructor) について、正しいものはどれか。

  • ア Instructor -> Subject は部分関数従属なので、TEACHは2NFに違反する。
  • イ すべての属性が主属性なので、TEACHはBCNFである。
  • ウ TEACHは3NFだがBCNFではない。INSTRUCTOR_SUBJECT(Instructor, Subject) と STUDENT_INSTRUCTOR(Student, Instructor) への分解は無損失だが、(Student, Subject) -> Instructor は1つの関係の中に保存されない。
  • エ (Student, Subject) と (Student, Instructor) に分解すると、無損失かつすべての従属性が保存される。

正解:ウ

  • ア 誤り。2NF・3NFは非キー属性に関する制約である。Subjectは主属性なので、TEACHは2NFかつ3NFである。
  • イ 誤り。BCNFでは自明でないすべての決定項がスーパーキーでなければならない。Instructorはスーパーキーでない。
  • ウ 正しい。Subjectが主属性なので3NFは満たし、BCNFには違反する。Instructorにより無損失だが、元のFDには追加の制約/検査が必要になることがある。
  • エ 誤り。共通属性Studentはどちらも決定しないので、損失のある分解(見せかけの組が生じる)である。

正解一覧: イ、ウ、エ、ア、ウ(1始まりの番号:2, 3, 4, 1, 3)

13. セルフチェックと1/3/7日復習

セルフチェック:

  • メモなしでFから {StudentID, CourseID}+、{CourseID}+、{StudentID}+ を求められる。
  • この組が唯一の候補キーである理由(右辺の議論+極小性)を説明できる。
  • 完全/部分/推移関数従属を区別し、導出された CourseID -> InstructorName を説明できる。
  • サンプル行から更新・挿入・削除時異状を1つずつ挙げられる。
  • 2NF・3NFのスキーマをPK/FKの向きまで書ける。
  • 3NF・BCNFの条件と、無損失な2分割の基準を言える。
  • TEACHが3NFだがBCNFでない理由と、BCNF分解で失うものを説明できる。

復習計画:

  • 1日目: 4–5節を紙で解き直す。問1–2に再挑戦。
  • 3日目: 2NF/3NFのスキーマと無損失の3段階を記憶から書き直す。問3–4に再挑戦。
  • 7日目: TEACHのトレードオフを声に出して説明する。5問すべてを解き直し、間違えた選択肢の解説を見直す。

14. 改訂履歴

  • 2026-10-28:データ中心設計の公式階層を大分類4:開発技術/中分類12:システム開発技術/2. 設計/(9)ソフトウェア設計手法/② データ中心設計に訂正し、出典ページをデータベース設計・正規化はPDF 42–43ページ(印刷38–39ページ)、データ中心設計はPDF 67ページ(印刷63ページ)に修正し、シリーズメタデータのシラバス範囲にこの項目を追加した。本文の説明、練習問題と正解は変更していない。

ブログへ