【完全ガイド】ORA-01858: a non-numeric character was found where a numeric was expected の原因と解決方法|TO_DATE の罠・NLS_DATE_FORMAT まで徹底解説

【完全ガイド】ORA-01858: a non-numeric character was found where a numeric was expected の原因と解決方法|TO_DATE の罠・NLS_DATE_FORMAT まで徹底解説

Oracle で日付変換の際、必ず遭遇する第3の日付エラー:

SELECT TO_DATE('ABCD-06-15', 'YYYY-MM-DD') FROM DUAL;
ORA-01858: a non-numeric character was found where a numeric was expected

翻訳: 「数値が期待された位置に、非数値の文字があった」

Oracle の日付変換エラー3兄弟の一つ:

  • ORA-01843: 「無効な月」(月の位置に解釈できない値)
  • ORA-01830: 「フォーマット終了後に余り」(入力が長すぎ)
  • ORA-01858: 「数値位置に非数値」(形式が根本的に違う)

現場では:

  • CSV インポートで一部の行だけエラー
  • TO_DATE(SYSDATE, 'YYYY-MM-DD') で発生(!)
  • 全角スペース・全角数字の混入
  • 空文字 '' を渡してエラー
  • NLS_DATE_FORMAT との不一致
  • 他 DB(Informatica/ODBC)経由でエラー
  • MON フォーマットに数値月を渡すエラー

このエラーは、フォーマットと入力の型が根本的に合わないことを示します。「余分がある」ORA-01830 とは違い、**「そもそも数値じゃない」**という状況。

さらに、Oracle 開発者が驚くほどよくハマる罠があります:

-- 一見正しそうだが実は誤り
SELECT TO_DATE(SYSDATE, 'YYYY-MM-DD') FROM DUAL;
-- ORA-01858

理由: SYSDATE は DATE 型なので、内部的に文字列に変換される際、NLS_DATE_FORMAT に依存。もし DD-MON-RR だと 15-JUN-26 になり、YYYY-MM-DD フォーマットの Y 位置に 1(数値OK)ではなく - があると混乱。この暗黙変換の罠は、日本語圏でほぼ解説されていません。

本記事では、ORA-01858: a non-numeric character was found where a numeric was expected完全な原因と解決方法を、リファレンスとして実用的に整理します。エラーの本質、3種類の日付エラー比較、7大発生パターン、TO_DATE(SYSDATE) の罠、REGEXP_LIKE 事前チェック、12c+ 新機能、Rails/Java/Python 対応、実践シナリオ、予防策、FAQまで完全網羅。この1本で ORA-01858 を根本から解決できるようになります。


目次

結論:フォーマットと入力の型を一致させる

時間がない方向けに、最速の対処を先に示します。

基本原則

フォーマットが「数値」を期待する位置に「非数値」があると発生

3つの日付エラー比較

エラー意味
ORA-01843月の位置に無効な値(例: 13月)
ORA-01830入力が長すぎる(フォーマット後に余り)
ORA-01858数値位置に非数値(型の根本ミスマッチ)

7大原因

#原因
数値位置に文字TO_DATE('ABCD-06-15', 'YYYY-MM-DD')
TO_DATE(SYSDATE) の罠TO_DATE(SYSDATE, 'YYYY-MM-DD')
MON と MM の混同TO_DATE('06', 'MON')
全角文字TO_DATE('2026-06-15', 'YYYY-MM-DD')
空文字・空白TO_DATE('', 'YYYY-MM-DD')
NULL 混入TO_DATE(v_str, 'YYYY-MM-DD')
NLS_DATE_FORMAT 不一致セッション設定違い

最速解決コード

-- ① 明示的フォーマット指定
TO_DATE('2026-06-15', 'YYYY-MM-DD')

-- ② DATE の再変換は避ける(そのまま使う)
-- ❌ TO_DATE(SYSDATE, 'YYYY-MM-DD')
-- ✅ SYSDATE  または  TRUNC(SYSDATE)

-- ③ 事前チェック(REGEXP_LIKE)
CASE 
  WHEN REGEXP_LIKE(v_str, '^\d{4}-\d{2}-\d{2}$')
  THEN TO_DATE(v_str, 'YYYY-MM-DD')
  ELSE NULL
END

-- ④ 12c+ の DEFAULT ON CONVERSION ERROR
TO_DATE(v_str DEFAULT NULL ON CONVERSION ERROR, 'YYYY-MM-DD')

詳細は以下で解説します。


まず理解する:エラーの本質

メッセージの意味

ORA-01858: a non-numeric character was found where a numeric was expected
                                            ↑
                                    「数値が期待された位置に」

フォーマット指定で数値位置(YYYY, MM, DD 等)に、数字以外の文字があると発生。

Oracle 公式の説明

Cause: The input data to be converted using a date format model was incorrect. 
       The input data did not contain a number where a number was required 
       by the format model.

Action: Fix the input data or the date format model to make sure the elements 
        match in number and type.

翻訳: 「入力データがフォーマットモデルの数値要求位置に数値がなかった

具体例

入力:      'ABCD-06-15'
フォーマット: 'YYYY-MM-DD'

Y Y Y Y | - | M M | - | D D
↓ ↓ ↓ ↓
A B C D    ← 数値じゃない!
        → ORA-01858

3つの日付エラー完全比較

-- ORA-01858: 数値位置に非数値
TO_DATE('ABCD-06-15', 'YYYY-MM-DD')
--       [ABCD が YYYY 位置] → 非数値

-- ORA-01830: 入力が長すぎる
TO_DATE('2026-06-15 14:30', 'YYYY-MM-DD')
--       [変換OK]     [余分] → 長い

-- ORA-01843: 月の位置に無効な値
TO_DATE('31/13/1985', 'DD/MM/YYYY')
--       [DD] [??] → 13月は無効

エラーが発生するタイミング

  • INSERT/UPDATE の値変換
  • WHERE 句の比較
  • SELECT 句での計算
  • PL/SQL の代入

DML 全般で発生の可能性。


【原因①】数値位置に文字

症状

TO_DATE('ABCD-06-15', 'YYYY-MM-DD')
-- ORA-01858

原因

YYYY 位置に ABCD という文字。明らかに不正な入力データ

診断

-- 不正データを検出
SELECT date_str
FROM staging_data
WHERE NOT REGEXP_LIKE(date_str, '^\d{4}-\d{2}-\d{2}$');

解決

入力データを修正、またはバリデーションで除外:

-- 事前チェック付き変換
CASE 
  WHEN REGEXP_LIKE(date_str, '^\d{4}-\d{2}-\d{2}$')
  THEN TO_DATE(date_str, 'YYYY-MM-DD')
  ELSE NULL
END

【原因②】TO_DATE(SYSDATE) の罠

症状

一見正しく見えるコード:

-- 深夜バッチで発生
SELECT TO_DATE(SYSDATE, 'YYYY-MM-DD') FROM DUAL;
-- ORA-01858

なぜ発生するか

SYSDATE は DATE 型TO_DATE は文字列を DATE に変換する関数なので、SYSDATE内部的に文字列に変換される:

SYSDATE
  ↓ 暗黙変換
NLS_DATE_FORMAT に従い文字列化
  ↓ 例: '15-JUN-26'(DD-MON-RR)
TO_DATE('15-JUN-26', 'YYYY-MM-DD')
  ↓
'YYYY' 位置に '15-JU' → 数値じゃない!
  ↓
ORA-01858

診断

-- NLS_DATE_FORMAT 確認
SHOW PARAMETER nls_date_format

-- SYSDATE の文字列表現
SELECT SYSDATE FROM DUAL;

解決

そもそも DATE を DATE に変換する必要はない:

-- ❌ 不要な変換
TO_DATE(SYSDATE, 'YYYY-MM-DD')

-- ✅ そのまま使う
SYSDATE

-- ✅ 時刻部分を切り捨てたいなら
TRUNC(SYSDATE)

-- ✅ 文字列にしたい場合
TO_CHAR(SYSDATE, 'YYYY-MM-DD')

-- ✅ 別の DATE に変換したい場合(レア)
TO_DATE(TO_CHAR(SYSDATE, 'YYYY-MM-DD'), 'YYYY-MM-DD')

この罠が現場で発生するパターン

-- レガシー PL/SQL でよくある
BEGIN
  IF v_input_date = TO_DATE(SYSDATE, 'YYYY-MM-DD') THEN
    -- 同じ日付判定したいが、エラー
  END IF;
END;

-- 正しくは
BEGIN
  IF TRUNC(v_input_date) = TRUNC(SYSDATE) THEN
    -- 日付部分だけ比較
  END IF;
END;

【原因③】MON と MM の混同

症状

-- 数値月を MON フォーマットに
TO_DATE('06', 'MON')
-- ORA-01858

-- 月名を MM フォーマットに
TO_DATE('JUN', 'MM')
-- ORA-01858

動作の違い

  • MM: 数値月(01-12)を期待
  • MON: 月名略称(JAN, FEB…)を期待
  • MONTH: 月名フル(JANUARY…)を期待

解決

入力とフォーマットを一致:

-- 数値月
TO_DATE('06', 'MM')      -- OK

-- 月名略称
TO_DATE('JUN', 'MON')    -- OK

-- 月名フル
TO_DATE('JUNE', 'MONTH') -- OK

NLS_LANGUAGE の影響

-- 英語環境
TO_DATE('15-JAN-26', 'DD-MON-RR')  -- OK

-- 日本語環境
TO_DATE('15-1月-26', 'DD-MON-RR')   -- 環境依存

-- 明示的に言語指定
TO_DATE('15-JAN-26', 'DD-MON-RR', 'NLS_DATE_LANGUAGE = AMERICAN')

言語設定関連は Oracle パラメータ確認(V$PARAMETER)の記事、月フォーマットの詳細は ORA-01843: not a valid month の記事も参照してください。


【原因④】全角文字の混入

症状

TO_DATE('2026-06-15', 'YYYY-MM-DD')  -- 全角数字
-- ORA-01858

TO_DATE('2026-06-15 ', 'YYYY-MM-DD')     -- 全角スペース
-- ORA-01858

診断

-- 全角混入を検出
SELECT date_str
FROM t
WHERE date_str <> ASCIISTR(date_str);
-- ASCII 変換で違いがあれば非 ASCII 文字含む

-- 特定の全角文字検出
SELECT date_str
FROM t
WHERE REGEXP_LIKE(date_str, '[^\x00-\x7F]');

解決

アプリ側で全角→半角変換、または SQL で:

-- CONVERT で ASCII 変換
TO_DATE(
  CONVERT(REGEXP_REPLACE(date_str, '[^\x00-\x7F]', ''), 'US7ASCII'),
  'YYYY-MM-DD'
)

-- TRANSLATE で個別変換
TO_DATE(
  TRANSLATE(date_str, '0123456789', '0123456789'),
  'YYYY-MM-DD'
)

Java 側での対処(推奨):

String halfWidth = Normalizer.normalize(input, Normalizer.Form.NFKC);

【原因⑤】空文字・空白のみ

症状

TO_DATE('', 'YYYY-MM-DD')
-- ORA-01858

TO_DATE('   ', 'YYYY-MM-DD')
-- ORA-01858

解決A: NULLIF で NULL 化

TO_DATE(NULLIF(TRIM(date_str), ''), 'YYYY-MM-DD')
-- 空文字なら NULL、それ以外は変換

解決B: CASE で分岐

CASE 
  WHEN TRIM(date_str) IS NULL THEN NULL
  WHEN REGEXP_LIKE(date_str, '^\d{4}-\d{2}-\d{2}$')
    THEN TO_DATE(date_str, 'YYYY-MM-DD')
  ELSE NULL
END

空文字と NULL の Oracle 挙動

Oracle は空文字を NULL として扱う(他 DB と違う):

SELECT * FROM t WHERE col = '';  -- 常に0行(col = NULL と同じ)
SELECT * FROM t WHERE col IS NULL;  -- 空文字も含む

移行時に注意


【原因⑥】NULL 混入

症状

-- v_date_str が NULL
SELECT TO_DATE(v_date_str, 'YYYY-MM-DD') FROM DUAL;
-- 通常は NULL を返すが、環境によりエラー

動作

  • 通常: TO_DATE(NULL, ...) は NULL を返す
  • 稀に: 実装依存でエラー

対処

-- NULL チェック
CASE 
  WHEN v_date_str IS NULL THEN NULL
  ELSE TO_DATE(v_date_str, 'YYYY-MM-DD')
END

-- NVL で明示的
TO_DATE(NVL(v_date_str, '1900-01-01'), 'YYYY-MM-DD')

-- 12c+ の DEFAULT ON CONVERSION ERROR
TO_DATE(v_date_str DEFAULT NULL ON CONVERSION ERROR, 'YYYY-MM-DD')

【原因⑦】NLS_DATE_FORMAT との不一致

症状

-- セッション設定: NLS_DATE_FORMAT = 'DD-MON-RR'
SELECT * FROM t WHERE date_col = '2026-06-15';
-- 内部的に TO_DATE('2026-06-15', 'DD-MON-RR')
-- YYYY-MM-DD 形式なのに DD-MON-RR で解釈 → ORA-01858

診断

-- 現在の設定
SHOW PARAMETER nls_date_format

-- または
SELECT SYS_CONTEXT('USERENV', 'NLS_DATE_FORMAT') FROM DUAL;

-- ODBC/JDBC 経由での確認
SELECT * FROM nls_session_parameters WHERE parameter = 'NLS_DATE_FORMAT';

解決A: 明示的フォーマット

-- 常に明示
TO_DATE('2026-06-15', 'YYYY-MM-DD')
-- NLS_DATE_FORMAT に依存しない

解決B: セッション統一

-- 起動時 or 接続時に統一
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

Rails / JDBC / ODBC 全て統一。

他 DB 連携(Informatica 等)

Informatica の ODBC ドライバはデフォルト 'YYYY-MM-DD'
Oracle デフォルトは環境により 'DD-MON-RR'
→ フォーマット不一致で ORA-01858

対処: 初期化文字列で NLS 設定
Initialization String = alter session set NLS_DATE_FORMAT='YYYY-MM-DD'

診断ツール

問題データの検出

-- 数値以外の文字を含む行
SELECT date_str
FROM staging_data
WHERE NOT REGEXP_LIKE(date_str, '^[0-9\-/: .]+$');

空文字・空白のみ

SELECT date_str
FROM t
WHERE TRIM(date_str) IS NULL AND date_str IS NOT NULL;

NULL vs 空文字

SELECT date_str, 
       CASE 
         WHEN date_str IS NULL THEN 'NULL'
         WHEN TRIM(date_str) IS NULL THEN 'EMPTY'
         WHEN NOT REGEXP_LIKE(date_str, '^\d') THEN 'INVALID'
         ELSE 'OK'
       END AS status
FROM t;

バルク処理でエラー行分離

INSERT INTO target
SELECT TO_DATE(date_str, 'YYYY-MM-DD') 
FROM source
LOG ERRORS INTO source_err REJECT LIMIT UNLIMITED;

SELECT ora_err_number$, ora_err_mesg$, date_str
FROM source_err
WHERE ora_err_number$ = 1858;

LOG ERRORS の詳細は ORA-00001: unique constraint violated の記事も参考にしてください。


Rails / Java / Python 対応

Rails ActiveRecord

# ✅ ActiveRecord は日付型を直接変換
Order.create!(order_date: Date.parse('2026-06-15'))

# ❌ 生 SQL で文字列
sql = "INSERT INTO orders (order_date) VALUES ('#{date_str}')"

# ✅ 生 SQL で明示的
sql = "INSERT INTO orders (order_date) VALUES (TO_DATE(:d, 'YYYY-MM-DD'))"
ActiveRecord::Base.connection.execute(sql, d: '2026-06-15')

# 初期化スクリプト
Rails.application.config.after_initialize do
  ActiveRecord::Base.connection.execute(
    "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
  )
end

Rails 8 系の詳細は Rails 8 アップグレードガイドの記事、rails db:migrate 使い方の記事、Solid Queue 使い方の記事も参照してください。

Java (JDBC)

// ❌ 文字列で渡す(エラーの温床)
ps.setString(1, dateStr);

// ✅ java.sql.Date で渡す
ps.setDate(1, java.sql.Date.valueOf("2026-06-15"));

// ✅ LocalDate(Java 8+)
ps.setObject(1, LocalDate.of(2026, 6, 15));

// バリデーション
if (!input.matches("\\d{4}-\\d{2}-\\d{2}")) {
    throw new IllegalArgumentException("Invalid date");
}

Python (oracledb)

import oracledb
from datetime import date

# ✅ date 型を直接
cursor.execute(
    "INSERT INTO orders (order_date) VALUES (:d)",
    d=date(2026, 6, 15)
)

# ❌ 文字列
cursor.execute(
    "INSERT INTO orders (order_date) VALUES (:d)",
    d="2026-06-15"
)
# → NLS_DATE_FORMAT 依存でエラーの可能性

実践シナリオ

シナリオ1:CSV インポート

-- staging から検証しながら投入
INSERT INTO orders (id, order_date)
SELECT id,
       CASE 
         WHEN REGEXP_LIKE(order_date_str, '^\d{4}-\d{2}-\d{2}$')
           THEN TO_DATE(order_date_str, 'YYYY-MM-DD')
         ELSE NULL
       END
FROM staging_orders;

シナリオ2:Data Pump 後の検証

-- インポート後の日付列検証
SELECT COUNT(*) 
FROM imported_data
WHERE date_col IS NULL AND date_col_str IS NOT NULL;

Data Pump の詳細は Oracle Data Pump 使い方の記事を参照してください。

シナリオ3:REST API からの受信

-- ISO 8601 の可能性も含めて柔軟に
CASE 
  WHEN REGEXP_LIKE(input, '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$')
    THEN TO_DATE(input, 'YYYY-MM-DD"T"HH24:MI:SS')
  WHEN REGEXP_LIKE(input, '^\d{4}-\d{2}-\d{2}$')
    THEN TO_DATE(input, 'YYYY-MM-DD')
  ELSE NULL
END

ISO 8601 の詳細は ORA-01830: date format picture ends の記事、無効月は ORA-01843: not a valid month の記事も参照してください。

シナリオ4:他 DB からの取り込み

-- Informatica 経由のセッション設定
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';

-- または明示的
INSERT INTO t SELECT TO_DATE(date_str, 'YYYY-MM-DD') FROM ext_source;

シナリオ5:レガシー PL/SQL 修正

-- 旧コード(罠)
IF v_input = TO_DATE(SYSDATE, 'YYYY-MM-DD') THEN ...

-- 修正
IF TRUNC(v_input) = TRUNC(SYSDATE) THEN ...

シナリオ6:バッチ処理での安全な変換

DECLARE
  v_date DATE;
BEGIN
  FOR rec IN (SELECT id, date_str FROM staging) LOOP
    BEGIN
      v_date := TO_DATE(rec.date_str, 'YYYY-MM-DD');
      INSERT INTO target VALUES (rec.id, v_date);
    EXCEPTION
      WHEN OTHERS THEN
        INSERT INTO err_log VALUES (rec.id, rec.date_str, SQLERRM);
    END;
  END LOOP;
END;
/

シナリオ7:Docker Oracle での動作確認

docker exec -it oracle-xe sqlplus scott/tiger <<EOF
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';
SELECT TO_DATE(SYSDATE, 'YYYY-MM-DD') FROM DUAL;
-- 上記なら OK
-- ↓ 罠を確認
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-RR';
SELECT TO_DATE(SYSDATE, 'YYYY-MM-DD') FROM DUAL;
-- ORA-01858 発生
EOF

Docker 関連は docker daemon 接続エラーの記事、Docker no space left on device の記事も参照してください。

シナリオ8:Kamal デプロイ後の DB 初期化

# 環境変数で NLS 統一
env:
  clear:
    NLS_LANG: JAPANESE_JAPAN.AL32UTF8
    NLS_DATE_FORMAT: "YYYY-MM-DD HH24:MI:SS"

Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事を参照してください。

シナリオ9:Solid Queue ジョブ時刻

-- ジョブスケジュール時刻の変換
SELECT job_id,
       TO_TIMESTAMP(scheduled_at_str, 'YYYY-MM-DD HH24:MI:SS.FF')
FROM job_queue;

Solid Queue の詳細は Solid Queue 使い方の記事も参照してください。

シナリオ10:全角混入の検出と修正

-- 全角数字を含む行を検出
SELECT id, date_str
FROM t
WHERE date_str <> ASCIISTR(date_str)
   OR REGEXP_LIKE(date_str, '[0-9]');

-- 修正 SQL
UPDATE t 
SET date_str = TRANSLATE(date_str, 
                         '0123456789', 
                         '0123456789')
WHERE REGEXP_LIKE(date_str, '[0-9]');

予防のベストプラクティス

1. 常に明示的なフォーマット指定

-- ❌ NLS 依存
TO_DATE(str)

-- ✅ 明示
TO_DATE(str, 'YYYY-MM-DD')

2. TO_DATE(DATE型) は使わない

-- ❌ SYSDATE は DATE 型なので無意味
TO_DATE(SYSDATE, 'YYYY-MM-DD')

-- ✅ そのまま使う
SYSDATE
TRUNC(SYSDATE)

3. アプリ側で日付型を渡す

ps.setDate(1, java.sql.Date.valueOf("2026-06-15"));

文字列化を避けるのが根本策。

4. 事前バリデーション

CASE 
  WHEN REGEXP_LIKE(str, '^\d{4}-\d{2}-\d{2}$')
    THEN TO_DATE(str, 'YYYY-MM-DD')
  ELSE NULL
END

5. 12c+ の ON CONVERSION ERROR

TO_DATE(str DEFAULT NULL ON CONVERSION ERROR, 'YYYY-MM-DD')

6. セッション設定の統一

-- 全接続で
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

7. 全角/空文字の除去

NULLIF(TRIM(str), '')

8. ISO 8601 標準採用

2026-06-15T14:30:45Z

曖昧さのない標準形式

9. LOG ERRORS でバルク対応

INSERT ... LOG ERRORS INTO t_err REJECT LIMIT UNLIMITED;

10. テストデータの多様化

  • 正常データ
  • NULL / 空文字
  • 全角混入
  • 不正フォーマット
  • 空白のみ

トラブルシューティング

一部の行だけエラー

-- 不正データを特定
SELECT id, date_str
FROM t
WHERE NOT REGEXP_LIKE(date_str, '^\d{4}-\d{2}-\d{2}$');

アプリ側は文字列だが CI で失敗

// テスト環境の NLS 設定を確認
System.getenv("NLS_DATE_FORMAT")

開発機で動くが本番で失敗

NLS_DATE_FORMAT の環境差異:

SELECT SYS_CONTEXT('USERENV', 'NLS_DATE_FORMAT') FROM DUAL;

環境で違えばセッション設定で統一。

ODBC/JDBC ドライバ経由

接続文字列に初期化スクリプト:

initSQL=ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'

レガシー PL/SQL のリファクタリング

-- 一括検索
SELECT text FROM user_source
WHERE UPPER(text) LIKE '%TO_DATE(SYSDATE%';

該当箇所を全て修正

RAISE_APPLICATION_ERROR で明示化

BEGIN
  ...
EXCEPTION
  WHEN OTHERS THEN
    IF SQLCODE = -1858 THEN
      RAISE_APPLICATION_ERROR(-20001, 
        'Date format mismatch: ' || v_date_str);
    ELSE RAISE;
    END IF;
END;
/

よくある質問(FAQ)

Q1. ORA-01858 と ORA-01830 と ORA-01843 の違い

  • ORA-01858: 数値位置に非数値(型ミスマッチ)
  • ORA-01830: 入力が長すぎる
  • ORA-01843: 月の位置に無効な値

Q2. TO_DATE(SYSDATE) の代替

-- そのまま
SYSDATE

-- 時刻切り捨て
TRUNC(SYSDATE)

-- 特定精度
TRUNC(SYSDATE, 'HH24')

Q3. 全角数字の変換

TRANSLATE(str, '0123456789', '0123456789')

Q4. Oracle は空文字を NULL 扱い

'' IS NULL  -- TRUE(Oracle 特有)

他 DB と挙動が違う

Q5. NLS_DATE_FORMAT の変更

-- セッション
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';

-- システム
ALTER SYSTEM SET NLS_DATE_FORMAT = 'YYYY-MM-DD' SCOPE = SPFILE;

パラメータ設定の詳細は Oracle パラメータ確認(V$PARAMETER)の記事を参照してください。

Q6. Rails での対応

# ActiveRecord は自動変換
Model.create!(date: Date.parse(str))

Q7. Autonomous DB での対応

同じ挙動。プラットフォーム関係なし。

Q8. AWS RDS Oracle

同じ挙動。Parameter Group で NLS 設定可能。

Q9. 空文字を扱う設計

-- 空文字排除
NULLIF(TRIM(str), '')

Q10. 大量データの変換失敗

-- LOG ERRORS で継続
INSERT ... LOG ERRORS INTO t_err REJECT LIMIT UNLIMITED;

Q11. 数値カラムでも発生?

-- 数値変換でも似たエラー(ORA-01722)
TO_NUMBER('ABC')
-- ORA-01722: invalid number

ORA-01858 は主に日付、ORA-01722 は数値。姉妹エラー。

Q12. 12c+ の DEFAULT ON CONVERSION ERROR

TO_DATE(str DEFAULT NULL ON CONVERSION ERROR, 'YYYY-MM-DD')
-- 変換失敗時 NULL を返す

バルク処理で有用


参考リンク

Oracle 公式


まとめ

ORA-01858: a non-numeric character was found where a numeric was expected の要点を再整理します。

エラーの本質

フォーマット: YYYY (数値期待)
入力:        ABCD (非数値)
       ↓
ORA-01858 発生

3つの日付エラー比較

エラー意味
ORA-01843月の位置に無効な値13月
ORA-01830入力が長すぎる‘YYYY-MM-DD’ に ‘2026-06-15 14:00’
ORA-01858数値位置に非数値‘YYYY-MM-DD’ に ‘ABCD-06-15’

7大原因

#原因対処
数値位置に文字事前検証
TO_DATE(SYSDATE)そのまま使う
MON vs MM 混同フォーマット確認
全角文字TRANSLATE
空文字・空白NULLIF(TRIM(…), ”)
NULL 混入NULL チェック
NLS_DATE_FORMAT 不一致セッション統一

TO_DATE(SYSDATE) の罠

-- ❌ NG(NLS 依存)
TO_DATE(SYSDATE, 'YYYY-MM-DD')

-- ✅ そのまま
SYSDATE

-- ✅ 日付部分だけ
TRUNC(SYSDATE)

DATE 型を DATE に変換する必要はない

事前検証パターン

CASE 
  WHEN str IS NULL THEN NULL
  WHEN TRIM(str) IS NULL THEN NULL
  WHEN REGEXP_LIKE(str, '^\d{4}-\d{2}-\d{2}$')
    THEN TO_DATE(str, 'YYYY-MM-DD')
  ELSE NULL
END

予防のベストプラクティス

  • 明示的なフォーマット指定
  • TO_DATE(DATE型) は使わない
  • アプリで日付型を渡す
  • 事前バリデーション
  • 12c+ の ON CONVERSION ERROR
  • セッション設定の統一
  • 全角/空文字の除去
  • ISO 8601 標準採用
  • LOG ERRORS でバルク対応

事故防止

  • フォーマット文字列を必ず明示
  • SYSDATE は文字列変換不要
  • NLS_DATE_FORMAT の環境差を意識
  • 入力データを事前検証
  • アプリで日付型を使う

これらの知識は、Oracle での日常開発・CSV インポート・データ移行・ETL・レガシー保守・Rails / Java / Python 開発・他 DB 連携など、あらゆる場面で活用できます。本記事をブックマークしておけば、ORA-01858 に出会っても迷わず的確に対処できるようになります。


本記事は2026年6月時点の情報をもとに、Oracle Database 19c〜23ai での動作確認・公式ドキュメントに基づき作成しています。Oracle のバージョンにより挙動が異なる場合があるため、最新の情報は Oracle 公式ドキュメント(docs.oracle.com)もあわせてご確認ください。