3秒でわかる
ある列の値が決まると別の列の値も一意に決まる関係。テーブルをどこで分割すべきかを判断する、正規化の出発点になる考え方です。
もう少し詳しく
どういうものか
関数従属は、テーブルのある列(の組)の値が決まると、別の列の値がひとつに定まる関係のことです。社員テーブルで社員番号が決まれば氏名も決まる、という状態を「社員番号 → 氏名」と書き、社員番号が氏名を関数的に決定する、と言います。
矢印の左側を決定項、右側を従属項と呼びます。ここでいう「決まる」はデータの入り方の話ではなく、業務のルールとして常にそうなる、という制約です。たまたま今の行がすべて一致しているだけでは関数従属とは言えません。
なぜ必要か
正規化の判断は、この関数従属をどう見つけるかで決まります。主キー全体ではなく一部の列だけで決まってしまう列があれば第2正規形に反しており、主キー以外の列を経由して決まる列があれば第3正規形に反しています。どちらの状態も、同じ事実が複数の行に重複して書かれることを意味します。
重複が起きると、更新のときに一部の行だけ直して食い違う(更新異常)、注文を消すと商品名まで消える(削除異常)、商品だけ先に登録できない(挿入異常)といった問題が出ます。関数従属を洗い出すのは、この3つの異常を設計の段階で潰す作業です。
具体例
注文明細テーブル (正規化前)
主キー = (注文ID, 商品ID)
注文ID | 商品ID | 商品名 | 単価 | 数量 | 顧客ID | 顧客名
1001 | P01 | コーヒー | 480 | 2 | C1 | 田中
1001 | P02 | ケーキ | 520 | 1 | C1 | 田中
1002 | P01 | コーヒー | 480 | 3 | C2 | 佐藤
見つかる関数従属
(注文ID, 商品ID) -> 数量 主キー全体で決まる。問題なし
商品ID -> 商品名, 単価 主キーの一部だけで決まる。部分関数従属
注文ID -> 顧客ID 主キーの一部だけで決まる
顧客ID -> 顧客名 主キー以外を経由して決まる。推移的関数従属分解すると、注文明細(注文ID, 商品ID, 数量)、商品(商品ID, 商品名, 単価)、注文(注文ID, 顧客ID)、顧客(顧客ID, 顧客名)の4つになります。
-- 商品名の変更が1行の更新で済む
UPDATE products SET name = 'ブレンドコーヒー' WHERE product_id = 'P01';つまずきやすいところ
今あるデータを眺めて関数従属を決めてしまうのが典型的な失敗です。今は同姓同名がいないというだけで「顧客名 → 顧客ID」が成り立つように見えますが、業務ルールとしては成り立ちません。関数従属は現在の行の並びではなく、業務上の決まりから導きます。
似た用語との違い
| 語 | 意味 |
|---|---|
| 完全関数従属 | 主キー全体が揃ってはじめて決まる |
| 部分関数従属 | 主キーの一部だけで決まってしまう。第2正規形で解消 |
| 推移的関数従属 | 主キー以外の列を経由して決まる。第3正規形で解消 |