2026년 08월 30일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-06531 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-06531 Reference to uninitialized collection 는?
ORA-06531 에러는 PL/SQL에서 컬렉션(Collection) 타입 변수를 선언만 하고 초기화(Initialize)하지 않은 상태에서 해당 변수를 참조하거나 조작하려 할 때 발생하는 에러입니다. Oracle에서 컬렉션 타입인 VARRAY, Nested Table, Associative Array(Index-By Table) 등을 사용할 때, 변수를 선언한 것만으로는 메모리가 할당되지 않으며 반드시 생성자(Constructor)를 통해 초기화해야 합니다. 초기화되지 않은 컬렉션은 NULL 상태로 존재하며, 이 상태에서 EXTEND, COUNT, FIRST, LAST 등의 컬렉션 메서드를 호출하거나 인덱스로 접근하면 ORA-06531이 발생합니다.
주요 발생 원인
1. 컬렉션 변수 선언 후 생성자 호출 없이 바로 사용
가장 흔한 원인으로, VARRAY 또는 Nested Table 타입의 변수를 선언한 뒤 생성자(Constructor)를 호출하지 않고 곧바로 EXTEND나 인덱스 접근을 시도하는 경우입니다. PL/SQL에서 컬렉션 변수는 선언 직후 자동으로 NULL 상태가 되며, 이는 빈 컬렉션(Empty Collection)과는 전혀 다른 개념이므로 반드시 명시적 초기화가 필요합니다.
2. 조건문 분기에 따라 초기화가 누락되는 경우
복잡한 비즈니스 로직에서 IF-THEN-ELSE 또는 CASE 문으로 분기 처리를 할 때, 특정 조건 분기에서만 컬렉션을 초기화하고 다른 분기에서는 초기화를 누락하는 경우가 있습니다. 이후 코드에서 컬렉션을 공통으로 사용할 때, 초기화되지 않은 분기를 타면 에러가 발생하며 이런 경우 디버깅이 까다롭습니다.
3. 서브프로그램(함수/프로시저) 내에서 OUT 파라미터 초기화 누락
프로시저나 함수의 OUT 또는 IN OUT 파라미터로 컬렉션 타입을 사용할 때, 서브프로그램 내부에서 파라미터를 초기화하지 않고 사용하거나, 호출자(Caller) 측에서 초기화하지 않은 변수를 넘기는 경우에도 발생합니다. 특히 OUT 파라미터는 서브프로그램 진입 시 NULL로 초기화되므로, 서브프로그램 내에서 반드시 생성자를 사용해 초기화해야 합니다.
해결 방법
원인 1 해결: 생성자(Constructor)를 이용한 명시적 초기화
컬렉션을 선언한 직후, 또는 사용하기 전에 반드시 생성자를 호출하여 초기화합니다.
-- 잘못된 예시 (ORA-06531 발생)
DECLARE
TYPE num_list IS TABLE OF NUMBER;
v_numbers num_list;
BEGIN
v_numbers.EXTEND; -- ORA-06531 발생!
v_numbers(1) := 100;
END;
/
-- 올바른 예시 (생성자로 초기화)
DECLARE
TYPE num_list IS TABLE OF NUMBER;
v_numbers num_list;
BEGIN
v_numbers := num_list(); -- 빈 컬렉션으로 초기화
v_numbers.EXTEND; -- 정상 동작
v_numbers(1) := 100;
DBMS_OUTPUT.PUT_LINE('Value: ' || v_numbers(1));
END;
/
-- VARRAY 초기화 예시
DECLARE
TYPE varchar_array IS VARRAY(5) OF VARCHAR2(50);
v_names varchar_array;
BEGIN
v_names := varchar_array('Alice', 'Bob', 'Charlie'); -- 값과 함께 초기화
DBMS_OUTPUT.PUT_LINE('First: ' || v_names(1));
DBMS_OUTPUT.PUT_LINE('Count: ' || v_names.COUNT);
END;
/
원인 2 해결: 조건 분기 전 사전 초기화
모든 분기에서 컬렉션이 초기화되도록, 분기문 진입 전에 미리 초기화하거나 각 분기마다 초기화 코드를 추가합니다.
-- 잘못된 예시 (특정 분기에서 초기화 누락)
DECLARE
TYPE emp_list IS TABLE OF VARCHAR2(100);
v_employees emp_list;
v_dept_id NUMBER := 20;
BEGIN
IF v_dept_id = 10 THEN
v_employees := emp_list('King', 'Blake');
END IF;
-- v_dept_id = 20이면 초기화 안 됨 -> ORA-06531 발생!
DBMS_OUTPUT.PUT_LINE('Count: ' || v_employees.COUNT);
END;
/
-- 올바른 예시 (분기 전 사전 초기화)
DECLARE
TYPE emp_list IS TABLE OF VARCHAR2(100);
v_employees emp_list := emp_list(); -- 선언 시점에 초기화
v_dept_id NUMBER := 20;
BEGIN
IF v_dept_id = 10 THEN
v_employees := emp_list('King', 'Blake');
ELSIF v_dept_id = 20 THEN
v_employees := emp_list('Jones', 'Ford', 'Smith');
END IF;
-- 초기화 여부를 방어적으로 체크
IF v_employees IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE('Count: ' || v_employees.COUNT);
FOR i IN 1 .. v_employees.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Employee: ' || v_employees(i));
END LOOP;
ELSE
DBMS_OUTPUT.PUT_LINE('No employees found.');
END IF;
END;
/
원인 3 해결: OUT 파라미터 컬렉션 초기화
OUT 파라미터로 전달되는 컬렉션은 서브프로그램 내부에서 반드시 초기화합니다.
-- 컬렉션 타입 정의 (패키지 또는 스키마 레벨)
CREATE OR REPLACE TYPE num_table IS TABLE OF NUMBER;
/
-- 잘못된 프로시저 예시
CREATE OR REPLACE PROCEDURE get_dept_ids_bad (
p_dept_ids OUT num_table
) IS
BEGIN
-- p_dept_ids 초기화 없이 바로 EXTEND -> ORA-06531 발생!
p_dept_ids.EXTEND;
p_dept_ids(1) := 10;
END;
/
-- 올바른 프로시저 예시
CREATE OR REPLACE PROCEDURE get_dept_ids_good (
p_dept_ids OUT num_table
) IS
BEGIN
p_dept_ids := num_table(); -- OUT 파라미터 초기화
-- BULK COLLECT로 데이터 적재 (권장 방식)
SELECT department_id
BULK COLLECT INTO p_dept_ids
FROM departments
WHERE rownum <= 5;
DBMS_OUTPUT.PUT_LINE('Total departments: ' || p_dept_ids.COUNT);
END;
/
-- 호출 예시
DECLARE
v_ids num_table;
BEGIN
get_dept_ids_good(v_ids);
FOR i IN 1 .. v_ids.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Dept ID: ' || v_ids(i));
END LOOP;
END;
/
NULL 체크를 활용한 방어적 코딩
-- IS NOT NULL 체크로 초기화 여부 확인
DECLARE
TYPE str_list IS TABLE OF VARCHAR2(200);
v_list str_list;
BEGIN
-- 안전하게 사용하기 위한 NULL 체크
IF v_list IS NULL THEN
v_list := str_list();
DBMS_OUTPUT.PUT_LINE('Collection was NULL. Initialized now.');
END IF;
v_list.EXTEND(3);
v_list(1) := 'Oracle';
v_list(2) := 'PL/SQL';
v_list(3) := 'Collection';
FOR i IN v_list.FIRST .. v_list.LAST LOOP
DBMS_OUTPUT.PUT_LINE(i || ': ' || v_list(i));
END LOOP;
END;
/
예방 방법
1. 컬렉션 변수는 선언 시점에 즉시 초기화하는 코딩 컨벤션 수립
팀 내 PL/SQL 코딩 표준을 정의할 때, 컬렉션 타입 변수는 반드시 선언부(DECLARE 섹션)에서 생성자를 호출하여 초기화하도록 규칙을 정합니다. 예를 들어 v_list emp_list := emp_list();와 같이 선언과 동시에 빈 컬렉션으로 초기화하면, 이후 코드에서 초기화 여부를 신경 쓰지 않아도 되어 실수를 원천적으로 방지할 수 있습니다. 코드 리뷰 체크리스트에도 컬렉션 초기화 항목을 추가하여 정적 분석 단계에서 걸러낼 수 있도록 합니다.
2. 컬렉션 사용 전 IS NULL 조건 방어 코드 삽입 및 단위 테스트 작성
외부에서 전달받거나 복잡한 로직을 거친 컬렉션 변수를 사용하기 전에, 반드시 IF v_collection IS NULL THEN v_collection := collection_type(); END IF; 형태의 방어 코드를 삽입하는 습관을 들입니다. 또한 컬렉션을 사용하는 PL/SQL 프로그램에 대해 utPLSQL 등의 단위 테스트 프레임워크를 활용하여 초기화 관련 엣지 케이스(Edge Case)를 테스트 케이스로 작성하면, 릴리즈 전에 이러한 문제를 조기에 발견할 수 있습니다.
관련 에러
- ORA-06530: Reference to uninitialized composite — 초기화되지 않은 복합 타입(Object Type 등)을 참조할 때 발생하며, ORA-06531과 유사한 맥락의 에러입니다.
- ORA-06532: Subscript outside of limit — VARRAY에서 정의된 최대 크기를 초과하는 인덱스로 접근할 때 발생합니다.
- ORA-06533: Subscript beyond count — 컬렉션에 실제 존재하는 요소 수를 초과하는 인덱스로 접근할 때 발생합니다.
- ORA-01403: No data found — BULK COLLECT 없이 INTO 절을 사용할 때 데이터가 없으면 발생하며, 컬렉션 처리 로직에서 함께 자주 등장하는 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.