【ITニュース解説】Database Normalization: From 1NF to 3NF
2025年10月05日に「Dev.to」が公開したITニュース「Database Normalization: From 1NF to 3NF」について初心者にもわかりやすく解説しています。
ITニュース概要
データベースの正規化は、データの重複をなくし不整合を防ぐ技術だ。記事では、非正規化されたテーブルを1NF、2NF、3NFと段階的に整理。データの追加・更新・削除時に起こる問題をSQL例で解説し、効率的で整合性の高いデータベース構築法を示す。
ITニュース解説
データベースを効率的かつ正確に管理するために、データの整理方法である「正規化」は非常に重要な概念である。正規化とは、データベースのテーブルを分割したり再構成したりすることで、データの重複(冗長性)をなくし、データの整合性を高めるプロセスを指す。この正規化にはいくつかの段階があり、通常は第一正規形(1NF)から始まり、第二正規形(2NF)、第三正規形(3NF)へと進んでいく。
なぜ正規化が必要なのかというと、データを整理せずに一つの大きなテーブルにまとめてしまうと、様々な問題が発生するからである。これらの問題は「データ異常(アノマリー)」と呼ばれ、主に三つの種類がある。
一つ目は「挿入異常」である。これは、新しいデータを追加したいのに、関連する別のデータがなければ追加できないという問題だ。例えば、新しい学生を登録したい場合、その学生がまだどのコースも受講していないと、学生自身の情報だけではテーブルに登録できない、といった状況がこれにあたる。
二つ目は「更新異常」である。これは、あるデータを更新する際に、同じ情報が複数の場所に存在するため、それらすべてを漏れなく更新しなければならないという問題だ。例えば、ある先生の電話番号が変わったとき、その先生が担当するすべてのコースの行に、同じ電話番号が何回も記述されていたら、一つ残らず更新する必要がある。もし一つでも更新を忘れてしまうと、データに矛盾が生じてしまう。
三つ目は「削除異常」である。これは、あるデータを削除すると、それに関連する他の重要なデータまで意図せず削除されてしまうという問題だ。例えば、ある学生が受講していたすべてのコースを辞めてしまったとき、そのコースの情報と一緒に、その学生自身の名前やIDといった情報までテーブルから消えてしまう、といった状況である。
これらの異常を避けるために、正規化というデータ整理の手順を踏むことになる。
正規化の最初のステップは「第一正規形(1NF)」である。これは、データベースのテーブルの各セルには単一の値のみが含まれ、同じ種類のデータが繰り返し存在する「繰り返しグループ」がない状態を指す。具体的には、一つのセルに複数の値をカンマ区切りで入力したり、同じ情報を表現する複数の列(例えば「コース1」「コース2」)を設けたりしないことを意味する。記事で提示される最初の学生、コース、インストラクターのデータを含む単一のテーブルは、この第一正規形を満たした状態からスタートしている。
次に「第二正規形(2NF)」への移行がある。これは、第一正規形を満たしていることに加えて、「部分関数従属」を排除することが求められる。部分関数従属とは、テーブルの主キー(レコードを一意に特定するための列または列の組み合わせ)が複数の列から構成されている場合に、主キーの一部にだけ依存している属性(列)が存在する状態を指す。
例えば、学生IDとコースIDを組み合わせたものが主キーである場合、学生の名前は学生IDにのみ依存し、コース名やインストラクター名はコースIDにのみ依存する。このような状況で、学生の名前がコースIDにも依存したり、インストラクター名が学生IDにも依存したりするのは不自然である。
記事の例では、初期のテーブルで学生IDとコースIDが複合主キーであるとすると、インストラクター名やその電話番号はコースIDにのみ依存する。つまり、これらは主キーの「コースID」部分にだけ依存しており、「学生ID」には依存していない。この部分従属を解消するためには、関連する属性を別のテーブルに分離する必要がある。
記事では、このステップで学生の情報、インストラクターの情報、コースの情報、そして学生とコースの関連情報をそれぞれ別のテーブルに分割している。具体的には、Studentsテーブルに学生IDと学生名、CoursesテーブルにコースID、コース名、担当インストラクター、そしてInstructorsテーブルにインストラクター名と電話番号が格納され、さらにStudentCoursesテーブルで学生IDとコースIDを組み合わせて、どの学生がどのコースを受講しているかという関係を管理するようになる。
最後のステップは「第三正規形(3NF)」である。これは、第二正規形を満たしていることに加えて、「推移的関数従属」を排除することが求められる。推移的関数従属とは、主キー以外の属性が、主キー以外の別の属性に依存している状態を指す。
例えば、「コース名」が分かれば「担当インストラクター名」が分かり、さらに「担当インストラクター名」が分かれば「インストラクターの電話番号」が分かる、という状況があるとする。この場合、「インストラクターの電話番号」は「インストラクター名」に依存しており、そして「インストラクター名」は「コース名」に依存しているため、「インストラクターの電話番号」は「コース名」に推移的に依存していると言える。
記事の例では、InstructorPhone(インストラクター電話番号)はInstructor(インストラクター名)に依存しており、直接CourseID(コースID)に依存しているわけではない、と説明されている。第二正規形への移行の際に、すでにInstructorsテーブルとしてインストラクター名と電話番号を分離したため、この推移的従属は解消されている。つまり、インストラクターに関する情報はInstructorsテーブルにまとめられ、Coursesテーブルからはインストラクター名のみが参照される形になっている。
結果として、第三正規形まで正規化されたテーブルは、以下の四つのテーブルで構成される。
Studentsテーブル(学生ID、学生名)Instructorsテーブル(インストラクター名、インストラクター電話番号)Coursesテーブル(コースID、コース名、担当インストラクター名)StudentCoursesテーブル(学生ID、コースID)
このようにテーブルが分割されると、データはそれぞれの関連性に基づいて適切な場所に格納されるため、先述した挿入異常、更新異常、削除異常といった問題は解消される。例えば、インストラクターの電話番号が変わっても、Instructorsテーブルの該当する行を一度だけ更新すればよい。また、学生が全てのコースを辞めても、StudentCoursesテーブルから関連する行が削除されるだけで、Studentsテーブルの学生自身の情報が失われることはない。
正規化によってデータは複数のテーブルに分割されるが、必要な情報を取得する際は、それぞれのテーブルを関連付ける「JOIN」というデータベース操作を用いることで、元の情報全体を結合して参照できる。例えば、特定の学生がどのコースを受講しており、そのコースの担当インストラクターの電話番号は何であるか、といった複雑な情報も、JOINクエリを使えば簡単に取得可能である。
この正規化された構造は、データの冗長性をなくし、更新を容易にし、データの整合性を高めるだけでなく、実際のデータベースシステムではクエリの実行速度向上にもつながる場合がある。このように、正規化はデータベース設計の基本であり、信頼性の高いシステムを構築するために不可欠なプロセスである。