CodeGym /コース /SQL SELF /CHECK 制約でデータをチェックする方法

CHECK 制約でデータをチェックする方法

SQL SELF
レベル 17, レッスン 3
使用可能

CHECK 制約は、ある意味テーブルの入り口にいるガードマンみたいなもの。テーブルに追加するデータが、決められた条件に合ってるかどうかを保証してくれる。もし条件に合わないデータを入れようとしたら、データベースはそれを拒否するよ。

例えば、ドイツでお店を開きたいとする。でも法律で 日曜日は休み で、その日は営業禁止なんだ。これがデータベースの CHECK 制約みたいなもの。お店のスケジュールを 週7日営業 って設定しようとすると、システムがすぐに「"Nein, nein, nichiyoubi wa kinshi. Sonna schedule wa NG da yo!"」って返してくる。

データベースでも同じ。CHECK のルールに違反する値を入れようとしたら、システムがブロックして「ロジックエラー」を防いでくれる。

なんで CHECK が必要なの?

  1. データ品質の維持: CHECK はテーブルに変なデータやロジックに合わない情報が入るのを防いでくれる。
  2. ミスの減少: データを追加する前に毎回手動でチェックしなくても、データベースに任せられる。
  3. ロジックの自立性: チェックルールをデータベース構造に組み込めるから、アプリ側で毎回書かなくてOK。

CHECK はどうやって動くの?

CHECK 制約はテーブル作成時に指定できるし、あとから ALTER TABLE コマンドで追加もできる。基本のシンタックスはこんな感じ:

CREATE TABLE テーブル (
    カラム データ型 CHECK (条件)
);

条件 は、指定したカラムの値ごとに成り立つべきロジック式だよ。条件に違反したら、データベースがエラーを返す。

例1: 値の範囲チェック

例えば students テーブルを作って、学生の年齢(age)が16〜100の間だけOKにしたいとする:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INTEGER CHECK (age >= 16 AND age <= 100)
);

これで、もし12歳の学生を追加しようとしたら、データベースが「ダメだよ!」って止めてくれる:

INSERT INTO students (name, age)
VALUES ('Maria Chi', 12);

エラー:

ERROR:  new row for relation "students" violates check constraint "students_age_check"
DETAIL:  Failing row contains (1, Maria Chi, 12).

そう、データベースはここで厳しい門番。16歳未満はダメだよ。

例2: データ形式のチェック

例えば emails テーブルがあって、メールアドレス一覧を保存してるとする。アドレスに @ が入ってるかだけでもチェックしたい(簡易バージョン):

CREATE TABLE emails (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) CHECK (email LIKE '%@%')
);

条件に合わないアドレスを追加しようとすると:

INSERT INTO emails (email)
VALUES ('notanemail.com');

エラー:

ERROR:  new row for relation "emails" violates check constraint "emails_email_check"
DETAIL:  Failing row contains (1, notanemail.com).

全部のデータに @ が入ってればエラーは出ない:

INSERT INTO emails (email) 
VALUES ('example@student.com');

このクエリはちゃんと通るよ。

例3: 複数カラムの条件チェック

CHECK 制約は1つのカラムだけじゃなくて、複数カラムにまたがるロジック式もOK。例えば employees テーブルで、給料(salary)がボーナス(bonus)より大きくなきゃダメってルール:

CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    salary NUMERIC CHECK (salary > 0),
    bonus NUMERIC CHECK (bonus >= 0),
    CHECK (salary > bonus)
);

これで、ボーナスが給料より多い社員を追加しようとしたら、データベースが止めてくれる:

INSERT INTO employees (name, salary, bonus)
VALUES ('Otto Lin', 3000, 4000);

エラー:

ERROR:  new row for relation "employees" violates check constraint "employees_salary_bonus_check"
DETAIL:  Failing row contains (1, Otto Lin, 3000, 4000).

実践的な使い方

CHECK 制約は、ビジネスロジックがデータ制約と密接に関係してる時に超便利。例えば:

  1. ネットショップ: マイナス価格の商品を追加禁止。
  2. 教育プラットフォーム: コース参加者の年齢チェック。
  3. 医療システム: 患者の体温が許容範囲内かチェック。

こういうチェックは、ただのセキュリティレイヤーじゃなくて、開発者やユーザーの手間とストレスを減らしてくれるんだ。

特徴とよくあるミス

CHECK を使う時は、次のポイントに注意しよう:

  • CHECK のロジック式は、テーブルの全行でtrueにならなきゃダメ。もし1行でも違反してたら、制約追加前にその行を直す必要があるよ。

  • 挿入する値が NULL の場合、チェックは実行されない。つまり CHECK (age >= 18) でも age = NULL ならエラーにならない。これは、NULL を含む式は自動的に未定義になるから。NULL を禁止したいなら NOT NULL も追加しよう。

  • CHECK の条件が複雑すぎると、大きなテーブルでデータ追加・更新時にパフォーマンスが落ちることもある。

2
タスク
SQL SELF, レベル 17, レッスン 3
ロック未解除
CHECK制約を使った値の範囲チェック
CHECK制約を使った値の範囲チェック
2
タスク
SQL SELF, レベル 17, レッスン 3
ロック未解除
複数カラムの条件チェック
複数カラムの条件チェック
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION