MySQLのエラー『エラー1690: BIGINT value is out of range』の解決方法

MySQLのエラー『エラー1690: BIGINT value is out of range』の解決方法

MySQLで「ERROR 1690 (22003): BIGINT value is out of range」が発生するのは、数値演算の結果がBIGINT型の上限または下限を超えた場合。このエラーは、演算処理やデータ型の不一致が原因で発生する。SIGNED/UNSIGNEDの違いにも注意が必要で、正しく理解していないと思わぬバグを招く。

1. エラーメッセージの内容と意味

ERROR 1690 (22003): BIGINT UNSIGNED value is out of range

このエラーは、MySQLが演算中に想定する範囲(BIGINTの最大・最小値)を超えたことを意味する。特にUNSIGNED(負の値を取らない)型では、0未満の値が割り当てられると発生する。

2. 発生条件:UNSIGNEDに負の値を代入

CREATE TABLE test (
  value BIGINT UNSIGNED
);

INSERT INTO test (value) VALUES (-1);

このように、UNSIGNED型カラムに負の値を挿入しようとするとエラーが出る。

3. 発生条件:演算によるオーバーフロー

SELECT POW(2, 64); -- BIGINTの上限を超える

MySQLのBIGINT UNSIGNEDの上限は 18,446,744,073,709,551,615 (2^64-1)、SIGNEDは 9,223,372,036,854,775,807 (2^63-1)。それを超える計算はオーバーフローになる。

4. 発生条件:符号なし列への減算

UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;

`balance` が UNSIGNED かつ現在値が 50 の場合、この演算は `-50` となりエラー1690が発生する。

5. 対策1:SIGNED型に変更する

負の値の可能性がある場合、UNSIGNEDからSIGNEDに変更することでエラーを防ぐ。

ALTER TABLE test MODIFY value BIGINT;

6. 対策2:値を事前にチェックする

演算前に負の結果にならないかチェックしておくことで安全性を高められる。

UPDATE accounts SET balance = GREATEST(balance - 100, 0) WHERE user_id = 1;

7. 対策3:オーバーフローしないようにデータ型を見直す

例えば、計算結果がINTの上限を超える場合にはBIGINTへ、BIGINTの上限を超える場合はDECIMALやDOUBLEへの変更を検討する。

ALTER TABLE metrics MODIFY value DECIMAL(65, 0);

8. CASTで一時的に型を変える

演算中のみSIGNEDに変換することも可能。

SELECT CAST(balance AS SIGNED) - 100 FROM accounts;

9. 暗黙の型変換によるエラー

たとえば、UNSIGNEDカラムに対して `-` 演算子を使うと、MySQLはSIGNEDにキャストせずにそのまま処理しようとしてエラーになる。

10. ログやトリガーで事前チェックする

INSERTやUPDATE前にトリガーで範囲を超える処理を拒否するロジックを追加することも可能。

CREATE TRIGGER check_balance_before_update
BEFORE UPDATE ON accounts
FOR EACH ROW
BEGIN
  IF NEW.balance < 0 THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Balance cannot be negative';
  END IF;
END;

11. INSERT … SELECT構文でも発生する

INSERT INTO test_unsigned (value)
SELECT -1;

この場合も、UNSIGNED型に負の値をINSERTするためエラー1690が起きる。

12. ORMやアプリケーション経由のバグにも注意

RailsやLaravelなどのフレームワークが、MySQLの型に応じて勝手にUNSIGNEDを使っているケースがある。マイグレーションの確認は必須。