投稿日:2026/6/16
更新日:2026/6/16

データベースの「CHECK(チェック)制約」について、初心者にも分かりやすい具体例を交えてまとめたマークダウン資料を作成しました。そのままコピー&ペーストしてドキュメント等にご活用ください。
CHECK制約(チェック制約)とは、データベースのテーブルに設定できる「データのルール(バリデーション)」機能です。
指定した条件(数式や値の組み合わせなど)を満たさないデータが追加・更新されようとした場合、データベース側が自動的にそれを拒否(エラー)します。
役割: アプリケーション側のバグや手作業でのデータ操作による「矛盾したデータ(ゴミデータ)」の混入を100%防ぐ最後の砦。
特徴: データの追加(INSERT)や更新(UPDATE)のたびに、自動で高速にチェックが走ります。
もっともイメージしやすい例として、ECサイトの「注文(orders)」テーブルを考えてみましょう。
このサイトには、以下の絶対に破ってはならない2つのルールがあるとします。
割引金額(discount_price)は、必ず「0円以上」でなければならない(マイナスは不可)。
「送料無料フラグ(is_free_shipping)」が TRUE(無料)のときは、送料(shipping_fee)は絶対に 0円 でなければならない。
このルールをDBに強制させるためのSQLは以下のようになります。
SQL
CREATE TABLE orders (
order_id INT PRIMARY KEY,
product_name VARCHAR(100),
discount_price INT,
is_free_shipping BOOLEAN,
shipping_fee INT,
-- 例1: 単一カラムのチェック(マイナス価格の禁止)
CONSTRAINT orders_discount_price_check
CHECK (discount_price >= 0),
-- 例2: 複数カラムの組み合わせチェック(送料無料時の矛盾禁止)
CONSTRAINT orders_free_shipping_fee_check
CHECK (
(is_free_shipping = TRUE AND shipping_fee = 0)
OR
(is_free_shipping = FALSE AND shipping_fee >= 0)
)
);
| discount_price | is_free_shipping | shipping_fee | 判定理由 |
|---|---|---|---|
500 |
TRUE |
0 |
割引は0以上、送料無料で送料0円。完璧。 |
0 |
FALSE |
600 |
割引は0以上、通常の送料が発生。問題なし。 |
| discount_price | is_free_shipping | shipping_fee | DBが返すエラーの理由 |
|---|---|---|---|
-100 |
TRUE |
0 |
orders_discount_price_check 違反(割引にマイナス値は不可) |
500 |
**TRUE |
600** |
orders_free_shipping_fee_check 違反(送料無料なのに送料600円は矛盾) |
Webアプリ(プログラム)側にもバリデーションは書きますが、プログラムのバグで書き漏らしたり、開発者がデータベースを直接手修正したりした際に、すり抜けてしまうリスクがあります。DB側に制約があれば、どのような経路からの操作であっても不正データを確実にブロックします。
orders_free_shipping_fee_check という制約名とその条件を見るだけで、後からプロジェクトに参画した開発者でも「あ、このシステムは送料無料のときは送料カラムを0にするルールなんだな」と一目で仕様を理解できます。
| 比較項目 | アプリ側のバリデーション (Zod, Rails等) | DB側のCHECK制約 |
|---|---|---|
| 主な目的 | ユーザーへエラーを分かりやすく伝えるため | 不正なデータ混入を防ぐ最後の砦 |
| エラー表示 | 「送料を入力してください」など、画面に優しく表示可能 | 「SQLエラー」が発生するため、画面表示には不向き |
| ガードの堅さ | 実装漏れや直接のDB操作ですり抜ける可能性あり | 絶対にすり抜けられない |
💡 結論: ユーザーが触る画面(アプリ側)で優しくチェックし、最終的な保存場所(DB側)でガッチリ守るという「二重チェック(両方に書く)」が、安全なシステム開発のベストプラクティスです。