本文へスキップ
BecomeCoder

SQL テーブル設計 (DDL)コース · 第1章 テーブルを設計する · レッスン5

制約 ― 正しいデータだけを守る

ブラウザで完結

導入

テーブルを作るとき、列に 制約(constraint) を付けられます。制約とは「この列に入れてよいデータのルール」。ルールをデータベース自身に守らせることで、間違ったデータ(必須の欄が空、ID の重複、負の年齢…)がそもそも入らないようにできます。アプリ側のチェックは書き忘れますが、DB の制約は忘れません。ここが「壊れにくい設計」の要です。

説明

代表的な制約を、CREATE TABLE の列定義に書き足していきます。

CREATE TABLE members (
  id    INTEGER PRIMARY KEY,
  email TEXT NOT NULL UNIQUE,
  age   INTEGER CHECK (age >= 0),
  city  TEXT DEFAULT '未設定'
);
flowchart TB
    PK["PRIMARY KEY(主キー)<br/>行を一意に識別。重複×・空× 1表に1つ"]
    NN["NOT NULL<br/>空(NULL)を禁止。必須の欄に"]
    UQ["UNIQUE<br/>値の重複を禁止(メール等)"]
    DF["DEFAULT 値<br/>INSERT で省略したときの初期値"]
    CK["CHECK(条件)<br/>条件を満たす値だけ許す(age >= 0 等)"]

制約が働くか試してみましょう。同じメールを2回入れるとエラーになります。

INSERT INTO members (id, email, age) VALUES (1, 'a@example.com', 20);
INSERT INTO members (id, email, age) VALUES (2, 'a@example.com', 30);

2件目で「UNIQUE constraint failed」というエラーが出れば、制約が守ってくれた証拠です。

外部キー(FOREIGN KEY) は、別のテーブルの行を指す列に付けます。データを消したり変えたりするときに問題になる「参照整合性」を、DB に守らせるための制約です。「この user_id は必ず users に実在する id であること」を表明し、迷子のデータが生まれないようにします。

CREATE TABLE reviews (
  id      INTEGER PRIMARY KEY,
  user_id INTEGER NOT NULL,
  comment TEXT,
  FOREIGN KEY (user_id) REFERENCES users(id)
);

SQLite では外部キーのチェックは既定でオフで、有効にするには PRAGMA foreign_keys = ON; を実行します(MySQL / PostgreSQL では既定で有効)。それでも、設計として FOREIGN KEY を書くことは「このテーブルはあの表につながっている」という意図を残す大切な記録になります。

やってみよう

初期表示の members テーブルを作成してから、上の2つの INSERT を続けて実行し、2件目で UNIQUE 制約のエラーが出ることを確かめましょう。次に city を省略した INSERT INTO members (id, email, age) VALUES (3, 'b@example.com', 40); を入れ、SELECT * FROM members; で city が「未設定」になっていることを見てください。

演習

id(整数・主キー)、name文字列・NOT NULL)、stock(整数・0以上の CHECK・DEFAULT 0)を持つ items テーブルを作ってください。

ヒント1を見る

stock の列には INTEGER CHECK (stock >= 0) DEFAULT 0 のように制約を並べて書けます。

ヒント2を見る

CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT NOT NULL, stock INTEGER CHECK (stock >= 0) DEFAULT 0);

実際に動かしてみよう

下のエディタにクエリを書いて「実行」を押すと、ブラウザ内のSQLiteで結果が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう。

SQL — ブラウザ内で実行(SQLite)

ブラウザ内でSQLを動かす環境(SQLite)を読み込みます(初回のみ一瞬)。
スクロールして表示された時点でも自動で読み込まれます。