【完全ガイド】ORA-01722: invalid number の原因と解決方法|TO_NUMBER・暗黙型変換・NLS 徹底解説
- 作成日 2026.07.31
- Oracle Database
Oracle 開発者・データエンジニアが最も頻繁に遭遇する型変換エラー:
SELECT TO_NUMBER('abc') FROM DUAL;
-- ORA-01722: invalid number
SELECT * FROM orders WHERE order_number = '123-456';
-- ORA-01722(暗黙変換で失敗)
「数値に変換できない」というシンプルなメッセージ。しかし、実際には変換エラー・型不一致・暗黙変換の多岐にわたる原因があり、多くのケースでハマります:
TO_NUMBERで明示的に変換して失敗- VARCHAR2 と NUMBER の暗黙比較(WHERE 句)
- スペースや制御文字を含む値
- 通貨記号(
$,¥,€) - カンマ区切り(
1,000,000) - NLS の小数点(欧州の
,) - CSV / ETL データの汚れ
- 予約語(
UID,LEVEL)が原因 - 連結演算子(
||)で数値と文字列混在 - CASE / DECODE 内での型不一致
さらに、多くの日本語記事が「文字列を数値に変換できないだけ」で終わりますが、実務では:
- どの行が違反しているかの特定
- Oracle 12c+ の
DEFAULT ... ON CONVERSION ERROR活用 VALIDATE_CONVERSION関数(12c+)REGEXP_LIKEでのフィルタ- NLS_NUMERIC_CHARACTERS の影響
ERROR_MESSAGE_DETAILS=ON(21c+ で問題値を表示)is_numberユーザー関数の作成- Rails / Java / Python からの防御的コーディング
さらに、本当に厄介なパターンがあります:
-- 一見動くが、実は危険
CREATE TABLE t (id VARCHAR2(10));
INSERT INTO t VALUES ('123');
INSERT INTO t VALUES ('456');
INSERT INTO t VALUES ('abc'); -- ここに非数値
-- 開発時は動く
SELECT * FROM t WHERE id = 123;
-- 本番で ORA-01722('abc' の変換失敗)
「WHERE 句での暗黙変換」 は Oracle の中でも特に予測困難なエラー源です。データが増えるにつれ、いつか必ず発生します。
本記事では、ORA-01722: invalid number の完全な原因と解決方法を、リファレンスとして実用的に整理します。有効な数値リテラル、10大発生パターン、5つの診断方法、5つの解決策、Oracle 12c+ の新機能、NLS の影響、Rails/Java/Python 対応、実践シナリオ、FAQまで完全網羅。この1本で ORA-01722 を根本から解決できるようになります。
- 1. 結論:文字列が数値に変換できない
- 2. まず理解する:有効な数値リテラル
- 3. 【原因①】TO_NUMBER で非数値文字列(最頻出)
- 4. 【原因②】WHERE 句での暗黙変換(超危険)
- 5. 【原因③】通貨記号・カンマ
- 6. 【原因④】スペース・制御文字
- 7. 【原因⑤】CSV / ETL データ
- 8. 【原因⑥】予約語による誤変換
- 9. 【原因⑦】INSERT で数値列に文字列
- 10. 【原因⑧】CASE / DECODE 内の型不一致
- 11. 【原因⑨】連結演算子(||)
- 12. 【原因⑩】NLS 依存の小数点
- 13. 診断ツール完全リファレンス
- 14. Rails / Java / Python 対応
- 15. 実践シナリオ
- 16. トラブルシューティング
- 17. よくある質問(FAQ)
- 17.1. Q1. ORA-01722 と ORA-06502 の違い
- 17.2. Q2. DEFAULT ON CONVERSION ERROR が使えるバージョン
- 17.3. Q3. VALIDATE_CONVERSION のバージョン
- 17.4. Q4. NULL は数値変換で問題ないか
- 17.5. Q5. 空文字 ”
- 17.6. Q6. 千位区切り
- 17.7. Q7. 前後スペース
- 17.8. Q8. Rails での対応
- 17.9. Q9. Autonomous DB での挙動
- 17.10. Q10. エラー詳細を常に見たい
- 17.11. Q11. パフォーマンスへの影響
- 17.12. Q12. PostgreSQL からの移行
- 18. 参考リンク
- 19. まとめ
結論:文字列が数値に変換できない
時間がない方向けに、最速の対処を先に示します。
エラーメッセージの読み方
ORA-01722: invalid number
-- Oracle 21c+ で ERROR_MESSAGE_DETAILS=ON なら
ORA-01722: unable to convert string value containing 'S' to a number: ENAME
ORA-03302: (ORA-01722 details) invalid string value: SMITH
問題の値と列名が明示される(21c+)。
最速の診断
-- ① 詳細エラー有効化(Oracle 21c+)
ALTER SESSION SET ERROR_MESSAGE_DETAILS = ON;
-- ② 変換可能性チェック(Oracle 12c+)
SELECT column_name, VALIDATE_CONVERSION(column_name AS NUMBER)
FROM my_table;
-- 1 = 変換可能, 0 = 不可
-- ③ 非数値データ検出
SELECT * FROM my_table
WHERE NOT REGEXP_LIKE(column_name, '^-?[0-9]+(\.[0-9]+)?$');
5つの解決策
| # | 手法 | 使う場面 |
|---|---|---|
| ① | DEFAULT ON CONVERSION ERROR (12c+) | エラー時デフォルト値 |
| ② | VALIDATE_CONVERSION (12c+) | 事前チェック |
| ③ | REGEXP_LIKE フィルタ | データ絞り込み |
| ④ | CASE 式で判定 | 混在データ |
| ⑤ | TRIM / REPLACE | 前処理 |
有効な数値リテラル
✅ OK
123, -456, +789
1.5, -3.14, .5
1e10, 1.5E-3 (指数表記)
❌ NG
'123abc' (非数値文字)
'1,000' (カンマ)
'$100' (通貨記号)
' 123 ' (前後スペース、実は TRIM されれば OK)
'1.5.6' (複数の小数点)
'12-34' (ハイフン中央)
詳細は以下で解説します。
まず理解する:有効な数値リテラル
Oracle の数値変換ルール
含めて良いもの:
- 数字 (0-9)
- 符号 (+/-)
- 小数点 (
.) ※ NLS 依存 - 指数表記 (
e,E)
含めてはいけないもの:
- 数字以外の文字(a, b, c…)
- 通貨記号 ($, ¥, €)
- 千位区切り(デフォルトでは カンマ不可)
- 特殊文字(-, /, スペース等)※ 位置による
変換例
SELECT TO_NUMBER('123') FROM DUAL; -- 123
SELECT TO_NUMBER('-456') FROM DUAL; -- -456
SELECT TO_NUMBER('1.5') FROM DUAL; -- 1.5
SELECT TO_NUMBER('1e10') FROM DUAL; -- 10000000000
-- 全て ORA-01722
SELECT TO_NUMBER('abc') FROM DUAL;
SELECT TO_NUMBER('1,000') FROM DUAL;
SELECT TO_NUMBER('$100') FROM DUAL;
SELECT TO_NUMBER('123abc') FROM DUAL;
前後スペースは自動除去
SELECT TO_NUMBER(' 123 ') FROM DUAL; -- OK: 123(自動 TRIM)
-- しかし文字列中のスペースは NG
SELECT TO_NUMBER('1 23') FROM DUAL; -- ORA-01722
NLS の影響
欧州ロケールでは小数点がカンマ:
-- ドイツ語ロケールで
ALTER SESSION SET NLS_NUMERIC_CHARACTERS = ',.';
SELECT TO_NUMBER('1,5') FROM DUAL; -- OK: 1.5
-- 日本/US ロケール
ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,';
SELECT TO_NUMBER('1,5') FROM DUAL; -- ORA-01722
NLS 依存はバグの温床。フォーマットモデル明示推奨。
【原因①】TO_NUMBER で非数値文字列(最頻出)
症状
SELECT TO_NUMBER('abc') FROM DUAL;
-- ORA-01722
診断
-- 21c+ の詳細エラー
ALTER SESSION SET ERROR_MESSAGE_DETAILS = ON;
SELECT TO_NUMBER('abc') FROM DUAL;
-- ORA-01722: unable to convert string value containing 'a' to a number
解決A: DEFAULT ON CONVERSION ERROR(12c+)
-- 変換失敗時にデフォルト値
SELECT TO_NUMBER('abc' DEFAULT 0 ON CONVERSION ERROR) FROM DUAL;
-- 結果: 0(エラーなし)
-- 大量データで一括処理
SELECT id,
TO_NUMBER(amount_str DEFAULT -1 ON CONVERSION ERROR) AS amount
FROM orders;
Oracle 12.2+ で神機能。エラー処理が SQL 内で完結。
解決B: VALIDATE_CONVERSION(12c+)
-- 事前チェック
SELECT id, amount_str,
CASE VALIDATE_CONVERSION(amount_str AS NUMBER)
WHEN 1 THEN TO_NUMBER(amount_str)
ELSE NULL
END AS amount
FROM orders;
1 = 変換可能, 0 = 変換不可。
解決C: REGEXP_LIKE でフィルタ
SELECT TO_NUMBER(amount_str)
FROM orders
WHERE REGEXP_LIKE(amount_str, '^-?[0-9]+(\.[0-9]+)?$');
-- 数値パターンにマッチするもののみ
【原因②】WHERE 句での暗黙変換(超危険)
症状
-- id は VARCHAR2 列
CREATE TABLE t (id VARCHAR2(10));
INSERT INTO t VALUES ('123');
INSERT INTO t VALUES ('456');
INSERT INTO t VALUES ('abc'); -- 非数値混在
SELECT * FROM t WHERE id = 123;
-- ORA-01722('abc' の変換失敗)
なぜ危険か
- 開発時: データが少なく成功
- 本番: データ増加で発生
- オプティマイザ: 実行順序で発生タイミングが変わる
診断
-- 非数値行の特定
SELECT * FROM t
WHERE NOT REGEXP_LIKE(id, '^-?[0-9]+(\.[0-9]+)?$');
解決A: 文字列側で比較
-- 数値を文字列化
SELECT * FROM t WHERE id = '123';
-- OK: 完全一致検索
-- または TO_CHAR
SELECT * FROM t WHERE id = TO_CHAR(123);
解決B: 数値列側で比較
-- t.id を数値化(ただし非数値行があれば ORA-01722)
SELECT * FROM t WHERE TO_NUMBER(id) = 123;
-- 対処: WHERE 句に事前フィルタ
解決C: 事前フィルタ
SELECT * FROM t
WHERE REGEXP_LIKE(id, '^-?[0-9]+(\.[0-9]+)?$')
AND TO_NUMBER(id) = 123;
サブクエリの評価順に注意(オプティマイザが並び変える可能性)。
解決D: DEFAULT ON CONVERSION ERROR
SELECT * FROM t
WHERE TO_NUMBER(id DEFAULT NULL ON CONVERSION ERROR) = 123;
-- 変換失敗は NULL、比較で FALSE
【原因③】通貨記号・カンマ
症状
SELECT TO_NUMBER('$1,000.50') FROM DUAL;
-- ORA-01722
解決A: FORMAT MODEL 指定
SELECT TO_NUMBER('$1,000.50', '$999,999.99') FROM DUAL;
-- OK: 1000.5
解決B: REPLACE で除去
SELECT TO_NUMBER(REPLACE(REPLACE('$1,000.50', '$'), ',')) FROM DUAL;
-- OK: 1000.5
FORMAT モデル完全リファレンス
-- 千位区切り
TO_NUMBER('1,000,000', '999,999,999')
-- 通貨記号(ロケール依存)
TO_NUMBER('$1000', 'L999999') -- L = ロケール通貨
TO_NUMBER('$1000', '$999999') -- $ 固定
-- 前ゼロ
TO_NUMBER('00123', '000000') -- 123
-- 小数点(NLS)
TO_NUMBER('1,5', '9D9', 'NLS_NUMERIC_CHARACTERS = '',.''')
-- パーセント
TO_NUMBER('50%', '99%') -- 不可、REPLACE で除去
【原因④】スペース・制御文字
症状
-- 前後スペースは自動 TRIM されるが、中央は NG
SELECT TO_NUMBER('1 2 3') FROM DUAL; -- ORA-01722
-- タブや制御文字
SELECT TO_NUMBER('123' || CHR(9)) FROM DUAL; -- ORA-01722(タブ含む)
診断
-- 非印字文字の検出
SELECT id, DUMP(id) FROM t WHERE NOT REGEXP_LIKE(id, '^-?[0-9]+$');
-- DUMP で ASCII コード確認
解決
-- 全空白除去
SELECT TO_NUMBER(REGEXP_REPLACE('1 2 3', '\s')) FROM DUAL;
-- 123
-- ASCII 制御文字除去
SELECT TO_NUMBER(REGEXP_REPLACE(id, '[[:cntrl:]]')) FROM t;
【原因⑤】CSV / ETL データ
症状(現実的なケース)
CSV:
id,name,amount
1,John,1000
2,Mary,2000
3,Bob,N/A ← 非数値
4,Alice, ← 空文字(実は OK になる)
5,Tom,$500 ← 通貨記号
解決:全部を耐性のある処理に
-- ステージングテーブル
CREATE TABLE staging (id VARCHAR2(10), name VARCHAR2(50), amount VARCHAR2(20));
-- クリーニング付き移行
INSERT INTO final_orders (id, name, amount)
SELECT
TO_NUMBER(id DEFAULT NULL ON CONVERSION ERROR),
name,
TO_NUMBER(
REPLACE(REPLACE(amount, '$'), ',')
DEFAULT NULL ON CONVERSION ERROR
)
FROM staging;
エラー行のログ
-- エラー行を別テーブルへ
INSERT INTO staging_errors
SELECT * FROM staging
WHERE VALIDATE_CONVERSION(
REPLACE(REPLACE(amount, '$'), ',') AS NUMBER
) = 0
AND amount IS NOT NULL;
Data Pump の詳細は Oracle Data Pump 使い方の記事も参照してください。
【原因⑥】予約語による誤変換
症状(罠)
CREATE TABLE t (uid VARCHAR2(50));
INSERT INTO t VALUES ('abc123');
SELECT * FROM t WHERE uid = '4a29d12025012995c231f18eb7704009';
-- ORA-01722
原因
UID は Oracle の予約疑似列(現在のユーザーIDを返す NUMBER):
SELECT UID FROM DUAL; -- 数値(例: 84)
Oracle が uid を疑似列と解釈 → NUMBER と比較 → 文字列 '4a29...' を数値化しようとして失敗。
解決
A. 列名を変更:
ALTER TABLE t RENAME COLUMN uid TO user_uid;
B. テーブルエイリアスで修飾:
SELECT * FROM t x WHERE x.uid = '4a29...';
-- x. で明示的に列参照
C. 引用符:
SELECT * FROM t WHERE "uid" = '4a29...';
予約語関連は ORA-00904: invalid identifier の記事も参照してください。
【原因⑦】INSERT で数値列に文字列
症状
CREATE TABLE t (id NUMBER, amount NUMBER(10, 2));
INSERT INTO t VALUES (1, 'abc');
-- ORA-01722
解決
A. 数値を渡す:
INSERT INTO t VALUES (1, 1000.50);
B. アプリ側で事前バリデーション:
# Rails
validates :amount, numericality: true
【原因⑧】CASE / DECODE 内の型不一致
症状
SELECT CASE
WHEN status = 'A' THEN 100
WHEN status = 'B' THEN 200
ELSE 'N/A' -- ← 型不一致
END
FROM orders;
-- ORA-01722(オプティマイザが数値へ暗黙変換)
解決
戻り値の型を統一:
SELECT CASE
WHEN status = 'A' THEN '100' -- 全て文字列
WHEN status = 'B' THEN '200'
ELSE 'N/A'
END
FROM orders;
または全て数値 + NULL:
SELECT CASE
WHEN status = 'A' THEN 100
WHEN status = 'B' THEN 200
ELSE NULL
END
FROM orders;
【原因⑨】連結演算子(||)
症状
-- 意図しない暗黙変換
SELECT '合計: ' || total FROM orders;
-- 通常は OK
-- しかし WHERE で
SELECT * FROM orders WHERE 'ID_' || id = 'ID_123';
-- id が NUMBER なら OK
-- id が VARCHAR2 で非数値混在 → 危険なパターン
解決
明示的な型変換:
SELECT * FROM orders WHERE 'ID_' || TO_CHAR(id) = 'ID_123';
【原因⑩】NLS 依存の小数点
症状
-- ドイツ語ロケール(1,5 = 1.5)
ALTER SESSION SET NLS_NUMERIC_CHARACTERS = ',.';
SELECT TO_NUMBER('1.5') FROM DUAL;
-- ORA-01722(. が千位区切り扱い、整数化失敗)
解決A: NLS 明示
SELECT TO_NUMBER('1.5', '9D9', 'NLS_NUMERIC_CHARACTERS = ''.,'''')
FROM DUAL;
解決B: セッションで統一
ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,';
解決C: NLS 非依存に
-- REPLACE で正規化
SELECT TO_NUMBER(REPLACE('1,5', ',', '.')) FROM DUAL;
診断ツール完全リファレンス
VALIDATE_CONVERSION(Oracle 12c+)
-- 変換可能性チェック
SELECT amount_str,
VALIDATE_CONVERSION(amount_str AS NUMBER) AS is_valid
FROM orders;
-- 1 = 変換可能
-- 0 = 変換不可
-- 非数値行の抽出
SELECT * FROM orders
WHERE VALIDATE_CONVERSION(amount_str AS NUMBER) = 0;
DEFAULT ON CONVERSION ERROR(Oracle 12.2+)
-- 変換失敗時のデフォルト値
SELECT TO_NUMBER('abc' DEFAULT 0 ON CONVERSION ERROR) FROM DUAL; -- 0
SELECT TO_NUMBER('abc' DEFAULT NULL ON CONVERSION ERROR) FROM DUAL; -- NULL
REGEXP_LIKE
-- 標準的な数値パターン
REGEXP_LIKE(col, '^-?[0-9]+(\.[0-9]+)?$')
-- 指数表記も許容
REGEXP_LIKE(col, '^-?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$')
-- 千位区切り許容
REGEXP_LIKE(col, '^-?[0-9]{1,3}(,[0-9]{3})*(\.[0-9]+)?$')
is_number ユーザー関数
CREATE OR REPLACE FUNCTION is_number(p_str VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC
IS
v_num NUMBER;
BEGIN
v_num := TO_NUMBER(p_str);
RETURN 'Y';
EXCEPTION
WHEN VALUE_ERROR THEN RETURN 'N';
WHEN INVALID_NUMBER THEN RETURN 'N';
END;
/
-- 使用
SELECT id, amount_str, is_number(amount_str) AS valid
FROM orders;
ERROR_MESSAGE_DETAILS(Oracle 21c+)
ALTER SESSION SET ERROR_MESSAGE_DETAILS = ON;
SELECT TO_NUMBER(name) FROM emp;
-- ORA-01722: unable to convert string value containing 'S' to a number: NAME
-- ORA-03302: (ORA-01722 details) invalid string value: SMITH
問題の値と列名が特定できる。
DUMP 関数(非印字文字検出)
SELECT id, DUMP(id, 1010) FROM t
WHERE VALIDATE_CONVERSION(id AS NUMBER) = 0;
-- DUMP で ASCII コード表示
-- 制御文字(\t \n 等)検出
Rails / Java / Python 対応
Rails ActiveRecord
モデル側のバリデーション(第一防衛線):
class Order < ApplicationRecord
validates :amount, numericality: true
validates :amount, presence: true
# カスタム
validate :amount_is_reasonable
private
def amount_is_reasonable
return unless amount.present?
errors.add(:amount, "too large") if amount > 10_000_000
end
end
エラーハンドリング:
begin
Order.where("amount > 100").to_a
rescue ActiveRecord::StatementInvalid => e
if e.message.include?("ORA-01722")
Rails.logger.error "型変換失敗: #{e.message}"
end
end
型キャスト:
# 明示的な型変換
amount = params[:amount].to_i # Integer に
amount = params[:amount].to_d # BigDecimal に
# 検証してからクエリ
if params[:id].to_s.match?(/^\d+$/)
Order.find(params[:id])
end
Rails 8 系の詳細は Rails 8 アップグレードガイドの記事、find/find_by/where の記事も参照してください。
Java (JDBC)
// 事前バリデーション
public boolean isValidNumber(String s) {
if (s == null) return false;
try {
new BigDecimal(s.trim());
return true;
} catch (NumberFormatException e) {
return false;
}
}
// クエリ実行
try {
stmt.executeQuery("SELECT * FROM t WHERE id = 123");
} catch (SQLException e) {
if (e.getErrorCode() == 1722) {
logger.error("数値変換失敗: " + e.getMessage());
// 対処
}
}
Python (oracledb)
import oracledb
def is_number(s):
try:
float(s)
return True
except (ValueError, TypeError):
return False
try:
cursor.execute("SELECT * FROM t WHERE id = :1", (123,))
except oracledb.DatabaseError as e:
error_obj, = e.args
if error_obj.code == 1722:
print(f"数値変換失敗: {error_obj.message}")
実践シナリオ
シナリオ1:本番で突然発生する ORA-01722
-- 症状: 開発では動く、本番で ORA-01722
-- 原因: データ増加で非数値が混入
-- 診断
ALTER SESSION SET ERROR_MESSAGE_DETAILS = ON;
SELECT * FROM orders WHERE order_number = 12345;
-- ORA-01722: unable to convert 'ABC-001' to number: ORDER_NUMBER
-- 対処
SELECT * FROM orders
WHERE order_number = '12345'; -- 文字列で比較
-- 恒久対策
UPDATE orders SET order_number = '0'
WHERE VALIDATE_CONVERSION(order_number AS NUMBER) = 0;
シナリオ2:CSV データ移行
-- ステージング
CREATE TABLE staging_orders (
id VARCHAR2(20),
amount_str VARCHAR2(50)
);
-- 移行 with クレンジング
INSERT INTO orders (id, amount)
SELECT
TO_NUMBER(id DEFAULT NULL ON CONVERSION ERROR),
TO_NUMBER(
REPLACE(REPLACE(TRIM(amount_str), '$'), ',')
DEFAULT NULL ON CONVERSION ERROR
)
FROM staging_orders
WHERE TO_NUMBER(id DEFAULT NULL ON CONVERSION ERROR) IS NOT NULL;
-- エラー行を別ログ
INSERT INTO staging_errors
SELECT * FROM staging_orders
WHERE VALIDATE_CONVERSION(id AS NUMBER) = 0;
シナリオ3:レポート集計での対応
-- 平均金額(非数値行は除外)
SELECT AVG(TO_NUMBER(amount DEFAULT NULL ON CONVERSION ERROR))
FROM orders;
-- 分析関数と組み合わせ
SELECT id, amount,
AVG(TO_NUMBER(amount DEFAULT NULL ON CONVERSION ERROR))
OVER (PARTITION BY category) AS category_avg
FROM orders;
分析関数の詳細は Oracle 分析関数(OVER/PARTITION BY)の記事も参照してください。
シナリオ4:Rails でのバリデーション設計
class Order < ApplicationRecord
# 数値バリデーション
validates :amount,
numericality: { greater_than_or_equal_to: 0 },
presence: true
# 数値以外の文字を許可しない
before_save :sanitize_amount
private
def sanitize_amount
self.amount = amount.to_s.gsub(/[^\d.-]/, '').to_d
end
end
Solid Queue の詳細は Solid Queue 使い方の記事も参照してください。
シナリオ5:MERGE でのクレンジング
MERGE INTO final_orders dst
USING (
SELECT
TO_NUMBER(id DEFAULT NULL ON CONVERSION ERROR) AS id,
TO_NUMBER(amount DEFAULT NULL ON CONVERSION ERROR) AS amount,
name
FROM staging
WHERE VALIDATE_CONVERSION(id AS NUMBER) = 1
) src
ON (dst.id = src.id)
WHEN MATCHED THEN UPDATE SET dst.amount = src.amount
WHEN NOT MATCHED THEN INSERT VALUES (src.id, src.amount, src.name);
MERGE の詳細は Oracle MERGE 文 使い方の記事も参照してください。
シナリオ6:予約語との衝突回避
-- ORA-01722 の隠れた原因: 列名 UID
-- 対処: 列名変更
ALTER TABLE user_ids RENAME COLUMN uid TO user_identifier;
-- または引用符(非推奨)
SELECT "uid" FROM user_ids;
シナリオ7:NLS を無視した堅牢なコード
-- NLS 依存を避ける
CREATE OR REPLACE FUNCTION safe_to_number(p_str VARCHAR2)
RETURN NUMBER DETERMINISTIC
IS
BEGIN
RETURN TO_NUMBER(
REPLACE(REPLACE(TRIM(p_str), ',', ''), ' ', '')
DEFAULT NULL ON CONVERSION ERROR
);
END;
/
シナリオ8:Docker Oracle でのテスト
docker exec -it oracle-xe sqlplus scott/tiger <<EOF
ALTER SESSION SET ERROR_MESSAGE_DETAILS = ON;
SELECT TO_NUMBER('abc') FROM DUAL;
-- 詳細なエラーメッセージ
EOF
Docker 関連は docker daemon 接続エラーの記事、Docker no space left on device の記事も参照してください。
シナリオ9:AWS RDS Oracle での対処
-- Parameter Group で ERROR_MESSAGE_DETAILS 設定
ALTER SYSTEM SET error_message_details = 'ON' SCOPE = BOTH;
パラメータ関連は Oracle パラメータ確認(V$PARAMETER)の記事も参照してください。
シナリオ10:Kamal デプロイ後の型検証
docker exec -it db-container sqlplus / as sysdba <<EOF
-- 全 VARCHAR2 列で非数値だけをチェック
SELECT column_name FROM user_tab_columns
WHERE table_name = 'ORDERS' AND data_type = 'VARCHAR2';
EOF
Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事を参照してください。
トラブルシューティング
エラーが特定できない
21c+ の詳細エラー有効化:
ALTER SESSION SET ERROR_MESSAGE_DETAILS = ON;
VALIDATE_CONVERSION が使えない
12c 未満: is_number ユーザー関数を作成。
DEFAULT ON CONVERSION ERROR が使えない
12.2 未満: CASE VALIDATE_CONVERSION or ユーザー関数。
実行計画で意図しない変換
EXPLAIN PLAN FOR SELECT * FROM t WHERE id = 123;
-- INTERNAL_FUNCTION(id) = 123 が表示されたら暗黙変換
EXPLAIN PLAN は Oracle EXPLAIN PLAN 見方の記事も参照してください。
インデックス無効化
暗黙変換で関数索引となり、通常のインデックス無効化:
-- 索引が使われない
WHERE varchar_col = 123
-- 関数ベース索引で対応
CREATE INDEX idx ON t(TO_NUMBER(varchar_col));
21c の UNISTR エラー
ORA-01722: unable to convert string value containing UNISTR(...)
キャラセット互換性なし。DB キャラセットを確認。
よくある質問(FAQ)
Q1. ORA-01722 と ORA-06502 の違い
- ORA-01722: SQL レベルの数値変換失敗
- ORA-06502: PL/SQL レベルの数値変換失敗
Q2. DEFAULT ON CONVERSION ERROR が使えるバージョン
Oracle 12.2+。
Q3. VALIDATE_CONVERSION のバージョン
Oracle 12.1+。
Q4. NULL は数値変換で問題ないか
問題なし。NULL のまま。
Q5. 空文字 ”
NULL 扱い(Oracle の空文字は NULL)。
Q6. 千位区切り
FORMAT モデルか REPLACE で除去。
Q7. 前後スペース
自動 TRIM。中央のスペースは NG。
Q8. Rails での対応
validates :col, numericality: true で事前検証。
Q9. Autonomous DB での挙動
同じ。ERROR_MESSAGE_DETAILS デフォルト ON。
Q10. エラー詳細を常に見たい
ALTER SYSTEM SET error_message_details = 'ON';
Q11. パフォーマンスへの影響
VALIDATE_CONVERSION は各行評価、大量データで注意。
Q12. PostgreSQL からの移行
PG の CAST(... AS NUMERIC) は失敗時例外、Oracle と類似。
参考リンク
Oracle 公式
- Oracle Database Error Messages: ORA-01722
- Oracle Database SQL Language Reference: TO_NUMBER
- Oracle Database SQL Language Reference: VALIDATE_CONVERSION
- DEFAULT … ON CONVERSION ERROR
まとめ
ORA-01722: invalid number の要点を再整理します。
エラーの本質
文字列を数値に変換しようとして失敗
→ 明示的変換 (TO_NUMBER) or 暗黙変換 (WHERE 句)
→ 非数値文字が含まれる
エラーメッセージ(21c+)
ORA-01722: unable to convert string value containing 'S'
to a number: COLUMN_NAME
ORA-03302: (ORA-01722 details) invalid string value: STRING_VALUE
ERROR_MESSAGE_DETAILS = ON で詳細取得。
有効な数値リテラル
✅ 123, -456, 1.5, 1e10
❌ 'abc', '1,000', '$100', '1 2 3'
前後スペース: 自動 TRIM で OK
中央スペース: NG
10大原因
| # | 原因 | 対処 |
|---|---|---|
| ① | TO_NUMBER 非数値 | DEFAULT ON CONVERSION ERROR |
| ② | WHERE 暗黙変換 | 明示的型 |
| ③ | 通貨/カンマ | FORMAT モデル/REPLACE |
| ④ | スペース/制御文字 | REGEXP_REPLACE |
| ⑤ | CSV/ETL | クレンジング |
| ⑥ | 予約語 (UID) | 列名変更 |
| ⑦ | INSERT 文字列 | 事前検証 |
| ⑧ | CASE 型不一致 | 統一 |
| ⑨ | 連結演算子 | TO_CHAR |
| ⑩ | NLS 依存 | 明示指定 |
5つの解決策
-- ① DEFAULT ON CONVERSION ERROR (12.2+)
SELECT TO_NUMBER(x DEFAULT 0 ON CONVERSION ERROR) FROM t;
-- ② VALIDATE_CONVERSION (12.1+)
WHERE VALIDATE_CONVERSION(x AS NUMBER) = 1
-- ③ REGEXP_LIKE フィルタ
WHERE REGEXP_LIKE(x, '^-?[0-9]+(\.[0-9]+)?$')
-- ④ CASE 判定
CASE VALIDATE_CONVERSION(x AS NUMBER)
WHEN 1 THEN TO_NUMBER(x)
ELSE NULL
END
-- ⑤ TRIM / REPLACE
TO_NUMBER(REPLACE(REPLACE(x, '$'), ','))
診断コマンド Top 3
-- ① 詳細エラー (21c+)
ALTER SESSION SET ERROR_MESSAGE_DETAILS = ON;
-- ② 変換可能性
SELECT VALIDATE_CONVERSION(x AS NUMBER) FROM t;
-- ③ 非数値検出
SELECT * FROM t
WHERE NOT REGEXP_LIKE(x, '^-?[0-9]+(\.[0-9]+)?$');
日付エラー3部作との対比
ORA-01722: 数値変換失敗
ORA-01843: 月が無効
ORA-01830: 日付フォーマット早期終了
ORA-01858: 数値文字が期待される
型変換系の姉妹エラー。
暗黙変換の危険性
-- ❌ データ増加で必ず問題
SELECT * FROM t WHERE varchar_col = 123;
-- ✅ 明示的比較
SELECT * FROM t WHERE varchar_col = '123';
これらの知識は、Oracle でのアプリ開発・データ移行・ETL・API 開発・レポート・Rails / Java / Python 開発・データクレンジング・本番トラブル対応など、あらゆる場面で活用できます。本記事をブックマークしておけば、ORA-01722 に出会っても冷静に的確に対処できるようになります。
本記事は2026年6月時点の情報をもとに、Oracle Database 19c〜23ai での動作確認・公式ドキュメントに基づき作成しています。Oracle のバージョンにより挙動が異なる場合があるため、最新の情報は Oracle 公式ドキュメント(docs.oracle.com)もあわせてご確認ください。
-
前の記事
【完全ガイド】ORA-02291: integrity constraint (parent key not found) の原因と解決方法|外部キー制約・CASCADE・DEFERRED 徹底解説 2026.07.30
-
次の記事
【完全ガイド】ORA-06502: PL/SQL numeric or value error の原因と解決方法|4種類のサブタイプ・NOT NULL・例外処理 徹底解説 2026.07.31
コメントを書く