制約(NOT NULL / UNIQUE / DEFAULT)
| 対応: | SQL-92(1992) |
|---|
列に設定するルールのことを制約といいます。不正なデータの登録を防ぎ、データの整合性を保ちます。
構文
NULL値を禁止します。
列名 データ型 NOT NULL
列の値の重複を禁止します。
列名 データ型 UNIQUE
値が省略された場合のデフォルト値を設定します。
列名 データ型 DEFAULT デフォルト値
登録できる値の条件を指定します(MySQL 8.0.16以降)。
列名 データ型 CHECK (条件式)
制約に名前を付ける場合(テーブルレベル)。
CONSTRAINT 制約名 CHECK (条件式)
制約一覧
| 制約 | 概要 |
|---|---|
| NOT NULL | NULL値の登録を禁止します。必須入力の列に設定します。 |
| UNIQUE | 列内での値の重複を禁止します。メールアドレスや社員番号など一意性が必要な列に設定します。 |
| DEFAULT 値 | INSERT時に値を省略した場合に自動的に設定される値を指定します。 |
| CHECK (条件式) | 登録できる値を条件式で制限します(MySQL 8.0.16以降・PostgreSQL)。 |
| CONSTRAINT 名前 | 制約に名前を付けます。エラーメッセージに名前が表示され、原因の特定が容易になります。 |
サンプルコード
以下のような『employees』テーブルを作成する例で説明します。
各制約を設定してテーブルを作成します。
※ 『chk_age』の CHECK 制約は、age が NULL の場合はチェックをスキップし、値がある場合のみ 18〜100 の範囲を検証します。
sample_constraints.sql
CREATE TABLE employees (
employee_id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
department VARCHAR(50) NOT NULL DEFAULT '未配属',
salary INT NOT NULL DEFAULT 0,
age INT,
PRIMARY KEY (employee_id),
CONSTRAINT chk_salary CHECK (salary >= 0),
CONSTRAINT chk_age CHECK (age IS NULL OR age BETWEEN 18 AND 100)
);
Query OK, 0 rows affected
テーブル構造を確認します。各列に設定した制約やデフォルト値が反映されています。
sample_constraints.sql
DESCRIBE employees;
+-------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+----------------+ | employee_id | int | NO | PRI | NULL | auto_increment | | name | varchar(100) | NO | | NULL | | | email | varchar(255) | NO | UNI | NULL | | | department | varchar(50) | NO | | 未配属 | | | salary | int | NO | | 0 | | | age | int | YES | | NULL | | +-------------+--------------+------+-----+---------+----------------+ 6 rows in set
UNIQUE 制約を複数列に設定します(複合ユニーク)。
sample_constraints.sql
CREATE TABLE schedule (
room_id INT NOT NULL,
date DATE NOT NULL,
slot INT NOT NULL,
UNIQUE (room_id, date, slot)
);
Query OK, 0 rows affected
制約を満たすデータを挿入します。
sample_constraints.sql
INSERT INTO employees (name, email, department, salary, age)
VALUES ('岡部倫太郎', 'okabe@example.com', '未来ガジェット研究所', 250000, 24);
Query OK, 1 row affected (0.01 sec)
sample_constraints.sql
SELECT * FROM employees;
+-------------+------------+-------------------+----------------------+--------+------+ | employee_id | name | email | department | salary | age | +-------------+------------+-------------------+----------------------+--------+------+ | 1 | 岡部倫太郎 | okabe@example.com | 未来ガジェット研究所 | 250000 | 24 | +-------------+------------+-------------------+----------------------+--------+------+ 1 row in set
実行結果
UNIQUE 制約に違反した INSERT を実行した場合のエラー例(MySQL)です。
-- ERROR 1062 (23000): Duplicate entry 'okabe@example.com' for key 'employees.email'
CHECK 制約に違反した INSERT を実行した場合のエラー例(MySQL 8.0.16以降)です。
-- ERROR 3819 (HY000): Check constraint 'chk_salary' is violated.
データベース別の書き方
『NOT NULL』『UNIQUE』『DEFAULT』は主要なデータベースで共通して使用できます。
CREATE TABLE employees (
employee_id INT NOT NULL,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
department VARCHAR(50) NOT NULL DEFAULT '未配属',
salary INT NOT NULL DEFAULT 0
);
『CHECK』制約は PostgreSQL・SQLite では以前からサポートされていますが、MySQL では 8.0.16 以降のサポートです。それより前のバージョンでは構文エラーにはなりませんが制約が無視されます。
-- MySQL 8.0.16以降・PostgreSQL・SQLite(共通構文)
CREATE TABLE employees (
salary INT NOT NULL,
age INT,
CONSTRAINT chk_salary CHECK (salary >= 0),
CONSTRAINT chk_age CHECK (age IS NULL OR age BETWEEN 18 AND 100)
);
『CONSTRAINT 名前』で制約に名前を付ける構文も共通ですが、エラーメッセージの表示形式はデータベースごとに異なります。
概要
制約はデータベース側でデータの正確性を保証する仕組みです。アプリケーション側のバリデーションと二重にガードをかけることで、予期しないデータが入り込むリスクを大幅に減らせます。
『NOT NULL』と『DEFAULT』を組み合わせると、値の省略は許可しつつNULLは禁止するという設定が可能です。例えば『score INT NOT NULL DEFAULT 0』は、scoreを省略した場合に0が自動設定されます。
主キーや外部キーについては『PRIMARY KEY / FOREIGN KEY』を参照してください。テーブル作成の基本は『CREATE TABLE』で確認できます。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。