正規化の実践
判断は自分でする
ここまで、1NF・2NF・3NF を1つずつ潰してきました。今回は、どこが違反しているかを教えずに乱れた表を渡します。自分で見つけて直してください。
渡される表はこれです。主キーは (order_id, product_id) です。
| order_id | product_id | product_name | category_id | category_name | quantity |
|---|---|---|---|---|---|
| 1 | 1 | ノートPC | 10 | パソコン | 1 |
| 1 | 2 | マウス | 20 | 周辺機器 | 2 |
| 2 | 1 | ノートPC | 10 | パソコン | 3 |
手順は毎回同じ
乱れた表を渡されたら、次の順で見ます。順番を守ることが大事で、飛ばすと見落とします。
手順1 — 1マスに複数値が入っていないか。 カンマ区切りや tag1、tag2 を探します。あれば行に分解します。
手順2 — 主キーが複合キーなら、一部だけで決まる列がないか。 主キー以外の列を1つずつ取り上げ、「これは主キー全体が要るか、一部で足りるか」と聞きます。一部で足りるなら、その一部を主キーとする表に移します。
手順3 — 主キー以外の列で決まる列がないか。 残った列同士で「AがBを決めていないか」を聞きます。決めているなら、Aを主キーとする表に移します。
上の表に当てはめる
手順1では何も見つかりません。どのマスも値は1つです。
手順2で、product_name と category_id が引っかかります。どちらも product_id だけで決まります。order_id は要りません。この2列は product_id を主キーとする表に移します。
手順3は、移したあとの表に対しても行います。products に移った category_name は category_id で決まるので、さらに categories に移すことになります。
正規化は1回で終わらない、というのがここでの学びです。移した先でまた違反が見つかるので、見つからなくなるまで繰り返します。
分けすぎではないか
3つの表に増えました。JOIN が増えて面倒に見えるかもしれません。
しかし、カテゴリ名を「周辺機器」から「アクセサリ」に変えるとき、直すのは1行です。分けていなければ、その商品が売れた明細すべてを直すことになります。面倒さは書くときに前払いし、あとで受け取ります。
手を動かす
手順1から3を順に当てて、3つの表に分けてください。
テーブル構造
CREATE TABLE sales_raw (
order_id integer NOT NULL,
product_id integer NOT NULL,
product_name text NOT NULL,
category_id integer NOT NULL,
category_name text NOT NULL,
quantity integer NOT NULL,
PRIMARY KEY (order_id, product_id)
);
INSERT INTO sales_raw VALUES
(1, 1, 'ノートPC', 10, 'パソコン', 1),
(1, 2, 'マウス', 20, '周辺機器', 2),
(2, 1, 'ノートPC', 10, 'パソコン', 3),
(2, 3, 'キーボード', 20, '周辺機器', 1),
(3, 4, 'モニタ', 30, 'ディスプレイ', 2);
期待される出力
| order_id | product_id | product_name | category_name | quantity |
|---|---|---|---|---|
| 1 | 1 | ノートPC | パソコン | 1 |
| 1 | 2 | マウス | 周辺機器 | 2 |
| 2 | 1 | ノートPC | パソコン | 3 |
| 2 | 3 | キーボード | 周辺機器 | 1 |
| 3 | 4 | モニタ | ディスプレイ | 2 |