データベースでは、間違ったデータが入らないようにするための仕組みがあります。それが制約です。
一言でいうと
制約は、アプリ側の注意だけに頼らず、データベース自身にデータのルールを守らせる仕組みです。
代表的な制約
| 制約 | 役割 |
|---|---|
PRIMARY KEY | 行を一意に識別する |
FOREIGN KEY | 別テーブルとの関係を守る |
UNIQUE | 重複を防ぐ |
NOT NULL | 値なしを防ぐ |
CHECK | 条件に合わない値を防ぐ |
PRIMARY KEY
主キーは、テーブル内の1行を一意に識別します。
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
id が主キーなら、同じ id のユーザーは2人作れません。
主キーには、検索しやすくするだけでなく、他のテーブルから参照される役割もあります。
NOT NULL
NOT NULL は、値が入っていない状態を禁止します。
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL
);
名前やメールアドレスが必須なら、NOT NULL を付けます。
必ず必要な値には、アプリ側の入力チェックだけでなくNOT NULL制約を付けます。
UNIQUE
UNIQUE は、同じ値の重複を防ぎます。
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL UNIQUE
);
この場合、同じメールアドレスのユーザーは登録できません。
ログインID、メールアドレス、スラッグなど、重複してはいけない値に使います。
FOREIGN KEY
外部キーは、別テーブルの主キーを参照します。
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
total INTEGER NOT NULL
);
この制約があると、存在しない users.id を orders.user_id に入れにくくなります。
外部キーは、JOINのためだけでなく、データの整合性を守るために重要です。
CHECK
CHECK は、値が条件を満たすことを確認します。
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price INTEGER NOT NULL CHECK (price >= 0)
);
価格がマイナスになることを防げます。
制約がないと何が起きるか
| 制約がない状態 | 起きる問題 |
|---|---|
| 主キーがない | 1行を特定しにくい |
NOT NULL がない | 必須値が空の行が入る |
UNIQUE がない | 同じメールアドレスが重複する |
| 外部キーがない | 存在しないユーザーの注文が入る |
CHECK がない | マイナス価格などが入る |
よくある誤解
| 誤解 | 実際 |
|---|---|
| アプリでチェックするから制約はいらない | バグや別経路の登録を防げません |
| 外部キーはJOINに必須 | JOINはできますが、整合性は守られません |
UNIQUE は後から考えればよい | 重複データが入った後の修正は大変です |
NULL 許可で柔軟になる | 必須データが欠ける原因になります |
まとめ
制約は、データベースにデータのルールを守らせる仕組みです。PRIMARY KEY、NOT NULL、UNIQUE、FOREIGN KEY、CHECK を適切に使うと、アプリのバグや運用ミスがあっても壊れにくいデータ構造になります。