【Oracle】ORA-06502 の原因と解決方法完全ガイド|PL/SQL 数値または値のエラー・VARCHAR2バッファ・NUMBER精度・暗黙変換まで解説

【Oracle】ORA-06502 の原因と解決方法完全ガイド|PL/SQL 数値または値のエラー・VARCHAR2バッファ・NUMBER精度・暗黙変換まで解説 Oracle

ORA-06502: PL/SQL: 数値または値のエラーです(英語: numeric or value error)は、PL/SQL実行時に最も頻繁に遭遇するランタイムエラーのひとつです。変数への代入時に型・精度・サイズが一致しないときに発生します。

このエラーはSQL文ではなくPL/SQLブロック内で起きるため、スタックトレースがなければ発生箇所の特定が難しいという特徴があります。本記事では発生パターンごとに原因と対処法を整理し、Oracle 12.2以降で強化されたデバッグ方法も解説します。

この記事でわかること

  • ORA-06502 の発生メカニズムと主なサブコード
  • VARCHAR2 バッファオーバーフローのパターンと対処法
  • NUMBER 型の精度・スケール超過のパターンと対処法
  • 暗黙的な型変換失敗(文字列→数値、文字列→日付)のパターン
  • 文字セット変換によるバイト数超過のパターン
  • FORMAT_ERROR_BACKTRACE を使った発生行の特定方法
  • Oracle 12.2 以降のエラーメッセージ改善(実際の値・サイズが表示)
スポンサーリンク

ORA-06502 の発生メカニズムとサブコード

ORA-06502 は単体で発生することもありますが、多くの場合サブコードと追加メッセージが付随します。サブコードが実際の原因を示しているため、まずそこを読むことが診断の第一歩です。

主なサブコード・追加メッセージ 原因
ORA-06502: PL/SQL: numeric or value error: character string buffer too small VARCHAR2/CHAR 変数の宣言長より長い文字列を代入しようとした
ORA-06502: PL/SQL: numeric or value error: number precision too large NUMBER 変数の精度(桁数)を超える値を代入しようとした
ORA-06502: PL/SQL: numeric or value error: character to number conversion error 数値に変換できない文字列を NUMBER 変数に代入しようとした
ORA-06502: PL/SQL: numeric or value error 上記以外の型変換・演算エラー(除算0はORA-01476)
Oracle 12.2 以降のエラーメッセージ改善
Oracle 12.2(12cR2)以降では、”character string buffer too small” の場合に「実際の値の長さ」と「変数の宣言長」が表示されるようになりました。例:ORA-06502: PL/SQL: numeric or value error: character string buffer too small (actual: 25, maximum: 10)これにより発生箇所の特定が格段に楽になりました。Oracle 19c・21c・23ai でも同様です。

パターン:VARCHAR2 バッファオーバーフロー(最多発生)

最も頻繁に発生するパターンです。PL/SQL変数の宣言長より長い文字列を代入しようとすると発生します。SQL の VARCHAR2 列はエラーにならず暗黙的に切り捨て(TRUNC)しますが、PL/SQL変数は例外を発生させます

NG: 宣言長より長い文字列を代入
DECLARE
    v_name VARCHAR2(10);   -- 最大10文字で宣言
BEGIN
    v_name := 'Hello, World!';   -- 13文字 → ORA-06502
    DBMS_OUTPUT.PUT_LINE(v_name);
END;
/
-- ORA-06502: PL/SQL: numeric or value error: character string buffer too small
OK: 宣言長を実際の最大長に合わせる
DECLARE
    v_name VARCHAR2(100);   -- 十分な長さで宣言
BEGIN
    v_name := 'Hello, World!';   -- 13文字 → 問題なし
    DBMS_OUTPUT.PUT_LINE(v_name);
END;
/
OK: %TYPE を使って列定義から長さを継承する(推奨)
DECLARE
    -- テーブルの列定義から自動的に型・長さを継承する(最も安全)
    v_name employees.last_name%TYPE;
BEGIN
    SELECT last_name INTO v_name FROM employees WHERE employee_id = 100;
    DBMS_OUTPUT.PUT_LINE(v_name);
END;
/
-- %TYPE を使えば列の定義が変わっても自動追従する

文字列操作関数の戻り値を代入するときも注意が必要です。SUBSTR・REPLACE・CONCAT などの戻り値が変数の宣言長を超えると発生します。

NG: SUBSTR 結果が変数長を超える
DECLARE
    v_short VARCHAR2(5);
    v_long  VARCHAR2(4000) := 'ABCDEFGHIJ';
BEGIN
    -- SUBSTR(v_long, 1, 10) の戻り値は 10 文字 → v_short(5) に入らない
    v_short := SUBSTR(v_long, 1, 10);   -- ORA-06502
END;
/
OK: SUBSTR の第3引数を変数長に合わせる
DECLARE
    v_short VARCHAR2(5);
    v_long  VARCHAR2(4000) := 'ABCDEFGHIJ';
BEGIN
    v_short := SUBSTR(v_long, 1, 5);   -- 5文字以内に切り出す
    -- または
    v_short := SUBSTR(v_long, 1, LENGTH(v_short));  -- 変数長で制限
END;
/

パターン:NUMBER 型の精度・スケール超過

NUMBER(p, s) 型の変数に、精度(p)またはスケール(s)を超える値を代入しようとすると発生します。

NUMBER 精度・スケールの仕様
-- NUMBER(precision, scale) の仕様
-- precision: 全体の有効桁数(1〜38)
-- scale: 小数点以下の桁数(-84〜127)

-- 例: NUMBER(5, 2) → 最大 999.99(整数部3桁、小数部2桁)
--   → 1000.00 を代入しようとすると ORA-06502
--   → 999.999 は 999.99 に丸められる(スケール超過は四捨五入されエラーにならない)
--   → 1000 を代入しようとすると ORA-06502(整数部4桁で超過)
NG: NUMBER 精度を超える値を代入
DECLARE
    v_amount NUMBER(5, 2);   -- 最大 999.99
BEGIN
    v_amount := 10000;   -- 5桁の整数 → ORA-06502: number precision too large
END;
/
OK: 精度を実際のデータ範囲に合わせる、または NUMBER のみで宣言
DECLARE
    v_amount NUMBER;       -- 精度・スケール指定なし → 最大38桁、制限なし
    v_price  NUMBER(10, 2);  -- 億単位まで対応するなら余裕を持たせる
BEGIN
    v_amount := 10000;     -- OK
    v_price  := 9999999.99;  -- OK
END;
/
スケール超過はエラーにならず四捨五入される
NUMBER(5, 2) の変数に 99.999 を代入した場合、小数部3桁目が四捨五入されて 100.00 になります(エラーにはなりません)。しかし 999.99 に四捨五入した結果が精度を超える場合(999.9951000.00)はエラーになります。

パターン:文字列から数値への暗黙変換失敗

数値以外の文字列を NUMBER 型変数に代入しようとすると発生します。SQL の ORA-01722(数値が無効です)と似ていますが、こちらはPL/SQL変数への代入時に発生します。

NG: 数値変換できない文字列を NUMBER 変数に代入
DECLARE
    v_num NUMBER;
BEGIN
    v_num := 'ABC';    -- ORA-06502: character to number conversion error
    v_num := '12.3.4'; -- ORA-06502: 小数点が2つ
    v_num := '';       -- NULL として扱われる(エラーにはならない)
END;
/
OK: VALIDATE_CONVERSION(Oracle 12.2+)で事前チェック
DECLARE
    v_input  VARCHAR2(100) := '1234';
    v_num    NUMBER;
BEGIN
    -- Oracle 12.2 以降: 変換可能かチェックしてから代入
    IF VALIDATE_CONVERSION(v_input AS NUMBER) = 1 THEN
        v_num := TO_NUMBER(v_input);
        DBMS_OUTPUT.PUT_LINE('変換成功: ' || v_num);
    ELSE
        DBMS_OUTPUT.PUT_LINE('変換不可: ' || v_input);
    END IF;
END;
/
OK: TO_NUMBER の DEFAULT ON CONVERSION ERROR(Oracle 12.2+)
DECLARE
    v_input VARCHAR2(100) := 'ABC';
    v_num   NUMBER;
BEGIN
    -- 変換できない場合は指定したデフォルト値を使う
    v_num := TO_NUMBER(v_input DEFAULT 0 ON CONVERSION ERROR);
    DBMS_OUTPUT.PUT_LINE('結果: ' || v_num);  -- 結果: 0
END;
/

パターン:文字列から日付への暗黙変換失敗

DATE 型変数に文字列を代入する際、文字列の形式が NLS_DATE_FORMAT と一致しないとエラーになります。

NG: NLS_DATE_FORMAT と一致しない文字列を DATE に代入
DECLARE
    v_date DATE;
BEGIN
    -- NLS_DATE_FORMAT が 'DD-MON-RR' の環境で以下を実行すると ORA-06502
    v_date := '2025-04-01';   -- ハイフン区切りはデフォルト形式と異なる場合がある

    -- NLS_DATE_FORMAT が 'YYYY/MM/DD' でも以下はエラー
    v_date := '2025年4月1日';  -- 日本語月日表記はデフォルト変換不可
END;
/
OK: TO_DATE で書式を明示する(推奨)
DECLARE
    v_date DATE;
BEGIN
    -- 書式を明示することで NLS 設定に依存しなくなる(最も安全)
    v_date := TO_DATE('2025-04-01', 'YYYY-MM-DD');
    v_date := TO_DATE('2025年4月1日', 'YYYY"年"MM"月"DD"日"');
    DBMS_OUTPUT.PUT_LINE(TO_CHAR(v_date, 'YYYY-MM-DD'));
END;
/
OK: TO_DATE の DEFAULT ON CONVERSION ERROR(Oracle 12.2+)
DECLARE
    v_input VARCHAR2(100) := 'not-a-date';
    v_date  DATE;
BEGIN
    -- 変換失敗時にデフォルト値(SYSDATE)を使う
    v_date := TO_DATE(v_input DEFAULT SYSDATE ON CONVERSION ERROR, 'YYYY-MM-DD');
    DBMS_OUTPUT.PUT_LINE(TO_CHAR(v_date, 'YYYY-MM-DD'));
END;
/

パターン:文字セット変換によるバイト数超過

VARCHAR2(n) の n がバイト単位(デフォルト)で宣言されているとき、マルチバイト文字(日本語・中国語等)を含む文字列のバイト数が宣言長を超えると発生します。

NG: 文字単位ではなくバイト単位で溢れる例
DECLARE
    -- VARCHAR2(10) は BYTE 単位: UTF-8では日本語1文字 = 3バイト
    -- → 10バイトに入る日本語は最大3文字
    v_str VARCHAR2(10);
BEGIN
    v_str := '日本語テスト';  -- 6文字 = 18バイト → ORA-06502
END;
/
OK: CHAR セマンティクスで宣言(文字数で指定)
DECLARE
    -- VARCHAR2(10 CHAR) → 10文字(バイト数でなく文字数で制限)
    v_str VARCHAR2(10 CHAR);
BEGIN
    v_str := '日本語テスト';  -- 6文字 → OK(10文字まで許容)
    DBMS_OUTPUT.PUT_LINE(v_str);
END;
/
-- または NLS_LENGTH_SEMANTICS = CHAR に設定することでデフォルトを変えられる
-- ALTER SESSION SET NLS_LENGTH_SEMANTICS = CHAR;
VARCHAR2 の BYTE と CHAR セマンティクス比較
-- 文字セット AL32UTF8 (UTF-8)の環境での比較
-- 日本語1文字 = 最大3バイト(UTF-8)

-- BYTE セマンティクス(デフォルト)
DECLARE v_byte VARCHAR2(10);       BEGIN v_byte := '日本語テスト';  END;  -- ORA-06502(18バイト > 10)
DECLARE v_byte VARCHAR2(10);       BEGIN v_byte := '日本語';        END;  -- OK(9バイト <= 10)

-- CHAR セマンティクス
DECLARE v_char VARCHAR2(10 CHAR);  BEGIN v_char := '日本語テスト';  END;  -- OK(6文字 <= 10)
DECLARE v_char VARCHAR2(10 CHAR);  BEGIN v_char := 'ABCDEFGHIJK';  END;  -- ORA-06502(11文字 > 10)

発生箇所の特定方法:FORMAT_ERROR_BACKTRACE の活用

ORA-06502 が発生したとき、エラーメッセージだけではどの行で起きたかわかりません。DBMS_UTILITY.FORMAT_ERROR_BACKTRACE(Oracle 10g 以降)を使うことで、例外発生行の番号を取得できます。

FORMAT_ERROR_BACKTRACE で発生行を特定する
DECLARE
    v_str VARCHAR2(5);
BEGIN
    v_str := 'ABCDE';     -- 行4: OK
    v_str := 'ABCDEFGH';  -- 行5: ORA-06502 発生
EXCEPTION
    WHEN VALUE_ERROR THEN
        -- SQLERRM: エラーメッセージ
        -- FORMAT_ERROR_BACKTRACE: 例外が発生した行番号を含むスタックトレース
        DBMS_OUTPUT.PUT_LINE('エラー: ' || SQLERRM);
        DBMS_OUTPUT.PUT_LINE('発生箇所: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
        -- 出力例:
        -- エラー: ORA-06502: PL/SQL: numeric or value error: character string buffer too small
        -- 発生箇所: ORA-06512: at line 5
END;
/
例外ハンドラーで ORA-06502 をキャッチする方法
DECLARE
    v_val NUMBER;
BEGIN
    v_val := 'XYZ';  -- ORA-06502 発生
EXCEPTION
    -- ORA-06502 は PL/SQL の VALUE_ERROR として捕捉できる
    WHEN VALUE_ERROR THEN
        DBMS_OUTPUT.PUT_LINE('VALUE_ERROR をキャッチしました');
        DBMS_OUTPUT.PUT_LINE('詳細: ' || SQLERRM);
        DBMS_OUTPUT.PUT_LINE('行番号: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    WHEN OTHERS THEN
        -- 予期しないエラーはログに記録して再発生させる
        DBMS_OUTPUT.PUT_LINE('予期しないエラー: ' || SQLERRM);
        RAISE;
END;
/
バッチ処理でのエラーログパターン(実務向け)
CREATE OR REPLACE PROCEDURE process_data(p_id IN NUMBER) AS
    v_name  employees.last_name%TYPE;
    v_email VARCHAR2(200 CHAR);  -- CHAR セマンティクスで余裕を持って宣言
BEGIN
    SELECT last_name, email
    INTO v_name, v_email
    FROM employees
    WHERE employee_id = p_id;

    -- メイン処理...

EXCEPTION
    WHEN VALUE_ERROR THEN
        -- エラーログテーブルに記録(再発分析のため backtrace も保存)
        INSERT INTO error_log (log_dt, proc_name, input_id, err_code, err_msg, backtrace)
        VALUES (SYSDATE, 'PROCESS_DATA', p_id,
                SQLCODE, SQLERRM,
                DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
        COMMIT;
    WHEN OTHERS THEN
        INSERT INTO error_log (log_dt, proc_name, input_id, err_code, err_msg, backtrace)
        VALUES (SYSDATE, 'PROCESS_DATA', p_id,
                SQLCODE, SQLERRM,
                DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
        COMMIT;
        RAISE;
END;
/

ORA-06502 を予防するコーディング規則

ORA-06502 防止チェックリスト

  • 変数の長さは %TYPE で継承する:列定義が変わっても自動追従。最も効果的な予防策
  • 文字列操作の戻り値は余裕を持って宣言する:REPLACE や CONCAT の結果は入力より長くなり得る
  • マルチバイト文字を扱う変数は CHAR セマンティクスで宣言するVARCHAR2(n CHAR)
  • TO_NUMBER / TO_DATE は書式を明示する:NLS 設定に依存しない安全なコードになる
  • Oracle 12.2+ では VALIDATE_CONVERSION で事前チェックする:変換前に確認できる
  • 例外ハンドラーで VALUE_ERROR をキャッチしてログを残す:本番エラーの追跡が可能になる

まとめ

ORA-06502(PL/SQL: 数値または値のエラー)は、変数への代入時にサイズ・型・精度が合わないと発生するPL/SQLランタイムエラーです。サブコードのメッセージを正確に読むことで、原因のパターン(バッファ超過・精度超過・変換失敗)を素早く特定できます。

最も効果的な予防策は%TYPE を使った変数宣言です。また、Oracle 12.2 以降では VALIDATE_CONVERSIONDEFAULT ON CONVERSION ERROR を活用することで、変換前の安全チェックが簡潔に書けます。

例外発生時の調査には DBMS_UTILITY.FORMAT_ERROR_BACKTRACE を必ずセットで使うことで、発生行の特定が大幅に楽になります。ストアドプロシージャ・ファンクションの作成ガイドで解説している例外処理パターンと組み合わせると、本番環境でのエラー追跡が格段に改善されます。

関連するORAエラーとして、ORA-01722(数値が無効です)(SQL文での数値変換エラー)やORA-00904(無効な識別子です)も参考にしてください。