もしアマテラスの「任務(ミッション)」を1枚の表にまとめるとして、そこに担当する乗組員の名前・役職・年齢・出身地・給与まで、全部いっしょに書き込んだとしたら——何が起きるでしょう?
同じ乗組員が2つ、3つと任務を担当したら、その人の情報が表の中で何度も繰り返されることになりますよね。少し想像してから読み進めてください。
1枚の巨大表に、任務と乗組員を全部詰め込むと
ためしに、任務(ミッション)の表に、担当する乗組員の情報を全部いっしょに書き込んでみましょう。
| title | crew_name | crew_role | crew_home | crew_salary |
|---|---|---|---|---|
| 火星資源調査 | ケンジ | パイロット | 火星 | 400000 |
| タイタン氷床探査 | ソラ | エンジニア | 月 | 470000 |
| エウロパ生命探査 | レイ | 研究員 | 火星 | 380000 |
| 火星気象観測 | ケンジ | パイロット | 火星 | 400000 |
4行目に注目してください。ケンジがまた別の任務を担当したので、「ケンジ・パイロット・火星・400000」という同じ情報が、もう一度そっくりそのまま書かれています。任務が増えるたびに、こうした重複がどんどん積み重なっていきます。
重複が引き起こす「更新漏れ」
この状態で、ケンジの給与が400000円から420000円に上がったとしましょう。表の中にケンジの行が2つあるので、両方とも書き換えなければなりません。
もしうっかり1行だけ直して、もう1行を直し忘れたら——同じ「ケンジ」なのに、行によって給与が違うという、おかしなデータになってしまいます。これが更新漏れです。任務が10件、100件と増えていけば、直し忘れが起きる可能性はどんどん高くなります。同じ情報をあちこちに重複して持つこと自体が、事故の種なのです。
テーブルを分ける発想
この問題を解決する考え方はシンプルです。乗組員の情報は乗組員の表に1回だけ書き、任務の表には「誰が担当か」を示す番号だけを持たせます。
crew テーブル(乗組員):
| id | name | role | age | home | salary |
|---|---|---|---|---|---|
| 1 | ユミ | エンジニア | 24 | 地球 | 320000 |
| 2 | ケンジ | パイロット | 35 | 火星 | 400000 |
| 3 | サクラ | 医師 | 41 | 地球 | 520000 |
| 4 | ハルト | 医師 | 33 | 月 | 450000 |
missions テーブル(任務):
| id | title | crew_id | planet_id | reward | status |
|---|---|---|---|---|---|
| 1 | 火星資源調査 | 2 | 1 | 50000 | 完了 |
| 5 | 金星大気観測 | 1 | 2 | 40000 | 待機 |
| 8 | ケレス医療支援 | 4 | 5 | 65000 | 進行中 |
missionsテーブルの crew_id は、crewテーブルの id を指す数字です。crew_id = 2 は「crewテーブルのid=2、つまりケンジ」を意味します。これで、ケンジの給与が変わってもcrewテーブルの1行だけを直せば済みます。missions側には給与そのものが存在しないので、直し忘れも起こりようがありません。
外部キー ― 他の表の行を指し示す番号
この crew_id のように、別のテーブルの主キー(id)を指し示す列のことを、外部キー(Foreign Key)と呼びます。missionsテーブルにとって、crew_id はcrewテーブルへの、planet_id はplanetsテーブルへの外部キーです。
外部キーは、いわば「この情報の続きはあちらの表にありますよ」という案内板。表と表が、この案内板でつながっているおかげで、重複を持たずに済んでいるのです。
正規化のさわり
「重複を持たず、関連する情報は外部キーで参照する」——この考え方に沿って表を設計していく作業を、専門的には正規化と呼びます。細かいルールはこの先の学習で少しずつ触れていけば十分で、今は「同じ情報は1箇所に。あとは番号でつなぐ」という感覚さえつかめれば合格です。
1枚の巨大な表に全部の情報を詰め込む代わりに、crewテーブルとmissionsテーブルに分けることの、いちばんのメリットは何でしょう?
答えを見る
同じ情報(乗組員の名前や給与など)を1箇所にしか持たなくて済むことです。情報が1箇所にしかなければ、更新するときに直し忘れが起きません。
missionsテーブル側は crew_id という外部キーでcrewテーブルの行を指し示すだけなので、任務が何件増えても乗組員の情報が重複することはありません。
表を分けるのは、面倒なことをするためじゃなくて、むしろラクをするための工夫なんだよね。「同じ情報は1回だけ書いて、あとは番号でつなぐ」——このイメージさえ持てればOK! 次回はいよいよ、番号でつながった表同士を、実際にSQLでくっつける「JOIN」を学ぶよ。
SQL DIVERのゲーム画面でも、まさにこのcrewテーブルとmissionsテーブルが分かれた形で登場します。次回学ぶJOINを使って、この2つの表をつなげるところから、SQL DIVERでの実践がぐっと面白くなっていきます。