【Oracle】ORA-01438の原因と解決方法|value larger than specified precision allowed for this column・数値精度エラーの直し方

【Oracle】ORA-01438の原因と解決方法|value larger than specified precision allowed for this column・数値精度エラーの直し方 Oracle

ORA-01438: value larger than specified precision allowed for this column は、Oracleで数値列に入りきらない値を INSERT または UPDATE しようとしたときに発生するエラーです。日本語にすると「この列に指定された精度より大きい値です」という意味です。

原因はたいてい、対象列が NUMBER(5,2)NUMBER(3) のように桁数を制限しているのに、アプリ、SQL、CSV、バッチ取込から想定より大きい数値が入ってきていることです。文字列長の問題ではなく、数値の精度とスケールの問題として切り分けます。

先に結論
ORA-01438は、まず対象列の DATA_PRECISIONDATA_SCALE を確認します。NUMBER(p,s) なら、整数部に入れられる桁数は基本的に p - s 桁です。値を小さくする、取込前に検証する、または業務上必要なら ALTER TABLE ... MODIFY で列定義を広げる、の順で直します。
スポンサーリンク

ORA-01438とは

Oracle公式のエラー説明では、ORA-01438は「挿入または更新しようとした数値が、列に定義された精度を超えた」状態です。つまり、SQL文の構文が間違っているというより、値と列定義の組み合わせが合っていません。

たとえば金額列を NUMBER(5,2) と定義した場合、全体で5桁、小数点以下が2桁です。整数部に使えるのは3桁なので、999.99 は入りますが、1000.00 は入りません。このような値を登録しようとするとORA-01438になります。

確認するもの 見るポイント
列定義 NUMBER(p,s)ps NUMBER(5,2)
実データ 整数部と小数部の桁数 1234.56 は整数部4桁
発生箇所 INSERTUPDATE か、CSV取込か 画面登録、バッチ、SQL*Loader
修正方針 値を直すのか、列定義を広げるのか NUMBER(8,2) へ変更

NUMBER(p,s)の精度とスケールを確認する

ORA-01438を直すには、Oracleの NUMBER(p,s) の意味を押さえる必要があります。p は精度で、保存できる有効桁数の上限です。s はスケールで、小数点以下の桁数を表します。ざっくり見るなら、整数部に使える桁数は p - s と考えると判断しやすいです。

列定義 入りやすい値 入りにくい値 理由
NUMBER(5,2) 999.99 1000.00 整数部は3桁まで
NUMBER(3) 999 1000 全体で3桁まで
NUMBER(8,0) 99999999 100000000 整数8桁まで
NUMBER(6,3) 999.999 1000.000 整数部は3桁まで

小数点以下の桁だけに注目すると見落とします。たとえば NUMBER(5,2) に対して 1234.5 は小数1桁なので一見入りそうですが、整数部が4桁のため入りません。「小数点以下が何桁か」ではなく、「列全体の有効桁数と整数部の余裕」を見ます。

一方で、NUMBER のように精度とスケールを指定していない列では、DATA_PRECISIONDATA_SCALE がNULLになることがあります。その場合は列側の桁制限が明示されていないため、ORA-01438の主な確認対象は NUMBER(5,2) のように精度が指定された列です。

まずカラム定義を確認するSQL

エラーが出たら、推測で列を広げる前に、対象テーブルの列定義を確認します。USER_TAB_COLUMNS を見ると、自分のスキーマにある列の DATA_TYPEDATA_PRECISIONDATA_SCALE を確認できます。

check-number-column.sql
SELECT table_name,
       column_name,
       data_type,
       data_precision,
       data_scale
FROM user_tab_columns
WHERE table_name = 'SALES_WORK'
ORDER BY column_id;

別スキーマのテーブルを確認する場合は ALL_TAB_COLUMNS を使います。テーブル名やスキーマ名は大文字で登録されていることが多いので、まず大文字で検索します。

check-number-column-other-schema.sql
SELECT owner,
       table_name,
       column_name,
       data_type,
       data_precision,
       data_scale
FROM all_tab_columns
WHERE owner = 'APP_SCHEMA'
  AND table_name = 'SALES_WORK'
ORDER BY column_id;

どの列が原因かわからない場合は、対象テーブルのNUMBER列だけを先に一覧化します。古いOracle環境やアプリ経由のエラーでは、エラーメッセージに列名が出ないことがあるためです。INSERT文の列リストと値の順番を、この一覧と照らし合わせます。

list-number-columns.sql
SELECT column_id,
       column_name,
       data_type,
       data_precision,
       data_scale
FROM user_tab_columns
WHERE table_name = 'SALES_WORK'
  AND data_type = 'NUMBER'
ORDER BY column_id;

Oracleのデータディクショナリを使った確認に慣れていない場合は、OracleのINSERT/UPDATE/DELETEの基本 とあわせて、どのDMLで失敗しているかを整理すると原因を追いやすくなります。

INSERTで発生するケース

もっともわかりやすいのは、列定義より大きい値をそのまま登録しているケースです。次の例では、amountNUMBER(5,2) なので、整数部は3桁までです。

insert-ora01438.sql
CREATE TABLE sales_work (
    amount NUMBER(5,2)
);

-- OK: 5桁以内、整数部3桁以内
INSERT INTO sales_work (amount) VALUES (999.99);

-- NG: 整数部が4桁なのでORA-01438
INSERT INTO sales_work (amount) VALUES (1234.56);

この場合は、登録値が間違っているのか、列定義が狭すぎるのかを業務ルールで判断します。金額列なのに将来的に1000以上を扱うなら、値を無理に丸めるのではなく列定義を見直すほうが自然です。

UPDATEで発生するケース

UPDATEでは、計算結果が想定より大きくなってORA-01438になることがあります。元の値は問題なくても、掛け算、加算、税率計算、レート換算などの結果が列定義を超えるパターンです。

update-ora01438.sql
CREATE TABLE invoice_work (
    amount      NUMBER(8,2),
    tax_amount  NUMBER(5,2)
);

-- amount が大きい行では tax_amount が NUMBER(5,2) に収まらない可能性がある
UPDATE invoice_work
SET tax_amount = amount * 0.10;

このような場合は、更新前に異常値候補を抽出します。NUMBER(5,2) なら整数部は3桁なので、絶対値が 1000 以上になる値は入りません。

find-update-overflow.sql
SELECT amount,
       amount * 0.10 AS new_tax_amount
FROM invoice_work
WHERE ABS(amount * 0.10) >= 1000;

小数点以下ではなく整数部があふれているケース

ORA-01438では、「小数点以下を2桁に丸めれば解決する」と考えがちですが、整数部が収まらない場合は丸めても解決しません。

integer-digits-overflow.sql
-- NUMBER(5,2) は整数部3桁、小数部2桁

-- 小数部を丸めても整数部4桁なのでNG
INSERT INTO sales_work (amount) VALUES (ROUND(1234.567, 2));

-- 整数部が3桁以内ならOK
INSERT INTO sales_work (amount) VALUES (ROUND(999.994, 2));

実データを確認するときは、列定義と同じスケールに丸めた後の値だけでなく、整数部の桁数も確認します。特に外部ファイルからの取込では、想定外の単位、桁区切り、通貨換算後の値が混ざっていることがあります。

CSV・SQL*Loader取込で発生するケース

CSVや固定長ファイルの取込では、1行だけ桁の大きい値が混ざってORA-01438になることがあります。本テーブルへ直接入れると原因行を追いにくいため、まずステージングテーブルへ文字列として取り込み、検証してから本テーブルへ移す方法が安全です。

staging-before-insert.sql
CREATE TABLE sales_stg (
    amount_text VARCHAR2(50)
);

-- まず数値として解釈できない行を確認する
SELECT amount_text
FROM sales_stg
WHERE NOT REGEXP_LIKE(amount_text, '^\s*[+-]?([0-9]+(\.[0-9]+)?|\.[0-9]+)\s*$');

-- NUMBER(5,2) に入れる前に、整数部が3桁を超える候補を確認する
SELECT amount_text
FROM sales_stg
WHERE REGEXP_LIKE(amount_text, '^\s*[+-]?([0-9]+(\.[0-9]+)?|\.[0-9]+)\s*$')
  AND ABS(TO_NUMBER(TRIM(amount_text))) >= 1000;

SQL*Loaderを使っている場合は、エラー行、badファイル、ログを確認します。取込設定そのものは Oracle SQL*Loaderの使い方 にまとめています。ORA-01438では、ファイルの型変換だけでなく、受け側のNUMBER列の桁数まで確認するのがポイントです。なお、数値でない文字列まで TO_NUMBER すると別の変換エラーになるため、先に REGEXP_LIKE などで数値形式を分けておくと調査しやすくなります。

アプリから文字列や数値を渡しているケース

アプリ側では、画面入力値やAPIレスポンスをそのままDBへ渡してORA-01438になることがあります。DBエラーだけを見るとOracle側の問題に見えますが、実際には入力チェックや単位変換の漏れが原因のこともあります。

アプリ側で見る項目 確認内容
入力チェック DB列に入る上限を超えていないか 999.99までの列に1000以上を許可していないか
単位 円、千円、%、倍率などを取り違えていないか 1000円を1,000,000として渡していないか
型変換 文字列を数値化した後の値をログに出しているか '001234.56'1234.56 になる
丸め処理 丸め・切り捨て後の値が列定義に収まるか ROUND 後も整数部が超過していないか

バインド変数で値を渡している場合でも、列に入らない値ならORA-01438になります。バインド変数の基本は Oracleのバインド変数の使い方、動的SQL側の組み立ては EXECUTE IMMEDIATEの使い方 も参考になります。

ROUNDやTRUNCで丸める場合の注意点

小数点以下だけが問題なら、ROUNDTRUNC で桁数を合わせる方法があります。ただし、業務上の金額や数量を勝手に丸めると、請求額、在庫数、集計値が変わります。丸めてよい項目か、丸めルールは四捨五入か切り捨てかを確認してから使います。

round-trunc-before-insert.sql
-- 小数点以下2桁に丸める
INSERT INTO sales_work (amount)
VALUES (ROUND(:amount, 2));

-- 小数点以下2桁で切り捨てる
INSERT INTO sales_work (amount)
VALUES (TRUNC(:amount, 2));

なお、ROUND(1234.567, 2)1234.57 なので、NUMBER(5,2) には入りません。丸めは小数部の調整であり、整数部の桁あふれを消す処理ではない点に注意します。

カラム定義を広げる場合

値が業務上正しいなら、列定義のほうを広げます。たとえば、NUMBER(5,2) では足りない金額列を NUMBER(8,2) に変更すると、整数部は6桁まで扱えるようになります。

alter-number-precision.sql
ALTER TABLE sales_work
MODIFY (amount NUMBER(8,2));

ただし、列定義を広げる前に、画面表示、帳票、連携先、チェック制約、アプリ側の型や桁数制限も確認します。DBだけ広げても、アプリや連携先が古い桁数のままだと別の場所でエラーになります。

ORA-12899やORA-06502との違い

ORA-01438と似た場面で出るエラーに、ORA-12899やORA-06502があります。切り分けるときは、文字列の長さなのか、数値の精度なのか、PL/SQL変数のサイズなのかを分けて考えます。

エラー 主な原因 見る場所
ORA-01438 NUMBER列の精度超過 DATA_PRECISIONDATA_SCALE
ORA-12899 文字列列の長さ超過 VARCHAR2CHARDATA_LENGTH
ORA-06502 PL/SQLの数値・文字列・変換エラー PL/SQL変数の桁数、型変換、代入先

文字列長のエラーなら ORA-12899の原因と解決方法、PL/SQL変数や型変換の問題なら ORA-06502の原因と解決方法 を確認してください。SQL文の構文自体が怪しい場合は、ORA-00933ORA-00936 の観点もあわせて見ます。

修正チェックリスト

手順 確認すること 判断
1 エラーが出たテーブル・列を特定する ログ、SQL、取込エラー行を見る
2 USER_TAB_COLUMNS で列定義を確認する DATA_PRECISIONDATA_SCALE を見る
3 登録・更新しようとした値を確認する 整数部と小数部の桁数を見る
4 値が間違いか、列定義が狭いかを判断する 業務上の上限と照合する
5 入力チェックや取込前検証を追加する 同じエラーを再発させない
6 必要なら列定義を広げる 画面・帳票・連携先も確認する

よくある質問

NUMBER(5,2)には何桁まで入りますか?

全体で5桁、小数点以下が2桁です。整数部は3桁までなので、正の値なら 999.99 までが目安です。1000.00 は整数部4桁のため入りません。

小数点以下を丸めればORA-01438は解決しますか?

小数部だけが原因なら解決することがあります。ただし、整数部が列定義を超えている場合は、ROUNDTRUNC を使っても解決しません。

どの列が原因かわからない場合はどうしますか?

まず実行SQLと投入値をログで確認し、対象テーブルのNUMBER列を USER_TAB_COLUMNS で一覧化します。複数列へINSERTしている場合は、列リストを明示して、値との対応を見直します。列リストなしの INSERT INTO table VALUES (...) は原因列を追いにくいため、保守性の面でも避けるのがおすすめです。

列を広げても問題ありませんか?

業務上その値が正しいなら有力な修正です。ただし、アプリ、帳票、連携先、チェック制約、インデックス、テストデータも影響を受けるため、DB列だけで判断しないようにします。

CSV取込で1行だけ失敗する場合はどう見ればよいですか?

badファイルやログで失敗行を確認し、対象列の値を見ます。一度ステージングテーブルへ文字列で取り込んでから、NUMBER列に入るか検証すると原因行を特定しやすくなります。

まとめ

ORA-01438は、OracleのNUMBER列に定義された精度を超える数値を登録・更新しようとしたときに発生します。まず USER_TAB_COLUMNSDATA_PRECISIONDATA_SCALE を確認し、実際に入れようとしている値の整数部と小数部を照合します。

値が誤っているなら入力値や取込データを修正し、値が正しいなら列定義を広げます。丸め処理は便利ですが、業務値を変える処理なので慎重に使います。特にCSV取込やバッチ処理では、ステージングテーブルで検証してから本テーブルへ入れる構成にすると再発を防ぎやすくなります。

参考

ORA-01438 – Oracle Database Error Help

Data Types – Oracle SQL Language Reference