MySQL の UNIQUE 制約
UNIQUE 制約は、特定のカラムまたはカラムの組み合わせで重複する値を許さないための制約です。主キー以外にも「一意であるべきデータ」はたくさんあり、UNIQUE 制約でそれを保証します。
基本的な使い方
UNIQUE 制約を付けたカラムには、同じ値を複数行に挿入できなくなります。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(254) NOT NULL UNIQUE,
username VARCHAR(50) NOT NULL UNIQUE
);
-- 同じ email を入れるとエラー
INSERT INTO users (email, username) VALUES ('alice@example.com', 'alice');
INSERT INTO users (email, username) VALUES ('alice@example.com', 'bob');
-- ERROR: Duplicate entry 'alice@example.com' for key 'email'UNIQUE 制約を定義すると、MySQL は自動的にユニークインデックスを作成します。そのため、UNIQUE カラムへの検索は高速に処理されます。
PRIMARY KEY との違い
PRIMARY KEY も一意性を保証しますが、UNIQUE 制約とはいくつかの点で異なります。
テーブルに1つだけ。NULL を許容しない。InnoDB ではクラスタインデックスとして物理的な格納順を決定する。
テーブルに複数設定可能。NULL を許容できる(ただし NULL 同士は重複とみなされない)。セカンダリインデックスとして作成される。
ポイントは、UNIQUE 制約のカラムが NULL を許容する場合、複数の行に NULL が入っても制約違反にならないという点です。これは SQL 標準の仕様で、NULL は「値が不明」という意味のため、比較自体が成立しません。
複合ユニーク制約
複数カラムの組み合わせで一意性を保証したい場合は、複合ユニーク制約を使います。
CREATE TABLE enrollments (
id INT AUTO_INCREMENT PRIMARY KEY,
student_id INT NOT NULL,
course_id INT NOT NULL,
enrolled_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_student_course (student_id, course_id)
);この例では student_id と course_id の組み合わせが一意になるため、同じ学生が同じコースに2回登録することを防げます。個々のカラム単体では重複が許容される点に注意してください。
UNIQUE 制約を使うべき典型的なケース
ログインに使うメールアドレスは重複してはなりません。NOT NULL UNIQUE の組み合わせが基本です。
ブログ記事のスラッグ(/posts/my-first-post の my-first-post 部分)は URL の一意性を保つために UNIQUE にします。
Stripe の customer_id や OAuth の provider + provider_id の組み合わせなど、外部サービスとの連携キーにも UNIQUE 制約が必要です。
インデックスとの関係
UNIQUE 制約を付けたカラムには自動的にインデックスが作成されるため、別途 INDEX を作る必要はありません。逆に、CREATE INDEX で UNIQUE インデックスを作成しても、制約としての効果は同じです。
-- この2つは実質的に同じ
ALTER TABLE users ADD UNIQUE (email);
CREATE UNIQUE INDEX idx_email ON users (email);UNIQUE 制約はデータ品質を守る最後の砦です。アプリケーション側でのバリデーションだけに頼ると、並行リクエストで重複データが入り込む可能性があります。「重複してはいけないデータ」には、必ずデータベースレベルで UNIQUE 制約を設定しましょう。



