【実務・中級編】 CHECK制約 – PostgreSQL

やあ、今日もデータベースと格闘してる?

PostgreSQLを触っていると、ついつい「バリデーションは全部アプリケーション側のコードでやればいいや」って考えがちだよな。わかるよ、その気持ち。ORM(Object-Relational Mapper)の機能でサクッとチェックしたほうが手っ取り早いしね。

でもね、もし君が「堅牢なシステム」を作りたいなら、データの入り口であるデータベース側でルールを固めることを強くおすすめするよ。

今日は、そのための最もシンプルで強力な武器、「CHECK制約」について話そうと思う。

—

CHECK制約って何のためにあるの?

一言で言うと、「データベース自身に、データの番人をさせる」ための仕組みだ。

アプリケーションのコードは、将来的に別の言語に書き換わるかもしれないし、誰かが間違えて直接SQLを叩いてデータを修正するかもしれない。そんなとき、もしDB側に何のガードレールもなかったらどうなる? 整合性の取れていないデータが紛れ込んで、後々バグの温床になる……なんて悲劇は、現場で何度も見てきたよ。

CHECK制約は、そのカラムにどんな値が入るべきかをデータベースに直接教え込む。条件を満たさないデータは、DBが「おい、そのデータはルール違反だぞ!」と門前払いしてくれるんだ。

実践例:こんなふうに使ってみよう

例えば、ユーザーの年齢を管理するテーブルがあるとしよう。年齢にマイナスなんてありえないし、200歳を超えるようなデータもおかしいよね。

CREATE TABLE users (
id SERIAL PRIMARY KEY,
username TEXT NOT NULL,
age INTEGER CHECK (age >= 0 AND age <= 150) ); こうしておけば、もし誰かが `INSERT INTO users (username, age) VALUES ('hoge', -5);` なんてSQLを投げても、PostgreSQLがエラーを返して書き込みを拒否してくれる。これだけで、アプリケーション側の「年齢がマイナスじゃないかチェック」というコードを一つ減らせるわけだ。

もう一歩進んだ使い方:より複雑な条件

CHECK制約は、一つのカラムだけじゃなくて、行全体(複数のカラム)を見ることもできる。

例えば、「開始日」と「終了日」を持つタスクテーブルを想像してみてくれ。「終了日は必ず開始日より後でなければならない」というルールを強制したい場合、こう書くんだ。

CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
— 終了日が開始日より前ならエラーにする
CONSTRAINT valid_dates CHECK (end_date >= start_date)
);

`CONSTRAINT` を使って名前を付けておくと、エラーが出たときに「どのルールに違反したか」が明確になるから、運用中もデバッグが楽になるぞ。これは実務では地味に大事なテクニックだね。

現場のエンジニアとして知っておいてほしい「注意点」

ただ、何でもかんでもCHECK制約に入れればいいっていうわけじゃない。いくつか注意点がある。

  • 複雑すぎるロジックは避ける:

CHECK制約の中で重い関数を呼び出したり、他のテーブルを参照したりするのはNGだ。パフォーマンスがガタ落ちするし、そもそもPostgreSQLの制約は基本「その行単体」で完結させるのが鉄則。外部テーブルとの整合性が必要なら、それは外部キー制約やトリガーの出番だ。

  • エラーメッセージをアプリにどう伝えるか:

制約違反でエラーになると、DBからは標準的なエラーコードが返ってくる。これをフロントエンドまでどうやって分かりやすく伝えるかは、アプリケーション側の設計次第だ。DB側でガチガチに固めるなら、エラーハンドリングの設計もセットで考えよう。

最後に:データベースを「信じられる場所」にするために

DBを単なる「データの入れ物」と考えるか、「データの守護者」と考えるか。ここが、エンジニアとしての力量の分かれ道だと思うんだ。

CHECK制約は、記述量に対して得られるメリットがめちゃくちゃ大きい。設計段階で「この値は、どういう状態なら正解なのか?」を一度立ち止まって考える。その癖がつくだけで、君が作るシステムのデータ品質は格段に上がるはずだ。

まずは今開発しているテーブルで、「絶対にありえない値」がないかチェックしてみることから始めてみないか?

もし書いてみて詰まったら、いつでも聞いてくれ。また現場で会おう。

コメント

タイトルとURLをコピーしました