🐬

MySQL“TINYINT(1)=BOOLEAN”の罠──0/1制約で完全ガード

に公開

1️⃣ “BOOLEAN = 真偽値” は都市伝説? ― まずは素手で SQL 実験

ステップ0: 準備

# 作業用フォルダ(任意)
mkdir mysql-tinybool && cd mysql-tinybool

ステップ1: MySQL 8.3 コンテナを起動

docker run -d --name tinybool-test \
  -e MYSQL_ROOT_PASSWORD=root \
  -p 33060:3306 \
  mysql:8.3

ステップ2: MySQL クライアントで接続

コンテナ内から直接 client を叩くと楽です。

docker exec -it tinybool-test mysql -uroot -proot

ステップ3: SQL を実行して “しれっと入る” を検証

コピー&ペーストで一気にどうぞ👇

-- 1. テスト用 DB とテーブル
CREATE DATABASE IF NOT EXISTS demo;
USE demo;

DROP TABLE IF EXISTS tiny_bool_raw;
CREATE TABLE tiny_bool_raw (
  id   INT AUTO_INCREMENT PRIMARY KEY,
  flag TINYINT(1) NOT NULL  -- いわゆる BOOLEAN
);

-- 2. 普通に 0 / 1 を入れてみる
INSERT INTO tiny_bool_raw(flag) VALUES (0), (1);

-- 3. あえて -128 や 127 を入れてみる
INSERT INTO tiny_bool_raw(flag) VALUES (-128), (127);

-- 4. 結果を確認
SELECT * FROM tiny_bool_raw;

実行結果 (例)

+----+------+
| id | flag |
+----+------+
|  1 |    0 |
|  2 |    1 |
|  3 | -128 |   ← しれっと入る
|  4 |  127 |   ← これも入る
+----+------+

😱 実は TINYINT(1) は実質 -128~127 が入ってしまう。
BOOLEAN 型エイリアスでも 保存レイヤ では制限されません。

2️⃣ MySQL 8 の CHECK 制約 で 0 / 1 にロックする

ステップ1: 新しいテーブルを作成

-- 既存テーブルがあれば削除
DROP TABLE IF EXISTS tiny_bool_chk;

-- CHECK 制約付きテーブルを作成
CREATE TABLE tiny_bool_chk (
  id   INT AUTO_INCREMENT PRIMARY KEY,
  flag TINYINT(1) NOT NULL,
  CONSTRAINT chk_flag_bool CHECK (flag IN (0,1))   -- ★ここがポイント
);
  • CHECK (flag IN (0,1)) が “0 または 1 以外は拒否” というルール
  • MySQL 8.0.16 以降で正式サポート(それ以前は無視されるので要注意)

ステップ2: INSERT して動作確認

-- ✅ OK になるケース
INSERT INTO tiny_bool_chk(flag) VALUES (0), (1);

-- ❌ NG をわざと入れてみる
INSERT INTO tiny_bool_chk(flag) VALUES (2);

結果:

ERROR 3819 (HY000): Check constraint 'chk_flag_bool' is violated.

これで DB レイヤだけでも誤値をシャットアウト!

ステップ3: まとめ

やったこと 効果
CHECK (flag IN (0,1)) を付与 0/1 以外を SQL レベルで拒否
NG データの INSERT を検証 3819 エラーで弾かれることを確認

Discussion