본문 바로가기
IT

ORA-01843 not a valid month — 월 값 부적합 에러 원인·해결·예방

by 샤나엘 2026. 5. 19.
반응형

ORA-01843은 오라클이 문자열을 날짜로 변환할 때 월(month) 값이 유효하지 않다고 판단할 때 발생한다. 1~12 범위를 벗어나거나, MON·MONTH 마스크와 세션 언어가 맞지 않아 월 이름을 인식하지 못할 때 던져진다. ORA-01861이 "구조가 안 맞다"고 알려주는 1차 방어선이라면, ORA-01843은 "값이 잘못됐다"고 알려주는 2차 방어선이다. 한국어 세션이 기본인 국내 환경에서는 영문 약어 MON 마스크 사용 시 매우 흔히 마주친다. 본 글은 ORA-01843의 정확한 의미, 다섯 가지 원인, 진단 흐름, 그리고 NLS에 의존하지 않는 견고한 해결 패턴까지 정리한다.

ORA-01843

 

한눈에 보기
 
에러 의미 / 문자열 → 날짜 변환에서 월 값이 1~12 범위를 벗어나거나, MON·MONTH 마스크와 세션 언어 불일치
주요 원인 / MM 13 이상, MON/MONTH + 언어 불일치, NLS 암시적 변환, 구분자 위치 혼동, NLS_TERRITORY 영향
근본 해법 / TO_DATE 3번째 인자 NLS_DATE_LANGUAGE=AMERICAN, ANSI DATE '2026-05-15' 리터럴

목차

01ORA-01843 정확한 의미와 에러 메시지
02발생 원인 다섯 가지 (범위·언어·NLS·구분자·TERRITORY)
03재현 시나리오 — 한국어 세션에서 영문 MON 파싱
04해결 방법 — NLS_DATE_LANGUAGE, DATE 리터럴, 바인드 변수
05ORA-01861·ORA-01847·ORA-01839 인접 에러 구분
Q&A자주 묻는 질문 5선
06예방 체크리스트와 결론
01 / ORA-01843의 정확한 의미
오라클 공식 메시지는 "not a valid month" ━ 한국어로는 "지정한 월이 부적합합니다"이다. 11g부터 23ai까지 변경 없이 유지된다. 원인 설명은 "월 부분이 유효 범위(1~12)를 벗어났거나, 월 이름이 현재 NLS_DATE_LANGUAGE에서 인식되지 않음"이다.

ORA-01843은 값(value) 검증에 걸린 에러다. ORA-01861이 "글자 수·구분자 자체가 안 맞다"는 구조 검증에 걸리는 반면, ORA-01843은 구조는 통과했지만 안에 들어 있는 월 값이 잘못된 경우다. 예를 들어 '2026-13-01''YYYY-MM-DD' 조합은 구조는 맞지만 13월이라는 값이 부적합해서 ORA-01843이 발생한다.

1. ORA-01843이 던져지는 두 가지 경로

ORA-01843이 발생하는 경로는 크게 두 가지다.

경로 A / 숫자 월이 범위를 벗어남

MM, MON이 아닌 숫자 마스크에서 1~12 밖의 값이 들어왔을 때다. 13, 0, 99 같은 명백한 오류가 여기 해당한다.

경로 B / MON·MONTH 마스크가 세션 언어와 불일치

MON, MONTH 마스크는 텍스트 기반이고, 그 텍스트는 세션의 NLS_DATE_LANGUAGE 설정을 따른다. 한국어 세션은 1월, 2월을 기대하고, 영어 세션은 JAN, FEB를 기대한다. 입력 문자열과 세션 언어가 어긋나면 오라클은 월 이름을 인식하지 못해 ORA-01843을 던진다.

국내 운영 환경에서 흔히 마주치는 패턴은 경로 B다. 시스템 NLS가 KOREAN으로 설정돼 있는데 데이터나 코드는 영어 약어를 사용하는 경우가 많기 때문이다.

2. 발생 원인 다섯 가지

원인 1 / 월 값 범위 초과

가장 단순한 경우다. 입력 데이터 자체가 잘못된 월 값을 담고 있다.

-- 13월 → ORA-01843
SELECT TO_DATE('2026-13-01', 'YYYY-MM-DD') FROM dual;

-- 00월 → ORA-01843
SELECT TO_DATE('2026-00-15', 'YYYY-MM-DD') FROM dual;

대부분은 데이터 정제 단계에서 걸러야 할 사례다. ETL 파이프라인이나 입력 폼 검증에서 1~12 범위 체크를 추가하면 사전 차단된다.

원인 2 / MON·MONTH 마스크와 NLS_DATE_LANGUAGE 불일치

국내 환경에서 가장 빈번한 원인이다. 한국어 세션에서 영문 약어를 파싱하려고 하면 즉시 실패한다.

-- 세션이 한국어인 상태
ALTER SESSION SET NLS_DATE_LANGUAGE = 'KOREAN';

-- 한국어 세션은 'JAN'을 모름 → ORA-01843
SELECT TO_DATE('15-JAN-26', 'DD-MON-YY') FROM dual;

-- 한국어 세션은 '1월'을 기대 → 성공
SELECT TO_DATE('15-1월 -26', 'DD-MON-YY') FROM dual;

반대 방향도 마찬가지다. 영어 세션에서 한국어 월 이름을 파싱하면 같은 에러가 발생한다.

원인 3 / NLS 암시적 변환 차이

문자열을 직접 DATE 컬럼과 비교하거나 INSERT하면 오라클은 세션 NLS_DATE_FORMAT을 사용해 자동으로 TO_DATE를 호출한다. 이때 적용되는 마스크가 DD-MON-RR처럼 MON을 포함한 형식이면, 입력 문자열이 영문 약어를 갖고 있어야 한다.

-- 세션 NLS_DATE_FORMAT이 'DD-MON-RR'인 환경
INSERT INTO emp(hire_date) VALUES ('15-05-2026');
-- 오라클: TO_DATE('15-05-2026', 'DD-MON-RR') → MON 자리에 '05' → ORA-01843

원인 4 / 구분자 위치 혼동

마스크와 입력의 구분자 위치는 같지만, 어느 자리가 일·월·연도인지 해석이 어긋날 때 발생한다.

-- 입력은 DD-MM-YYYY인데 마스크는 MM-DD-YYYY
SELECT TO_DATE('15-05-2026', 'MM-DD-YYYY') FROM dual;
-- 오라클: 월=15 → ORA-01843

구조 검사(ORA-01861)는 통과한다. 길이도 같고 구분자 위치도 같기 때문이다. 하지만 첫 번째 숫자 15가 월로 해석되면서 값 검사에서 걸린다.

원인 5 / NLS_TERRITORY 변경 영향

NLS_TERRITORY를 바꾸면 그에 따라 NLS_DATE_FORMAT 기본값도 함께 바뀐다. KOREA → RR/MM/DD, AMERICA → DD-MON-RR, JAPAN → RR-MM-DD처럼 영토마다 다르다. 같은 데이터를 다른 영토 세션에서 처리하면 형식이 어긋난다.

-- TERRITORY 변경 시 NLS_DATE_FORMAT도 자동 변경
ALTER SESSION SET NLS_TERRITORY = 'AMERICA';
-- 이제 기본 마스크는 DD-MON-RR

SELECT TO_DATE('15/05/2026') FROM dual;
-- DD-MON-RR로 해석 시도 → MON 자리 '05' → ORA-01843

3. 재현 시나리오 — 환경 의존 실패

다음 SQL은 세션 언어에 따라 결과가 갈린다.

-- 케이스 A: 영어 세션
ALTER SESSION SET NLS_DATE_LANGUAGE = 'AMERICAN';
SELECT TO_DATE('15-JAN-26', 'DD-MON-YY') FROM dual;
-- 성공: 2026-01-15

-- 케이스 B: 한국어 세션
ALTER SESSION SET NLS_DATE_LANGUAGE = 'KOREAN';
SELECT TO_DATE('15-JAN-26', 'DD-MON-YY') FROM dual;
-- ORA-01843

NLS 상태는 다음 쿼리로 확인한다.

-- 현재 세션 NLS_DATE_LANGUAGE
SELECT parameter, value
FROM nls_session_parameters
WHERE parameter IN ('NLS_DATE_FORMAT',
                  'NLS_DATE_LANGUAGE',
                  'NLS_TERRITORY');

-- 사용 가능한 언어 값 조회
SELECT value
FROM v$nls_valid_values
WHERE parameter = 'LANGUAGE'
ORDER BY value;
디버깅 흐름
 
ORA-01843이 발생하면 다음 순서로 확인한다. 첫째, 변환에 사용된 마스크에 MON·MONTH가 포함돼 있는지 확인한다. 포함됐다면 NLS_DATE_LANGUAGE와 입력 문자열의 언어가 일치하는지 본다. 둘째, 마스크가 숫자 기반이라면 입력의 월 자리가 1~12 범위 안인지 확인한다. 셋째, 암시적 변환이 일어나는 위치(INSERT, WHERE 비교)를 모두 찾아 명시적 TO_DATE로 바꾼다. 넷째, 환경 간 차이가 의심되면 NLS_SESSION_PARAMETERS를 운영·개발 사이에서 비교한다.

4. 해결 방법 — 세 가지 패턴

패턴 A / TO_DATE 3번째 인자로 언어 강제

MON·MONTH 마스크를 꼭 써야 한다면 TO_DATE의 세 번째 인자에 NLS 옵션을 명시한다. 세션 NLS와 무관하게 항상 같은 동작이 보장된다.

-- 세션 NLS와 무관하게 영어 월 이름 파싱
SELECT TO_DATE('15-JAN-26', 'DD-MON-YY',
               'NLS_DATE_LANGUAGE=AMERICAN') FROM dual;

-- 한국어 월 이름 파싱
SELECT TO_DATE('15-1월 -26', 'DD-MON-YY',
               'NLS_DATE_LANGUAGE=KOREAN') FROM dual;

패턴 B / MON 대신 MM 사용

월을 약어가 아닌 숫자로 표현할 수 있다면 MM 마스크가 가장 안전하다. 언어 의존이 완전히 사라진다.

-- 숫자 월 → NLS 영향 없음
SELECT TO_DATE('2026-05-15', 'YYYY-MM-DD') FROM dual;
SELECT TO_DATE('15/05/2026', 'DD/MM/YYYY') FROM dual;

패턴 C / ANSI DATE 리터럴

상수 값이면 ANSI 표준 DATE 리터럴이 가장 견고하다. NLS·언어·영토 어느 것에도 영향받지 않는다.

-- ANSI DATE 리터럴 (NLS 무관)
SELECT DATE '2026-05-15' FROM dual;

-- WHERE 절에도 사용 가능
SELECT * FROM emp
WHERE hire_date >= DATE '2026-01-01'
  AND hire_date < DATE '2027-01-01';

패턴 D / 애플리케이션 바인드 변수

자바·파이썬·.NET 같은 애플리케이션에서는 문자열로 넘기지 말고 드라이버의 Date/Timestamp 타입으로 바인딩한다. 드라이버가 직접 DATE 타입으로 전송하므로 NLS 의존이 완전히 사라진다.

// Java JDBC 예시
PreparedStatement pstmt = conn.prepareStatement(
    "INSERT INTO emp(emp_id, hire_date) VALUES (?, ?)");
pstmt.setInt(1, 1001);
pstmt.setDate(2, java.sql.Date.valueOf("2026-05-15"));
pstmt.executeUpdate();

5. 인접 에러와의 구분

ORA-01843은 형제 격 에러가 여럿 있다. 메시지는 비슷해도 검사 단계가 다르다.

에러 코드 검사 대상 전형적 입력
ORA-01843 월 값 범위·이름 '2026-13-01' 또는 한국어 세션에 'JAN'
ORA-01861 구조 불일치 '2026/05/15' + 'YYYY-MM-DD'
ORA-01847 일 값이 월 범위 초과 '2026-02-31'
ORA-01839 월에 대한 일 부적합 2025-02-29 같은 비윤년 2/29
ORA-01830 마스크가 리터럴보다 짧음 '2026-05-15 14:30' + 'YYYY-MM-DD'
ORA-01840 리터럴이 마스크보다 짧음 '2026-5' + 'YYYY-MM-DD'

이 그룹의 에러는 모두 같은 해법 패턴을 공유한다 ━ TO_DATE를 명시하고, 마스크와 리터럴을 정확히 맞추고, NLS·언어 의존을 제거하고, 가능하면 ANSI 리터럴이나 바인드 변수로 전환한다.

Q & A — 자주 묻는 다섯 가지
Q1. 한국어 세션에서 MON을 꼭 써야 하는데 어떻게 하나요?
TO_DATE의 세 번째 인자에 'NLS_DATE_LANGUAGE=AMERICAN'을 명시하면 세션 NLS와 무관하게 영어 월 이름을 파싱할 수 있다. 함수 호출마다 추가해야 해 번거롭지만 가장 안전한 방법이다.

Q2. NLS_DATE_LANGUAGE 값 목록은 어디서 확인하나요?
SELECT value FROM v$nls_valid_values WHERE parameter='LANGUAGE'로 조회한다. AMERICAN, KOREAN, JAPANESE, SIMPLIFIED CHINESE, GERMAN, FRENCH 등 70여 종이 등록돼 있다.

Q3. 같은 SQL이 어제는 됐는데 오늘 ORA-01843이 발생합니다.
세션 NLS_DATE_LANGUAGE 또는 NLS_TERRITORY가 바뀌었을 가능성이 가장 높다. 클라이언트 OS 로케일 변경, JDBC URL 옵션 변경, 커넥션 풀 init SQL 변경이 흔한 원인이다. NLS_SESSION_PARAMETERS를 비교하면 즉시 드러난다.

Q4. 데이터 적재 시 1~12 범위 검증은 어디서 하는 게 좋나요?
1차는 애플리케이션 입력 검증, 2차는 DB 레벨 CHECK 제약 또는 트리거다. CHECK 제약을 두면 잘못된 값이 DATE 컬럼이 아니라 NUMBER 컬럼으로 들어올 때도 차단된다. 다만 DATE 컬럼은 오라클이 자동으로 1~12 검증을 하므로, CHECK는 별도 월 컬럼이 있을 때만 의미가 있다.

Q5. 23ai에서도 같은 동작인가요?
ORA-01843의 메시지와 동작은 11g부터 23ai까지 동일하다. 19.4~19.8 버전에서 일부 패치 회귀로 일시적 오작동 사례가 있었으나 19.9 이후 안정화됐다. 클라우드 환경(ATP·ADW)에서도 동일하게 동작한다.

6. 예방 체크리스트와 결론

ORA-01843은 마스크 선택과 NLS 명시화로 거의 100% 차단할 수 있다. 새 쿼리·새 모듈·새 데이터 파이프라인을 만들 때 다음 항목을 점검한다.

예방 체크리스트
  • 가능한 한 MON·MONTH 대신 MM 숫자 마스크 사용 (언어 의존 제거)
  • MON·MONTH 사용 시 TO_DATE 3번째 인자로 NLS_DATE_LANGUAGE 명시
  • 모든 문자열 → 날짜 변환에 TO_DATE 명시 (암시적 변환 차단)
  • 상수 값은 ANSI DATE 'YYYY-MM-DD' 리터럴 사용
  • 커넥션 풀 초기 SQL에서 NLS_DATE_LANGUAGE·NLS_DATE_FORMAT 명시
  • 애플리케이션은 Date·Timestamp 타입으로 바인딩 (문자열 금지)
  • ETL 파이프라인에 월 값 1~12 검증 단계 포함
  • 운영·개발·테스트 환경의 NLS_SESSION_PARAMETERS 동기화

ORA-01843은 단순히 "월이 13이다"라는 명백한 입력 오류뿐 아니라, NLS_DATE_LANGUAGE라는 보이지 않는 세션 상태에 의존하는 코드를 드러내는 경고다. 한국어 환경이 기본인 국내 운영에서는 영문 약어 MON 마스크가 위험 신호가 된다. 해법은 단순하다 ━ MM을 쓰거나, TO_DATE 3번째 인자로 언어를 강제하거나, ANSI 리터럴로 전환한다. 세 가지 중 하나만 일관되게 적용해도 ORA-01843은 다시 만날 일이 거의 없는 에러가 된다.

 

#ORA01843 #notavalidmonth #오라클에러 #NLSDATELANGUAGE #NLS #MON #MONTH #TO_DATE #날짜형식 #한국어세션 #DATE리터럴 #ORA01861 #ORA01847 #ORA01839 #SQL날짜

반응형

댓글