多重度は両端に書く — 片側だけでは情報不足
多重度は線の両端に書かないと必須/任意が決まらず、NOT NULL 設計が宙に浮く。
片側だけの多重度は「半分しか決まっていない」
「顧客 ── 注文」を「1 : N」とだけ書いた ER 図をよく見かけますが、これだけでは 4 つある組み合わせのうち 2 つまでしか絞れていません。
- 顧客側: 1 .. 1 と 0 .. 1 のどちら?(注文は必ず顧客を持つ?/匿名注文も許すのか?)
- 注文側: 1 .. N と 0 .. N のどちら?(顧客は最低 1 件注文済み?/まだ 0 件の顧客も居る?)
両端を書き切って初めて「必須か任意か」が決まります。そしてこの必須/任意は、そのまま NOT NULL 制約や ON DELETE の挙動に翻訳されます。
実例 — ゲストチェックアウトで多重度が変わる
同じ「顧客 ── 注文」の線でも、業務要件が少し変わるだけで多重度(特に親側の必須/任意)が丸ごと入れ替わります。
- 会員制 EC(Amazon Prime のような登録必須モデル): 注文には必ず顧客がいる → 親側 1 .. 1/FK は
NOT NULL - ゲストチェックアウト可能な EC(メルカリの匿名購入など): 顧客レコード無しの注文が存在しうる → 親側 0 .. 1/FK は
NULLABLE、ゲスト用の email/name を注文側に直接持たせる必要あり
片側だけ「1 : N」と書いたレビュー資料では、この 2 つの世界を区別できません。結果として「ゲスト注文を実装しようとしたら FK が NOT NULL で INSERT できない」「退会機能を作ろうとしたら顧客消去で全注文が消える設計だった」という実装段階の手戻りが起きます。
※ 同じ構造の例: 「従業員 ── 部署」(人事異動の宙づり期間を許すか)、「著者 ── 記事」(退職者の記事をどうするか)、「ユーザー ── アカウント設定」(未設定でも登録 OK か)。どれも親側の必須/任意が業務要件次第で揺れます。
両端の組み合わせと DB 制約への翻訳
両端の「必須/任意」は、FK 列の NOT NULL の有無と、逆側の「0 件を許すか」に直結します。
| 親側 | 子側 | 意味 | DB 制約 |
|---|---|---|---|
| 1 .. 1 | 1 .. N | 注文は必ず顧客を持ち、顧客は最低 1 件注文している | 子 FK は NOT NULL / 親にチェック制約や業務ロジックで「最低 1 件」を保証 |
| 1 .. 1 | 0 .. N | 注文は必ず顧客を持つが、顧客は 0 件でも可(既定) | 子 FK は NOT NULL のみ。親側の縛りなし |
| 0 .. 1 | 0 .. N | 注文は顧客が居ないケース(匿名)も許容 | 子 FK は NULLABLE。匿名注文の扱いをアプリ側で決める必要 |
| 0 .. 1 | 1 .. N | 顧客無しの注文も許しつつ、顧客側は最低 1 件持つ | 実務ではまず登場しない組み合わせ。設計ミスを疑う |
「顧客側は絶対 1 :注文側は 0 以上」のパターンが最多ですが、ゲストチェックアウトを許す EC では顧客側が 0..1 になる等、要件次第で変わります。
レビューで聞くべき 3 つの質問
ER 図のレビューで多重度の漏れを洗い出すには、機械的に 3 つ聞きます。
- 子なしの親は存在するか? — 「まだ 1 件も注文していない顧客」を許すなら子側は
0..N。許さないなら1..Nで業務ルールに落とし込む必要あり - 親なしの子は存在するか? — 許すなら FK は
NULLABLE。許さないならNOT NULL。ここで曖昧だと後日「匿名注文が保存できない」といった障害になる - 親が消えたら子はどうなる? —
ON DELETE CASCADE / RESTRICT / SET NULLのどれか。これも多重度の必須/任意と整合していないと動かない(SET NULLなのに FK がNOT NULL、など)
この 3 つを聞くだけで、線 1 本につき「両端の必須/任意」「FK の NULL 可否」「削除時挙動」まで決まり、DDL に落とせる情報が揃います。
