MySQL ERROR 1264: 列の値が範囲外 (Integer Overflow) の修正方法

beginner🗄️ MySQL2026-06-01| Linux、macOS、Windows 上の MySQL 5.7 / 8.0+ — strict モード (STRICT_TRANS_TABLES) がデフォルトで有効

Error Message

ERROR 1264 (22003): Out of range value for column 'age' at row 1
#mysql#strict-mode#data-type#integer#overflow

エラーの内容

ERROR 1264 (22003): Out of range value for column 'age' at row 1

このエラーは、値がカラムのデータ型の範囲に収まらないときに発生します。MySQL のストリクトモード(5.7 以降はデフォルトで有効)は、不正なデータを黙って切り捨てることを拒否し、このエラーをスローします。

典型的な原因:age カラムが TINYINT(最大 127)なのに、300 という値が送られてきた場合です。もう一つよくあるケース:INT カウンターカラムに、2 つの大きな数値を掛け合わせた計算結果が入り、2,147,483,647 を超えてしまう場合です。

ステップ 1 — カラムのデータ型を確認する

問題のカラムの実際の型を確認します:

DESCRIBE users;
-- より詳しい情報:
SHOW COLUMNS FROM users LIKE 'age';

次のような出力が表示されます:

+-------+---------+------+-----+---------+
| Field | Type    | Null | Key | Default |
+-------+---------+------+-----+---------+
| age   | tinyint | YES  |     | NULL    |
+-------+---------+------+-----+---------+

これで上限値がわかります。符号付き整数の範囲は以下のとおりです:

TINYINT    : -128          to  127
SMALLINT   : -32,768       to  32,767
MEDIUMINT  : -8,388,608    to  8,388,607
INT        : -2,147,483,648 to  2,147,483,647
BIGINT     : -9.2 × 10^18  to  9.2 × 10^18

UNSIGNED を付けると正の上限が 2 倍になります。TINYINT UNSIGNED は 0〜255、SMALLINT UNSIGNED は 0〜65,535 になります。

ステップ 2 — 修正方法を選ぶ

3 つのアプローチがあります。どれが適切かは、カラムの型が狭すぎるのか、入力データが不正なのか、あるいはその両方なのかによって異なります。

修正 A — カラムの型を拡大する

正当な値が収まらない場合は、カラムを変更します:

-- age は TINYINT では 127 を超えられない — SMALLINT UNSIGNED に変更
ALTER TABLE users MODIFY COLUMN age SMALLINT UNSIGNED;

-- view カウンターが INT の上限 2.1B に達した場合 — BIGINT に切り替え
ALTER TABLE events MODIFY COLUMN view_count BIGINT UNSIGNED NOT NULL DEFAULT 0;

ALTER 後に失敗していた INSERT を再実行してください。今度は成功するはずです。

修正 B — 入力データを検証して修正する

不正なデータが送られてくる場合は、発生源を修正します。データベースレベルで検出するために MySQL の CHECK 制約を追加します:

-- MySQL 8.0.16+ では CHECK 制約をサポート
ALTER TABLE users ADD CONSTRAINT chk_age CHECK (age BETWEEN 0 AND 120);

-- 300 を挿入すると明確な制約エラーが発生する
INSERT INTO users (name, age) VALUES ('Alice', 300);
-- ERROR 3819 (HY000): Check constraint 'chk_age' is violated.

または、INSERT が実行される前にアプリ側で検証します:

# Python の例
if not (0 <= age <= 120):
    raise ValueError(f"Age {age} is out of valid range")

修正 C — 負の値が不要な場合は UNSIGNED に切り替える

ID、カウント、サイズを格納するカラムは負の値を持つことがありません。それを明示することで、余裕を無料で 2 倍に増やせます:

ALTER TABLE orders MODIFY COLUMN quantity SMALLINT UNSIGNED NOT NULL DEFAULT 0;
-- SMALLINT UNSIGNED: 0 〜 65,535(符号付きの上限 32,767 との比較)

ストリクトモードについて

古い MySQL 5.6 サーバー、またはストリクトモードが無効になっているインスタンスでは、エラーを出さずに値を型の最大値・最小値にクランプしていました。現在のモードを確認します:

SELECT @@sql_mode;

出力に STRICT_TRANS_TABLES または STRICT_ALL_TABLES が表示されていれば、ストリクトモードが有効です。これは正しい動作です。このエラーは機能の一部であり、MySQL がデータを静かに破損することを拒否しているのです。

**回避策としてストリクトモードを無効にしないでください。**誤ったデータが黙って保存されるだけで、目に見えるエラーよりもはるかに深刻な問題を引き起こします。

MySQL が実際にどの値にクランプするか確認したい場合は、一時的にテストできます:

SET sql_mode = '';
INSERT INTO users (name, age) VALUES ('test', 300);
-- 127(TINYINT の最大値)が挿入される — エラーは出ないが、データは間違い
SELECT age FROM users WHERE name = 'test';
-- 127 が返される

テスト後はすぐにストリクトモードを再有効化してください:

SET sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';

修正を確認する

ALTER 後に、型が実際に変更されたことを確認します:

SHOW COLUMNS FROM users LIKE 'age';
-- SMALLINT UNSIGNED と表示されるはず

次に、以前失敗していた INSERT を実行します:

INSERT INTO users (name, age) VALUES ('Bob', 300);
Query OK, 1 row affected (0.01 sec)

SELECT age FROM users WHERE name = 'Bob';
-- 300 が返される ✓

再発防止のためのヒント

  • カラムは今日のデータだけでなく、実際のドメインに合わせてサイズを決める。 age カラムに BIGINT は不要ですが、TINYINT は心もとない — SMALLINT UNSIGNED が適切な選択です。
  • トラフィックの多いテーブルの ID と自動インクリメントカウンターには BIGINT を使う。 INT の 21 億という上限は、思ったよりも早く尽きます。
  • ビジネスロジックの制限には CHECK 制約を追加する(MySQL 8.0.16+)。どのアプリが書き込んでも DB レベルでルールが強制され、エラーメッセージも明確です。
  • **開発中に境界値をテストする。**リリース前に型の最小値と最大値を挿入しておく — エッジケースは本番より開発段階で発見する方がコストが低い。
  • **ストリクトモードは有効のままにしておく。**データの暗黙的な切り捨ては、診断に何週間もかかるバグを生みます。最初からエラーが出る方が親切です。

Related Error Notes