【Oracle】ORA-01843の原因と解決方法|not a valid month・月が無効です

【Oracle】ORA-01843の原因と解決方法|not a valid month・月が無効です Oracle

ORA-01843: not a valid month は、Oracleが日付文字列の月部分を有効な月として解釈できない時に発生するエラーです。TO_DATE の書式が入力値と合っていない、月名の言語が合っていない、日付型カラムと文字列を比較して暗黙変換が走っている、といった場面でよく出ます。

たとえば 2026-13-01 のように月が13になっている場合はもちろん、13/05/2026MM/DD/YYYY として読ませようとした場合や、MARMarch などの英語月名を日本語セッションで読ませる場合にも発生します。

先に結論
ORA-01843は、入力文字列、フォーマットモデル、NLS_DATE_LANGUAGEを同時に確認すると切り分けやすいです。数値月なら YYYY-MM-DDDD/MM/YYYY の並び違いを、文字月なら MON / MONTH と言語設定を確認します。日付型カラムとの比較では、文字列のまま比較せず TO_DATE やDATEリテラルで明示的に渡します。
スポンサーリンク

ORA-01843とは

Oracle公式の説明では、ORA-01843は「無効な月が指定された」時のエラーです。月名を使う書式では、MONTH ならJanuaryからDecember、MON ならJanからDecのような有効な月名・略称が必要です。ただし実務では、実際に月が13になっているケースだけでなく、日付の並びやセッションのNLS設定が原因で、正しいつもりの文字列が無効な月として読まれることも多いです。

日付フォーマット全体の基本は OracleのTO_CHAR / TO_DATE日付フォーマット、近いエラーの ORA-01861ORA-01861の原因と解決方法、文字列が最後まで読めない ORA-01830ORA-01830の原因と解決方法 も参考になります。

エラー 主な意味 よくある原因
ORA-01843 月が有効な値として解釈できない 月の値、日付の並び、月名の言語が合わない
ORA-01861 文字列と書式が一致しない 区切り文字、桁数、書式モデルの不一致
ORA-01830 書式が入力文字列の途中で終わる 時刻や小数秒などの残りがある

まず確認するポイント

ORA-01843が出たら、エラーになったSQLだけでなく、実際に渡されている文字列をそのまま確認します。アプリケーション側で組み立てたSQLやバインド値は、画面上で見ている日付と違う形になっていることがあります。

確認順 見るもの 判断ポイント
1 入力文字列 2026-05-14 なのか 14/05/2026 なのかを確認
2 書式モデル YYYY-MM-DDDD/MM/YYYYMON などが入力と合うか
3 月の値 数値月が1から12の範囲か。日と月を逆に読んでいないか
4 月名の言語 MarchMAR、日本語月名などをNLSが読めるか
5 暗黙変換 DATE列と文字列を直接比較していないか

原因1: 月の値が1から12の範囲外

もっとも単純な原因は、月として読まれる部分が1から12の範囲外になっているケースです。YYYY-MM-DD の書式で 2026-13-01 を読ませると、13月は存在しないためORA-01843になります。

invalid-month-number.sql
-- NG: 13月は存在しない
SELECT TO_DATE('2026-13-01', 'YYYY-MM-DD')
FROM dual;

-- OK: 月を1から12の範囲にする
SELECT TO_DATE('2026-12-01', 'YYYY-MM-DD')
FROM dual;

アプリ側で年月日を分割して組み立てている場合は、月だけ0始まりになっていないか、日付入力欄の値をそのまま連結していないかも確認します。

原因2: DD/MM/YYYYとMM/DD/YYYYを逆に読んでいる

実務で多いのは、日と月の順番を逆に指定しているケースです。13/05/2026DD/MM/YYYY なら2026年5月13日ですが、MM/DD/YYYY として読ませると13月として扱われ、ORA-01843になります。

day-month-order.sql
-- NG: 13を月として読もうとしている
SELECT TO_DATE('13/05/2026', 'MM/DD/YYYY')
FROM dual;

-- OK: 入力が日/月/年ならDD/MM/YYYYを指定する
SELECT TO_DATE('13/05/2026', 'DD/MM/YYYY')
FROM dual;

日本の業務データでは YYYY/MM/DDYYYY-MM-DD が多い一方、外部システムやCSVでは DD/MM/YYYYMM/DD/YYYY が混ざることがあります。取り込み元ごとにフォーマットを固定するのが安全です。

原因3: 月名とNLS_DATE_LANGUAGEが合っていない

JANFebMarch のような月名を使う場合、MONMONTH の書式だけでなく、月名をどの言語として読むかも重要です。セッションの NLS_DATE_LANGUAGE と入力文字列の言語が合わないと、月名を解釈できずORA-01843になります。

month-name-language.sql
-- 英語の月名を明示的に読む
SELECT TO_DATE(
         '14-MAR-2026',
         'DD-MON-YYYY',
         'NLS_DATE_LANGUAGE=American'
       ) AS target_date
FROM dual;

-- フルスペルの月名ならMONTHを使う
SELECT TO_DATE(
         '14-March-2026',
         'DD-Month-YYYY',
         'NLS_DATE_LANGUAGE=American'
       ) AS target_date
FROM dual;

月名を含む文字列は、環境差で壊れやすい形式です。可能なら外部連携では YYYY-MM-DD のような数値だけの形式に統一し、月名を使う必要がある場合は TO_DATE の第3引数で言語を明示します。

原因4: 暗黙変換でNLS_DATE_FORMATに依存している

DATE型カラムと文字列を直接比較したり、DATE型カラムに文字列をINSERTしたりすると、Oracleが暗黙的に文字列を日付へ変換します。この時にセッションの NLS_DATE_FORMAT と文字列の形式が合わないと、ORA-01843が発生します。

implicit-conversion.sql
-- NG: 文字列が暗黙変換され、環境によってORA-01843になる
SELECT *
FROM orders
WHERE order_date >= '2026-05-14';

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

-- OK: TO_DATEで書式を明示する
SELECT *
FROM orders
WHERE order_date >= TO_DATE('2026-05-14', 'YYYY-MM-DD');

現在日時や日付型の基本は SYSDATE・SYSTIMESTAMPの違い も参考になります。日付型の値を文字列として扱い直すより、最初から日付型として比較する方が安定します。

原因5: DATE型にTO_DATEをかけている

すでにDATE型になっている列や値に対して、さらに TO_DATE をかけるとORA-01843の原因になります。TO_DATE は文字列を日付へ変換する関数です。DATE型を渡すと、OracleがいったんDATE値を文字列へ暗黙変換し、その文字列を指定した書式で読み直そうとするため、セッションの NLS_DATE_FORMAT と書式がずれた時に壊れます。

to-date-date-column.sql
-- NG: order_dateがDATE型なら、TO_DATEをかけ直さない
SELECT *
FROM orders
WHERE TO_DATE(order_date, 'YYYY-MM-DD') = DATE '2026-05-14';

-- OK: DATE型はDATE型のまま比較する
SELECT *
FROM orders
WHERE order_date >= DATE '2026-05-14'
  AND order_date <  DATE '2026-05-15';

-- OK: 時刻を切り捨てたい時だけTRUNCを使う
SELECT *
FROM orders
WHERE TRUNC(order_date) = DATE '2026-05-14';

時刻部分を無視して日付だけで比較したい場合は、文字列変換ではなく TRUNC を検討します。詳しくは OracleのTRUNC関数で日付を切り捨てる方法 にまとめています。

原因6: INSERTで日付文字列をそのまま入れている

INSERTでも同じ問題が起きます。DATE列に文字列をそのまま入れると、Oracleはセッション設定に従って暗黙変換します。開発環境では動いたSQLが、本番やバッチ実行環境でORA-01843になる典型例です。

insert-date-string.sql
-- NG: DATE列に文字列をそのまま渡している
INSERT INTO orders (order_id, order_date)
VALUES (1001, '14/05/2026');

-- OK: 入力形式に合わせて明示的に変換する
INSERT INTO orders (order_id, order_date)
VALUES (1001, TO_DATE('14/05/2026', 'DD/MM/YYYY'));

-- OK: ISO形式の日付だけならDATEリテラルも使える
INSERT INTO orders (order_id, order_date)
VALUES (1002, DATE '2026-05-14');

原因7: CSVやSQL*Loaderの日付フォーマットが合っていない

CSV取り込みやSQL*Loaderでは、ファイル内の日付形式と制御ファイル側のDATE書式がずれるとORA-01843が発生します。特に、同じファイル内に 2026-05-1414/05/2026 が混在している場合は注意が必要です。

sqlldr-date-format.ctl
LOAD DATA
INFILE 'orders.csv'
INTO TABLE orders
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
(
  order_id,
  order_date DATE "YYYY-MM-DD"
)

SQL*Loaderでの日付取り込みは Oracle SQL*Loaderの使い方 にもまとめています。取り込み前に、対象列の日付形式を1種類にそろえるか、取込前処理で正規化しておくと安定します。

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

日付変換エラーは似ていますが、原因を見る場所が少し違います。ORA-01843は月として読んだ値が無効、ORA-01861は文字列と書式が合わない、ORA-01830は書式が途中で終わる、という切り分けです。

エラー 見る場所
ORA-01843 月として読まれる部分 13/05/2026MM/DD/YYYY で読んでいる
ORA-01861 文字列と書式全体の一致 2026-05-14YYYY/MM/DD で厳密に読んでいる
ORA-01830 入力文字列の残り 2026-05-14 10:00:00YYYY-MM-DD だけで読んでいる

NLS設定を確認するSQL

環境によって再現したりしなかったりする場合は、セッションのNLS設定を確認します。特に NLS_DATE_FORMATNLS_DATE_LANGUAGENLS_TERRITORY は日付文字列の解釈に影響します。

check-nls-date-settings.sql
SELECT parameter, value
FROM nls_session_parameters
WHERE parameter IN (
  'NLS_DATE_FORMAT',
  'NLS_DATE_LANGUAGE',
  'NLS_TERRITORY'
)
ORDER BY parameter;

一時的にセッション設定を変えて確認することはできますが、アプリケーションのSQLをNLS設定前提にするのは危険です。SQLの中で日付変換を明示する、またはバインド変数でDATE/TIMESTAMP型として渡す方が再発防止になります。

修正チェックリスト

項目 確認すること 修正方針
月の値 1から12の範囲か 入力値や変換前データを修正する
日/月の順番 DD/MMMM/DD を逆にしていないか 入力に合わせて書式を直す
月名 JANMarch などを使っているか NLS_DATE_LANGUAGE を第3引数で明示する
暗黙変換 DATE列と文字列を直接比較していないか DATEリテラル、TO_DATE、バインド変数を使う
DATE型の再変換 DATE型の列に TO_DATE をかけていないか DATE型はDATE型のまま比較し、必要なら TRUNC を使う
取込データ CSV内の日付形式が混在していないか 取り込み前に形式を統一する
環境差 開発と本番のNLS設定が違わないか NLS依存のSQLを避ける

よくある質問

YYYY-MM-DDなのにORA-01843が出るのはなぜですか?

DATE列と文字列を直接比較していて、Oracleがセッションの NLS_DATE_FORMAT で暗黙変換している可能性があります。DATE '2026-05-14' または TO_DATE('2026-05-14', 'YYYY-MM-DD') のように明示してください。

月が13ではないのにORA-01843になることはありますか?

あります。たとえば 13/05/2026MM/DD/YYYY として読むと、13が月として扱われます。また、英語の月名を日本語セッションで読むなど、月名の言語不一致でも発生します。

NLS_DATE_FORMATを変えれば解決しますか?

一時的には解決することがありますが、環境依存になります。アプリケーションやバッチでは、SQL内で書式を明示するか、日付型のバインド変数として渡す方が安全です。

DATE型の列にTO_DATEを使ってはいけませんか?

基本的には使いません。TO_DATE は文字列をDATE型へ変換する関数です。DATE型の列に使うと暗黙的な文字列化が挟まるため、NLS設定によってORA-01843の原因になります。DATE型の列はDATEリテラルや日付型のバインド変数と比較してください。

MONとMONTHはどう使い分けますか?

MONJAN のような略称、MONTHJANUARY のような月名に使います。どちらも言語設定の影響を受けるため、必要に応じて NLS_DATE_LANGUAGE を明示します。

バインド変数を使えばORA-01843は避けられますか?

日付型としてバインドすれば、文字列から日付への暗黙変換を避けやすくなります。ただし、アプリ側で文字列を日付型へ変換する段階の書式チェックは必要です。

まとめ

ORA-01843は、Oracleが月部分を有効な月として解釈できない時に発生します。月が13のように範囲外になっているケースだけでなく、DD/MM/YYYYMM/DD/YYYY の取り違え、月名と NLS_DATE_LANGUAGE の不一致、DATE列と文字列の暗黙変換でも起きます。

再発を防ぐには、文字列のまま日付を扱わず、入力形式に合わせて TO_DATE を明示する、日付だけならDATEリテラルを使う、アプリケーションでは日付型のバインド変数を使う、という方針に寄せるのが安全です。

参考

ORA-01843 – Oracle Database Error Help

Format Models – Oracle SQL Language Reference