【Oracle】ORA-01858の原因と解決方法|a non-numeric character was found where a numeric was expected

ORA-01858: a non-numeric character was found where a numeric was expected は、Oracleで文字列を日付や数値へ変換する際、数字を期待している位置に数字以外の文字が入っている時に発生するエラーです。特に TO_DATE、暗黙の日付変換、CSV取込、アプリからの文字列日付でよく起きます。

代表例は、TO_DATE('2026-05-17', 'YYYY/MM/DD') のように、実データの区切り文字と書式モデルが合っていないケースです。数字を期待する MMDD の位置に、月名、曜日、日本語文字、余計な空白などが入っている場合も原因になります。

先に結論
ORA-01858が出たら、変換対象の文字列と TO_DATE の書式モデルを1文字ずつ照合します。区切り文字、月の表記、曜日、日本語日付、空白、NLS設定を確認し、可能ならアプリ側からDATE型としてバインドします。
スポンサーリンク

ORA-01858とは

ORA-01858は、日付変換の書式と入力値が合っていない時に出ます。Oracleは書式モデルの YYYYMMDD などを見ながら文字列を読みます。数字を読むべき場所に -/、月名、空白、漢字などが来ると変換できません。

確認点 よくある原因 修正の方向
区切り文字 実データは-、書式は/ 入力値と書式を合わせる
月の表記 Jan5月MM で読んでいる MON や前処理を使う
余計な文字 曜日、時刻、空白が混ざっている 書式モデルに含めるか取り除く
NLS設定 英語月名/日本語月名の解釈が合わない NLS_DATE_LANGUAGE を指定する
暗黙変換 DATE列と文字列を比較している DATE型でバインドする

日付変換系では ORA-01830ORA-01843ORA-01861 も近いエラーです。ORA-01858は、特に「数字が来るべき場所に文字がある」点に注目します。

TO_DATEの書式と実データが合っていない

まず確認するのは、入力文字列と書式モデルの不一致です。見た目が日付でも、区切り文字や桁数が違うと変換に失敗します。

to-date-format-mismatch.sql
-- NG: 実データはハイフン区切り、書式はスラッシュ区切り
SELECT TO_DATE('2026-05-17', 'YYYY/MM/DD')
FROM dual;

-- OK: 実データに合わせる
SELECT TO_DATE('2026-05-17', 'YYYY-MM-DD')
FROM dual;

逆に、実データが 2026/05/17 なら YYYY/MM/DD にします。区切り文字を無視できると思い込まず、実際にDBへ渡っている値をログで確認してください。

数字を期待する場所に文字が入っている

MM は数字の月、DD は数字の日を期待します。そこに May5月月曜日 のような文字が入るとORA-01858になります。

non-numeric-month.sql
-- NG: MMは数字の月を期待する
SELECT TO_DATE('17-May-2026', 'DD-MM-YYYY')
FROM dual;

-- OK: 英語の月名ならMONを使う
SELECT TO_DATE(
  '17-May-2026',
  'DD-MON-YYYY',
  'NLS_DATE_LANGUAGE=English'
)
FROM dual;

日本語の 2026年05月17日 のような形式は、前処理で数字だけの形式に整えるか、書式モデルに固定文字を含めて読みます。

japanese-date-literal.sql
SELECT TO_DATE('2026年05月17日', 'YYYY"年"MM"月"DD"日"')
FROM dual;

NLS_DATE_LANGUAGEと月名の影響

月名を含む文字列を変換する場合、セッションの NLS_DATE_LANGUAGE によって解釈が変わります。英語の May、日本語の月名、曜日名を扱う場合は、TO_DATE の第3引数で明示する方が安全です。

nls-date-language-month-name.sql
-- セッション設定に依存させない
SELECT TO_DATE(
  '17-May-2026',
  'DD-MON-YYYY',
  'NLS_DATE_LANGUAGE=English'
)
FROM dual;

NLS_DATE_FORMAT は暗黙変換の表示/解釈に影響しますが、明示的な TO_DATE では書式モデルを指定するのが基本です。

暗黙変換で発生するケース

DATE列と文字列を比較すると、Oracleが暗黙的に文字列をDATEへ変換することがあります。この時、セッションのNLS設定や文字列の形式が合わないとORA-01858になります。

implicit-date-conversion.sql
-- NG: 文字列の日付比較はNLS設定に依存する
SELECT *
FROM orders
WHERE order_date = '2026-05-17';

-- OK: DATEリテラルを使う
SELECT *
FROM orders
WHERE order_date = DATE '2026-05-17';

-- または明示的にTO_DATEする
SELECT *
FROM orders
WHERE order_date = TO_DATE('2026-05-17', 'YYYY-MM-DD');

数値列に文字列を入れている場合は ORA-01722 側の問題です。日付列なのか数値列なのか、変換先の型も確認しましょう。

CSV取込や外部表で発生する場合

CSV取込では、空白、ヘッダー行、引用符、全角文字、混在フォーマットが原因でORA-01858が出やすいです。いきなりDATE列へ入れるのではなく、いったん文字列列へ取り込み、変換できない行を洗い出すと安全です。

find-invalid-date-rows.sql
-- 文字列として取り込んだ後、変換できない行を探す例
SELECT raw_date
FROM import_work
WHERE VALIDATE_CONVERSION(raw_date AS DATE, 'YYYY-MM-DD') = 0;

VALIDATE_CONVERSION が使えない古い環境では、正規表現で形式を先に絞り込み、明らかに形式が違う行を除外してから TO_DATE します。ただし正規表現だけでは 2026-02-31 のような存在しない日付までは完全に検出できないため、最終的な変換チェックも必要です。

find-invalid-date-rows-with-regexp.sql
-- YYYY-MM-DD形式でない行を先に探す
SELECT raw_date
FROM import_work
WHERE NOT REGEXP_LIKE(raw_date, '^\d{4}-\d{2}-\d{2}$');

-- 形式が合う行だけを変換対象にする
SELECT TO_DATE(raw_date, 'YYYY-MM-DD') AS converted_date
FROM import_work
WHERE REGEXP_LIKE(raw_date, '^\d{4}-\d{2}-\d{2}$');

CSVをSQLで直接読む場合は 外部表ガイド、PL/SQLでファイルを扱う場合は UTL_FILEガイド も参考になります。

FXで厳密に日付書式をチェックする

Oracleの書式モデルは、指定によっては空白や区切り文字をある程度ゆるく扱うことがあります。取込データを厳密に検査したい場合は、FX を付けて入力値と書式モデルを完全一致に近い形でチェックします。

strict-date-format-fx.sql
-- 厳密に YYYY-MM-DD 形式だけを許可する
SELECT TO_DATE('2026-05-17', 'FXYYYY-MM-DD')
FROM dual;

-- 区切りや桁が合わない値を早めに検出しやすい
SELECT TO_DATE('2026/05/17', 'FXYYYY-MM-DD')
FROM dual;

CSVや外部連携では、取り込み前に「許可する日付形式」を決め、FX や正規表現で検査しておくと、ORA-01858が本処理の途中で出るリスクを下げられます。

アプリからはDATE型でバインドする

アプリ側で日付を文字列連結してSQLへ埋め込むと、NLS設定や書式違いに弱くなります。JDBCやPythonなどでは、日付型としてバインドする方が安全です。

java-date-bind.java
String sql = "SELECT * FROM orders WHERE order_date = ?";

try (PreparedStatement ps = conn.prepareStatement(sql)) {
    ps.setDate(1, java.sql.Date.valueOf(LocalDate.of(2026, 5, 17)));
    ResultSet rs = ps.executeQuery();
}
python-date-bind.py
sql = "SELECT * FROM orders WHERE order_date = :target_date"
cursor.execute(sql, {"target_date": date(2026, 5, 17)})

ORA-01830・ORA-01843・ORA-01861との違い

ORA-01858

主な意味: 数字を期待する位置に数字以外の文字がある

例: MM の場所に May がある

ORA-01830

主な意味: 書式モデルが入力文字列の途中で終わる

関連記事: ORA-01830

ORA-01843

主な意味: 月として解釈できない値がある

関連記事: ORA-01843

ORA-01861

主な意味: リテラルと書式文字列が一致していない

関連記事: ORA-01861

調査手順

ORA-01858は、実データと書式モデルを並べて確認すると早く切り分けられます。暗黙変換が疑わしい場合は、SQL内の文字列日付をすべて明示変換またはDATE型バインドへ寄せます。

順番 確認すること 見るポイント
1 実際の入力文字列を確認する 区切り文字、空白、月名、曜日、日本語文字
2 TO_DATEの書式を確認する YYYYMMDD の位置
3 NLS設定を確認する NLS_DATE_LANGUAGENLS_DATE_FORMAT
4 暗黙変換をなくす DATEリテラル、明示的TO_DATE、DATE型バインド
5 不正データを抽出する VALIDATE_CONVERSION や一時表で確認

チェックリスト

  • 入力値と TO_DATE の書式モデルを1文字ずつ照合した
  • YYYY/MM/DDYYYY-MM-DD の区切り文字を確認した
  • 月名や曜日を含む場合は NLS_DATE_LANGUAGE を指定した
  • DATE列と文字列を暗黙比較していない
  • CSV取込では、まず文字列列へ取り込んで不正行を洗い出した
  • アプリからは文字列連結ではなくDATE型でバインドしている

よくある質問

YYYY/MM/DDとYYYY-MM-DDは自動で解釈されませんか?

期待しないでください。明示的な TO_DATE では、入力値と書式モデルを合わせるのが基本です。

画面では日付に見えるのに失敗します

画面表示では日付らしく見えても、DBへ渡っている値に空白、曜日、全角文字、別区切り文字が含まれていることがあります。実際のバインド値をログで確認してください。

NLS_DATE_FORMATを変えれば直りますか?

暗黙変換に依存している場合は一時的に直ることがありますが、根本対策としては明示的な書式指定やDATE型バインドを使う方が安全です。

まとめ

ORA-01858は、日付変換で数字を期待する位置に数字以外の文字が入っている時に発生します。入力文字列、書式モデル、NLS設定、暗黙変換の有無を順番に確認しましょう。

実務では、日付を文字列として扱い続けるほどエラーが増えます。CSV取込では一時表で検査し、アプリからはDATE型でバインドする設計にすると、ORA-01858を防ぎやすくなります。

参考

ORA-01858 – Oracle Database Error Help

TO_DATE – Oracle Database SQL Language Reference

Format Models – Oracle Database SQL Language Reference