制約 (NOT NULL / UNIQUE / DEFAULT)

制約 とは

NOT NULL、UNIQUE、DEFAULT制約をSQLで設定する方法を実践的に学びます。本レッスンでは、制約 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

なぜ重要か

テーブルの列に「型」を付けるだけでは、データの正しさは守れません。「メールアドレスが空のユーザ」「同じメールアドレスで複数登録された行」「フラグ列が NULL のままで判定不能」など、型は合っているのに業務上はあり得ないデータが入る余地が残るからです。これを DB 側で防ぐ仕組みが制約 (constraint) です。「アプリ側で気を付ける」だけでは必ず漏れます。一方で、DB に NOT NULLUNIQUE を入れておけば、どんな経路でデータを投入してもそもそも壊れたデータが入らない状態を作れます。これは設計の腕の見せどころで、「テーブルを見るだけで、何がアリで何がナシかわかる」状態を作るための語彙が 制約 です。

よく使う制約

diagram (will load when visible)

このレッスンでは NOT NULLUNIQUEDEFAULT に絞って解説します。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 つができることを確認しましょう。

  1. 制約 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. 制約 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

テーブル構造

schema.sql

SELECT 1;

期待される出力

idemailnameis_active
1a@example.com田中1
2b@example.com佐藤0
3c@example.com山田1

ヒント

query.sql
query.sql
学習モード
コードの実行結果
データベースを初期化中...