制約 (NOT NULL / UNIQUE / DEFAULT)
制約 とは
NOT NULL、UNIQUE、DEFAULT制約をSQLで設定する方法を実践的に学びます。本レッスンでは、制約 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
なぜ重要か
テーブルの列に「型」を付けるだけでは、データの正しさは守れません。「メールアドレスが空のユーザ」「同じメールアドレスで複数登録された行」「フラグ列が NULL のままで判定不能」など、型は合っているのに業務上はあり得ないデータが入る余地が残るからです。これを DB 側で防ぐ仕組みが制約 (constraint) です。「アプリ側で気を付ける」だけでは必ず漏れます。一方で、DB に NOT NULL や UNIQUE を入れておけば、どんな経路でデータを投入してもそもそも壊れたデータが入らない状態を作れます。これは設計の腕の見せどころで、「テーブルを見るだけで、何がアリで何がナシかわかる」状態を作るための語彙が 制約 です。
よく使う制約
このレッスンでは NOT NULL、UNIQUE、DEFAULT に絞って解説します。PRIMARY KEY は既出、FOREIGN KEY は次の章で扱います。
基本構文
SQL クエリ
CREATE TABLE users (
id INT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
age INT,
is_active INT NOT NULL DEFAULT 1,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);NOT NULL— その列に NULL を許さない。INSERT 時に値を必ず指定する (DEFAULT 併用時を除く)UNIQUE— その列で同じ値の行を許さないDEFAULT— 省略時の値を決める
複数列を組み合わせた UNIQUE 制約も書けます。
SQL クエリ
-- (user_id, product_id) の組み合わせで一意 (=お気に入りが重複しない)
CREATE TABLE favorites (
user_id INT NOT NULL,
product_id INT NOT NULL,
UNIQUE KEY uq_favorites_user_product (user_id, product_id)
);制約違反は INSERT/UPDATE を失敗させる
SQL クエリ
-- UNIQUE 違反
INSERT INTO users (id, email, name)
VALUES (1, 'a@example.com', 'A');
INSERT INTO users (id, email, name)
VALUES (2, 'a@example.com', 'B');
-- ↑ 2 つ目は失敗。最初の INSERT は成功している。DB 側で「壊れたデータが最初から入らない」状態を作るのが制約の目的です。アプリで try/catch してリトライするのではなく、そもそも入らないようにするのが設計の出発点です。
本番のテーブル定義を見たら「どこに NOT NULL があるか」「どこが UNIQUE か」を最初に確認するクセを付けると、そのテーブルの業務ルールが一瞬で読めます。コードのドキュメントよりも、DB スキーマの方が信用できます。
DEFAULT には
NOW()やCURRENT_TIMESTAMPのような関数も指定できます。created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMPを入れておくと、アプリ側で時刻を入れ忘れても DB が自動で埋めてくれるので、ログ用のテーブルでは便利です。
注意 後から
NOT NULLを付ける場合、既存行に NULL があると ALTER TABLE が失敗します。先に UPDATE で値を埋め、それから NOT NULL 化する 3 段階デプロイ (前レッスン参照) が必要です。
CHECK 制約 (発展)
MySQL 8 / TiDB の新しいバージョンには CHECK 制約も入りました。「列の値が条件式を満たすかどうか」を DB 側で検査できます。
SQL クエリ
CREATE TABLE products (
id INT PRIMARY KEY,
price INT NOT NULL,
CHECK (price >= 0)
);アプリのバグで負の価格を入れようとしても、DB が「価格はマイナスにできない」と弾いてくれます。CHECK は次の章 (外部キー) と合わせて知っておくと、テーブルが守るルールをより細かく書けます。
まとめ
- NOT NULL、UNIQUE、DEFAULT は最も基本的で、最も効く制約
- 「アプリで気を付ける」より「DB で入れない」方が確実
- 複数列 UNIQUE は組み合わせ重複の防止に使う
- DEFAULT は関数 (CURRENT_TIMESTAMP) も使える
- CHECK は値の範囲チェックに使える
- 後付け制約は既存データとの整合性を取ってから入れる
次のレッスン
次は TRUNCATE と DROP です。TRUNCATE文とDROP文の違いと、それぞれの使い方をSQLで学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 制約 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 制約 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
テーブル構造
schema.sql
SELECT 1;期待される出力
| id | name | is_active | |
|---|---|---|---|
| 1 | a@example.com | 田中 | 1 |
| 2 | b@example.com | 佐藤 | 0 |
| 3 | c@example.com | 山田 | 1 |