「山田太郎」の行が 4 つある (一意性)
一意性制約 (unique constraint) とは、指定した列 (または列の組) の値がテーブル内で重複しないことを DBMS が構造的に保証する制約であり、主キーは NOT NULL と一意性を組み合わせた特殊な一意性制約として位置付けられる。
事故 — 「山田太郎」の行が 4 つある。同一人物?別 4 名?
1 年ぶりに戻ってきた山田太郎さんは、自分の EC アカウントを覚えていなかった。ログイン画面で試行錯誤の末に「新規登録」を選んだが、 以前使っていた email も思い出せない。とりあえず適当な文字列 (n/a、unknown、-) を入れて 3 回登録試行し、 いずれも登録は通ってしまった。翌週、顧客管理シートを見ると「山田太郎」が 4 行ある。
| A | B | C | D | |
|---|---|---|---|---|
| 1 | 顧客ID | 顧客名 | メール | 登録日 |
| 2 | C-001 | 山田太郎 | yamada@example.com | 2024-01-15 |
| 3 | C-011 | 山田太郎 | n/a | 2025-11-01 |
| 4 | C-012 | 山田太郎 | unknown | 2025-11-01 |
| 5 | C-013 | 山田太郎 | - | 2025-11-01 |
| 6 | C-002 | 佐藤花子 | sato@example.com | 2024-02-10 |
ここで先に確認しておきたい: 山田太郎という名前が 4 行あっても、それ自体は問題ない。 現実に同姓同名の別人は存在する。顧客ID (C-001 / C-011 / C-012 / C-013) は自動採番で unique なので、DB 的な UNIQUE(顧客ID) 制約は既に満たされている。
では何が問題なのか。「山田太郎さんとして戻ってきたお客さんが、C-001 の再訪か、それとも別の新規 3 名か」を DB から判定できないことが問題。 マーケメールは 4 通全員に届き苦情が出た。「今月の新規顧客数」統計は3 名 増と報告されたが、実際は 0 (1 名の登録試行) だった可能性が高い。 カスタマーサポートに「私の注文履歴が見つからない」と問い合わせが殺到した。
原因 — 「識別に使うべき列」に UNIQUE 制約がない
Excel の顧客シートには、どの列に対しても 「絶対に重複させない」という宣言的な制約が無い。 顧客ID はプログラム側の自動採番で 結果的に unique になっているだけで、DB 側では何も保証していない。
本当に unique であるべきなのは、顧客を業務的に識別する属性 — つまり email や電話番号のような 「同じ人なら同じ値になる」自然キー。ここに UNIQUE 制約が掛かっていれば、山田太郎さんが 2 回目の登録を試みた時点でyamada@example.com の重複挿入としてシステムが弾ける。
surrogate key (顧客ID) の UNIQUE は「常に満たされる自明な条件」で、業務上ほとんど意味を持たない。 意味のある UNIQUE は 自然キー (email / phone / 会員番号) に掛ける必要がある。Excel にはこの区別が無いので、 surrogate key を unique にすればそれで満足してしまう構造になっている。
解決策 — 識別属性に UNIQUE + NOT NULL を宣言する
RDB では、テーブル定義時に 「この列は絶対に重複しない」「NULL 禁止」を宣言できる。 重複挿入は DBMS が拒否する。人間の運用に依存しない。
CREATE TABLE customers (
id BIGSERIAL PRIMARY KEY, -- surrogate key: 自動採番で常に unique
email VARCHAR(255) NOT NULL, -- 業務的な識別属性
name VARCHAR(50) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- 意味のある UNIQUE は「識別に使うべき列」に掛ける
CONSTRAINT customers_email_key UNIQUE (email)
);
-- 山田太郎さんが 2 回目の登録を試みる → DBMS が拒否
INSERT INTO customers (email, name)
VALUES ('yamada@example.com', '山田太郎');
-- ERROR: duplicate key value violates unique constraint "customers_email_key"本記事の主題である 「一意性 = UNIQUE 制約」 はこれだけ。 「識別に使うべき列を選び、そこに UNIQUE を掛ける」がすべて。
補足: junk 値による回避と CHECK 制約
実は UNIQUE(email) だけでは、悪意なしのユーザーが n/a、unknown、- のような 異なる junk 文字列を毎回入れて再登録するのを防げない (それぞれが別の unique 値として通ってしまう)。 これを塞ぐには、email の 形式そのもの を検証する CHECK 制約 を併用する必要がある (CHECK / NOT NULL 制約は本シリーズ scope 外)。
UNIQUE と CHECK は別の制約であり、扱う概念も別 (前者は「値の重複禁止」、後者は「値の形式検証」)。 本記事はあくまで UNIQUE (一意性) に集中する。
「自然キー」vs「代理キー (サロゲートキー)」
主キーの候補は 2 種類:
- 自然キー (natural key): 業務データそのもの (email、社員番号、ISBN)。 人間にとって意味があり、業務的な同一性を表現できる。だが値が変わる (email 変更、番号採番ルール変更) と参照が壊れる
- 代理キー (surrogate key): 業務と無関係な連番や UUID (
id列)。 値が絶対に変わらないので参照が安定する。ただし「同じ人か違う人か」の情報は持たない
多くの実務では surrogate key を主キーに、自然キー (email 等) に UNIQUE 制約 の組み合わせを取る。 これで「参照の安定性」と「業務的な重複防止」を両立できる。
境界事例と実務判断
- 同姓同名の別人: 名前を UNIQUE にしてはいけない (弾き過ぎる)。email や phone を UNIQUE にして、名前は普通の列にする
- 家族で 1 email を共有: email UNIQUE だと 2 人目が登録できない。 複合 UNIQUE
(email, name)や、phone を含む複合キーで対応する - NULL の扱いは DBMS で差がある: PostgreSQL / MySQL / Oracle は複数の NULL を許容、 SQL Server は 1 つの NULL のみ許容。UNIQUE 列は NOT NULL にする方が移植性が高い
- 複合ユニーク:
UNIQUE (order_id, product_id)で 「同じ注文の同じ商品は 1 行のみ」を保証。単一列 UNIQUE では表せない業務ルールを表現できる
関連トピック
主キー / UNIQUE の物理的な実装は UNIQUE インデックス を参照。キー設計そのものは キーの階層 で扱っている。
よくある疑問
もっと学びたい方へ(おすすめ書籍)
テーブル設計と正規化、パフォーマンス考慮のインデックス設計まで実務レベルで学べる定番書。第2版ではクラウド対応も強化。
実務でやりがちなSQL・DB設計のアンチパターンとその回避策を体系的に学べる。
IPAデータベーススペシャリスト試験の総合対策書。インデックス関連は本サイトと合わせて学ぶと理解が深まる。
ER 図をどう「使える設計」に落とすか、実務の判断まで踏み込んだ入門書。エンティティの切り出しから多対多の扱いまで具体例が豊富。
SQLの本質的な使い方と、インデックスが効くクエリの書き方を学べる。ウィンドウ関数など現代SQLも網羅。
PostgreSQLの内部構造・ストレージ・インデックス機構を丁寧に解説。設計と運用計画の鉄則が学べる。
リレーショナルモデルの理論から、インデックス設計を含む実務で使えるSQLまで解説。
本セクションはAmazonアソシエイトのリンクを含みます。
もっと深くDBを学びたい方へ。
たいてっくが、SQL・データベース設計・パフォーマンスチューニング・ IPAデータベーススペシャリスト対策まで、1対1で学習をサポートします。まずは無料相談から。
「教え方も上手で、お人柄も良いメンターです。DB周りの知識はもちろん、何より、しっかり教えてあげようという姿勢がとてもありがたかったです。データベース、SQLの学習を考えている方にはおススメです。」
— H 様(DB・SQL コース受講)「体系的に知識を教えてくださり、実際の業務でも大変役立っております。特に短い時間で効率よく知識の習得や、練習をできているのは期待以上でした。」
— M 様(DB・SQL コース受講)「大変充実したコンテンツでわかりやすいご説明をありがとうございました。基本的な質問にも丁寧にご説明いただき、また業務のご相談にも乗って頂き大変有意義な時間でした。」
— K 様(DB・SQL コース受講)