본문 바로가기
IT

ORA-06502 PL/SQL: numeric or value error — PL/SQL 수치·값 오류 에러 원인·해결·예방

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

 

ORA-06502는 PL/SQL 블록에서 변수 할당이나 연산 시 데이터 타입·길이·범위가 맞지 않을 때 발생하는 가장 흔한 런타임 에러다. VARCHAR2 변수에 선언 길이보다 긴 문자열을 넣거나, NUMBER 변수에 정밀도를 초과하는 값을 넣거나, TO_NUMBER가 변환 불가능한 문자열을 만났을 때 즉시 던져진다. SQL 레벨의 ORA-01438, ORA-01722와 형제 격이지만 발생 위치가 PL/SQL이라는 점이 다르다. 본 글은 ORA-06502의 정확한 의미, 두 가지 주요 하위 메시지, 일곱 가지 발생 원인, 진단 흐름, 그리고 %TYPE·VALUE_ERROR·DEFAULT NULL ON CONVERSION ERROR까지 실전 해결 패턴을 정리한다.

ORA-06502

 

한눈에 보기
에러 의미 / PL/SQL 변수 할당·연산·변환에서 타입·길이·범위 위반
주요 원인 / VARCHAR2 버퍼 부족, CHAR 패딩 초과, NUMBER 정밀도, TO_NUMBER 실패, NOT NULL 위반, PLS_INTEGER 오버플로, CONCAT 결과 초과
근본 해법%TYPE 선언, 입력 검증, VALUE_ERROR 예외, DEFAULT NULL ON CONVERSION ERROR

목차

01ORA-06502 정확한 의미와 두 가지 하위 메시지
02발생 원인 일곱 가지
03재현 시나리오 — PL/SQL 블록별 예시
04진단 — FORMAT_ERROR_BACKTRACE와 라인 식별
05해결 방법 — %TYPE, VALUE_ERROR, 12c 변환 옵션
06ORA-01438·ORA-01722·ORA-06512 인접 에러 구분
Q&A자주 묻는 질문 5선
07예방 체크리스트와 결론
01 / ORA-06502의 정확한 의미
오라클 공식 메시지는 "PL/SQL: numeric or value error[: string]"이며, 한국어로는 "PL/SQL: 수치 또는 값 오류"로 표시된다. 뒤에 붙는 부가 문자열이 실제 원인을 알려준다.

가장 자주 보이는 두 가지 하위 메시지는 다음과 같다.

"character string buffer too small" ━ VARCHAR2·CHAR 변수의 선언 길이가 할당하려는 값보다 작음
"numeric or value error" ━ 숫자 변환 실패 또는 NUMBER 정밀도 초과

오라클 공식 원인 설명은 "산술, 숫자, 문자열, 변환, 또는 제약 조건 오류가 발생함"이다. 즉 PL/SQL이 변수에 값을 넣거나 연산을 수행하는 순간 데이터 타입·길이·범위·NULL 가능성 같은 제약이 깨졌다는 광범위한 신호다.

1. ORA-06502가 던져지는 시점

ORA-06502는 PL/SQL 런타임에서만 발생한다. SQL 단독 실행에서는 비슷한 상황이 ORA-01438, ORA-01722, ORA-12899 같은 SQL 레벨 에러로 표현된다. 대표적인 트리거 시점은 다음과 같다.

  • 변수 선언 후 첫 할당 ━ 길이·범위 위반
  • 계산 결과 할당 ━ NUMBER 정밀도, PLS_INTEGER 범위 초과
  • TO_NUMBER, TO_DATE ━ 변환 실패
  • CONCAT ━ 결과가 대상 버퍼 초과
  • NOT NULL 변수에 NULL 대입
  • 컬렉션/레코드 필드 할당 ━ 내부 필드에서 동일 검증

2. 발생 원인 일곱 가지

원인 1 / VARCHAR2 선언 길이 부족

가장 흔한 케이스다. 변수 선언 시 추정한 길이보다 실제 값이 길 때 발생한다.

-- VARCHAR2(5)에 6자리 문자열 → ORA-06502
DECLARE
  v VARCHAR2(5);
BEGIN
  v := 'ABCDEF';
END;
/
-- ORA-06502: PL/SQL: numeric or value error:
--           character string buffer too small

원인 2 / CHAR 패딩 후 CONCAT 초과

CHAR 타입은 선언 길이만큼 공백 패딩된다. CHAR(5)에 'A'를 넣으면 'A '로 저장된다. 이 패딩이 CONCAT 결과를 의외로 길게 만들어 버퍼를 넘긴다.

-- CHAR(5) 자동 패딩 함정
DECLARE
  a CHAR(5) := 'A';     -- 실제 저장: 'A    '
  b CHAR(5) := 'B';
  v VARCHAR2(9);
BEGIN
  v := a || b;                -- 'A    B    ' = 10자 → 초과
END;
/

원인 3 / TO_NUMBER 변환 실패

비숫자 문자열을 TO_NUMBER로 변환하면 발생한다. SQL 레벨에서는 ORA-01722지만 PL/SQL 변수에 할당하는 시점이면 ORA-06502다.

-- 비숫자 문자열 변환 → ORA-06502
DECLARE
  n NUMBER;
BEGIN
  n := TO_NUMBER('Yes');
END;
/

원인 4 / NUMBER 정밀도 초과

NUMBER(p)·NUMBER(p,s)로 선언한 변수에 정밀도를 넘는 값을 할당하면 발생한다.

-- NUMBER(3)에 4자리 → ORA-06502
DECLARE
  n NUMBER(3);
BEGIN
  n := 4321;
END;
/

원인 5 / NOT NULL 변수에 NULL 대입

PL/SQL 변수에 NOT NULL 제약을 걸 수 있다. 그 변수에 NULL을 대입하면 ORA-06502가 발생한다.

DECLARE
  n NUMBER(4) NOT NULL := 10;
BEGIN
  n := NULL;
END;
/

원인 6 / PLS_INTEGER 오버플로

PLS_INTEGER는 32비트 부호 있는 정수다. 범위는 -2,147,483,648 ~ 2,147,483,647이며, 연산 결과가 이를 넘으면 ORA-06502가 발생한다.

-- PLS_INTEGER 오버플로
DECLARE
  a PLS_INTEGER := 2147483647;
BEGIN
  a := a + 1;
END;
/
-- ORA-06502

대안으로 SIMPLE_INTEGER가 있다. 같은 32비트지만 오버플로 시 wrap-around 되어 예외가 발생하지 않는다. 단 NULL 불가다.

원인 7 / 컬렉션 인덱스/필드 위반

연관 배열의 인덱스가 키 도메인을 벗어나거나, 레코드의 NOT NULL 필드에 NULL이 들어가는 경우 등 컬렉션·레코드 내부에서도 같은 검증이 작동한다.

3. 재현 시나리오 종합

다섯 가지 케이스를 한 번에 보여주는 PL/SQL 블록은 다음과 같다.

-- 버퍼 초과
DECLARE v VARCHAR2(5); BEGIN v := 'ABCDEF'; END;

-- 정밀도 초과
DECLARE n NUMBER(3); BEGIN n := 4321; END;

-- 변환 실패
DECLARE n NUMBER; BEGIN n := TO_NUMBER('abc'); END;

-- NOT NULL 위반
DECLARE n NUMBER NOT NULL := 1;
BEGIN n := NULL; END;

-- PLS_INTEGER 오버플로
DECLARE a PLS_INTEGER := 2147483647;
BEGIN a := a + 1; END;

4. 진단 — 정확한 위치 찾기

ORA-06502 메시지만으로는 어느 줄에서 어떤 변수가 문제였는지 알기 어렵다. PL/SQL 백트레이스 함수로 정확한 위치를 추출한다.

-- 진단 블록 템플릿
DECLARE
  v VARCHAR2(5);
BEGIN
  v := 'ABCDEF';
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('SQLCODE: '||SQLCODE);
    DBMS_OUTPUT.PUT_LINE('SQLERRM: '||SQLERRM);
    DBMS_OUTPUT.PUT_LINE('STACK: '||
      DBMS_UTILITY.FORMAT_ERROR_STACK);
    DBMS_OUTPUT.PUT_LINE('BACKTRACE: '||
      DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;
/

FORMAT_ERROR_BACKTRACE는 예외가 발생한 정확한 라인 번호를 알려준다. 단 RAISE로 예외를 재발생시키면 백트레이스가 그 지점부터 다시 시작하므로 원본 라인이 손실된다. PLSQL_OPTIMIZE_LEVEL=3(인라이닝)에서도 라인 번호가 부정확할 수 있으므로 디버깅 중에는 일시적으로 2 이하로 낮추는 것이 좋다.

디버깅 흐름
ORA-06502가 발생하면 다음 순서로 확인한다. 첫째, FORMAT_ERROR_BACKTRACE로 예외 발생 라인을 추출한다. 둘째, 해당 라인에서 좌변(변수)의 선언 길이·타입을 확인한다. 셋째, 우변(값) 길이·타입을 확인하고 차이를 좁힌다. 넷째, 입력이 외부 데이터라면 입력 검증을 추가한다. 다섯째, 정밀도·범위 문제라면 변수 타입을 더 큰 범위로 변경하거나 %TYPE로 컬럼과 일치시킨다.

5. 해결 방법

패턴 A / %TYPE으로 컬럼 일치

테이블 컬럼 값을 받는 변수는 반드시 %TYPE으로 선언한다. 컬럼 정의가 바뀌어도 자동으로 따라간다.

-- 컬럼 정의를 그대로 따름
DECLARE
  v_name emp.ename%TYPE;
  v_sal  emp.sal%TYPE;
BEGIN
  SELECT ename, sal INTO v_name, v_sal
  FROM   emp WHERE empno = 7369;
END;
/

패턴 B / VALUE_ERROR 예외 처리

ORA-06502는 사전 정의 예외 VALUE_ERROR로 catch할 수 있다. 변환·할당이 실패해도 흐름이 중단되지 않도록 처리한다.

DECLARE
  v_input VARCHAR2(20) := '1.5e10x';
  v_num   NUMBER;
BEGIN
  v_num := TO_NUMBER(v_input);
EXCEPTION
  WHEN VALUE_ERROR THEN
    v_num := NULL;
    DBMS_OUTPUT.PUT_LINE('변환 실패, NULL로 처리');
END;
/

패턴 C / 12c+ DEFAULT NULL ON CONVERSION ERROR

Oracle 12c 이후 TO_NUMBER·TO_DATE·CAST에 변환 실패 시 기본값을 반환하는 옵션이 추가됐다. 예외 없이 NULL을 받아 흐름을 그대로 진행할 수 있다.

-- 변환 실패 시 NULL 반환 (12c+)
DECLARE
  n NUMBER;
BEGIN
  n := TO_NUMBER('abc' DEFAULT NULL ON CONVERSION ERROR);
  -- n = NULL, 예외 없음
END;
/

패턴 D / 사전 검증

REGEXP·길이 검사로 변환 전에 형식을 점검한다. 디버깅이 쉽고 비즈니스 의미 메시지를 줄 수 있다.

-- TO_NUMBER 전 정규식 검증
DECLARE
  v_input VARCHAR2(20) := '1234.56';
  v_num   NUMBER;
BEGIN
  IF REGEXP_LIKE(v_input, '^-?\d+(\.\d+)?$') THEN
    v_num := TO_NUMBER(v_input);
  ELSE
    RAISE_APPLICATION_ERROR(-20001, '유효한 숫자 형식이 아님');
  END IF;
END;
/

패턴 E / 정밀도·범위 여유

NUMBER 정밀도는 꼭 필요한 경우가 아니면 지정하지 않는다. PLS_INTEGER 대신 INTEGER, NUMBER, 또는 SIMPLE_INTEGER(랩어라운드 허용) 사용을 검토한다.

-- 정밀도 없는 NUMBER는 사실상 무제한
DECLARE
  n NUMBER := 99999999999;
BEGIN
  n := n * 100;            -- 안전
END;
/

-- 카운터에 PLS_INTEGER 대신 NUMBER 사용
DECLARE
  cnt NUMBER := 0;
BEGIN
  FOR i IN 1..10000000 LOOP
    cnt := cnt + 1;
  END LOOP;
END;
/

6. 인접 에러와의 구분

ORA-06502는 SQL 레벨 형제와 PL/SQL 스택 추적 에러가 있다.

에러 코드 발생 레벨 전형적 시나리오
ORA-06502 PL/SQL 변수 할당·연산 버퍼 부족, 정밀도, 변환 실패
ORA-01438 SQL 컬럼 INSERT/UPDATE NUMBER(p,s) 컬럼 정밀도 초과
ORA-01722 SQL 변환 SELECT 등에서 비숫자 → NUMBER
ORA-12899 SQL 문자열 컬럼 VARCHAR2 컬럼 길이 초과 INSERT
ORA-06512 PL/SQL 스택 트레이스 "at line N" — 발생 위치 동반
ORA-01426 PL/SQL 산술 오버플로 NUMERIC_OVERFLOW 예외

핵심 구분 ━ 06502는 PL/SQL 변수 측, 01438·01722·12899는 SQL 측, 06512는 06502 등의 발생 라인을 알려주는 동반 표시 에러다.

Q & A — 자주 묻는 다섯 가지
Q1. ORA-06502와 함께 표시되는 ORA-06512는 무슨 관계인가요?
ORA-06512는 PL/SQL 스택 트레이스를 알려주는 부가 메시지다. "at line N" 또는 "at package.procedure, line N" 형태로 06502가 발생한 정확한 위치를 보여 준다. 두 에러가 항상 짝으로 출력되며, 06512의 라인 번호가 진짜 디버깅 시작점이다.

Q2. %TYPE을 모든 변수에 써도 되나요?
권장 패턴이다. 컬럼 변경 시 코드를 다시 컴파일하지 않아도 따라가므로 유지보수가 쉽다. 단점은 컴파일 의존성이 늘어 컬럼 변경 시 패키지가 INVALID 상태로 전환된다는 점이며, 자동 재컴파일로 대부분 해결된다.

Q3. PLS_INTEGER와 NUMBER의 성능 차이는 큰가요?
PLS_INTEGER는 하드웨어 정수 연산을 사용해 NUMBER보다 빠르다. 루프 카운터·인덱스 등 단순 정수 연산에는 PLS_INTEGER가 유리하다. 단 오버플로 가능성이 있으면 NUMBER 또는 SIMPLE_INTEGER(랩어라운드 허용)를 고려한다.

Q4. SIMPLE_INTEGER는 언제 쓰나요?
NULL이 들어올 수 없고 오버플로를 무시할 수 있는 카운터·해시 계산 등에 적합하다. 컴파일러가 NULL 검사와 오버플로 검사를 모두 생략해 PLS_INTEGER보다도 빠르다. 단점은 NULL 불가, 오버플로 시 wrap-around로 잘못된 결과 가능.

Q5. DEFAULT NULL ON CONVERSION ERROR는 모든 변환 함수에 쓸 수 있나요?
12c부터 TO_NUMBER, TO_DATE, TO_TIMESTAMP, TO_BINARY_FLOAT, TO_BINARY_DOUBLE, CAST가 지원한다. TO_CHAR 등 출력 변환에는 적용되지 않는다. 입력 검증·변환 실패에 NULL을 허용해도 무방한 모든 시나리오에서 매우 유용하다.

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

ORA-06502는 변수 선언과 입력 검증을 신중히 다루면 거의 차단할 수 있다. 다음 항목을 점검한다.

예방 체크리스트
  • 테이블 컬럼 값을 받는 변수는 %TYPE 또는 %ROWTYPE
  • 일반 문자열 변수는 가변 길이 VARCHAR2(4000) 권장, CHAR는 피함
  • NUMBER는 정밀도 불필요시 미지정으로 선언
  • 외부 입력은 TO_NUMBER·TO_DATE 전 REGEXP·길이 검증
  • 12c 이상이면 DEFAULT NULL ON CONVERSION ERROR 활용
  • VALUE_ERROR 예외 핸들러 표준화 (에러 로그 + 의미 있는 응답)
  • PLS_INTEGER 사용 시 오버플로 가능성 사전 검토, 큰 범위는 NUMBER
  • 디버깅 중 FORMAT_ERROR_BACKTRACE 활용, PLSQL_OPTIMIZE_LEVEL 2 이하

ORA-06502는 "값과 변수의 약속이 깨졌다"는 단순한 신호다. PL/SQL이 컴파일 시점에 모든 길이·범위를 보장할 수 없으므로 런타임에 그 약속을 검사하다 발견한 위반이다. 답은 두 가지로 압축된다 ━ 변수 선언을 명확하고 충분히 크게, 입력 검증을 명시적으로. %TYPE으로 컬럼과 일치시키고, 외부 입력은 변환 전 검증하고, VALUE_ERROR로 예외 흐름을 끊지 않도록 하면 ORA-06502는 더 이상 갑작스러운 장애가 아닌 예측 가능한 신호가 된다.

 

#ORA06502 #numericorvalueerror #오라클에러 #PLSQL #VARCHAR2 #NUMBER #PLSINTEGER #VALUEERROR #TOTYPE #백트레이스 #ORA01438 #ORA01722 #ORA06512 #PL_SQL예외 #PL_SQL디버깅

반응형

댓글