2026년 10월 12일 | DBMS Error 가이드
이 글에서 다루는 내용
2202E 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2202E array subscript error 는?
PostgreSQL 에러 코드 2202E는 배열 첨자(array subscript) 사용 시 유효하지 않은 값이 제공될 때 발생하는 에러입니다. 배열의 인덱스로 사용되는 값이 NULL이거나, 정수가 아닌 값이 첨자로 사용될 경우, 또는 배열의 차원(dimension)과 맞지 않는 방식으로 접근할 때 이 에러가 트리거됩니다. 실무에서는 동적 SQL을 생성하거나, 사용자 입력값을 배열 인덱스로 활용할 때 자주 마주치는 에러입니다.
주요 발생 원인
1. 배열 첨자로 NULL 값 사용
가장 빈번하게 발생하는 원인은 배열 첨자 위치에 NULL 값이 오는 경우입니다. PostgreSQL은 배열 인덱스로 NULL을 허용하지 않으며, 이 경우 명시적인 에러를 발생시킵니다. 특히 사용자 입력값이나 외부 시스템에서 받아온 인덱스 값이 검증 없이 배열 접근에 사용될 때 자주 발생합니다.
2. 비정수형(Non-integer) 값을 첨자로 사용
PostgreSQL 배열의 첨자는 반드시 정수(integer) 타입이어야 합니다. 실수(float), 문자열(text), 또는 다른 타입의 값을 명시적 캐스팅 없이 첨자로 사용하려 하면 이 에러가 발생합니다. 예를 들어 array[2.5] 혹은 array['abc'] 형태의 접근은 PostgreSQL이 내부적으로 정수로 변환하지 못할 때 에러를 발생시킵니다.
3. 다차원 배열에서 잘못된 첨자 구조 사용
PostgreSQL은 다차원 배열을 지원하지만, 각 차원에 대한 첨자 구조를 정확히 지켜야 합니다. 2차원 배열에 1차원 첨자만 사용하거나, 반대로 1차원 배열에 2차원 접근을 시도하는 경우 첨자 에러가 발생합니다. 특히 unnest()나 array_agg() 함수로 생성된 배열을 다룰 때 차원 구조를 잘못 이해하고 접근하면 이 에러가 발생하기 쉽습니다.
해결 방법
원인 1 해결: NULL 첨자 방지
NULL 값이 배열 첨자로 유입되지 않도록 COALESCE 또는 NULLIF 함수를 활용해 사전에 방어합니다.
-- 문제 발생 예시
DO $$
DECLARE
v_arr INTEGER[] := ARRAY[10, 20, 30, 40, 50];
v_idx INTEGER := NULL; -- NULL 인덱스
v_val INTEGER;
BEGIN
-- 아래 구문은 2202E 에러 발생
v_val := v_arr[v_idx];
RAISE NOTICE 'Value: %', v_val;
END;
$$;
-- 해결 방법 1: COALESCE로 기본값 제공
DO $$
DECLARE
v_arr INTEGER[] := ARRAY[10, 20, 30, 40, 50];
v_idx INTEGER := NULL;
v_val INTEGER;
BEGIN
-- NULL이면 기본 인덱스 1을 사용
v_val := v_arr[COALESCE(v_idx, 1)];
RAISE NOTICE 'Value: %', v_val;
END;
$$;
-- 해결 방법 2: NULL 체크 후 조건 분기
DO $$
DECLARE
v_arr INTEGER[] := ARRAY[10, 20, 30, 40, 50];
v_idx INTEGER := NULL;
v_val INTEGER;
BEGIN
IF v_idx IS NULL THEN
RAISE WARNING 'Index is NULL. Skipping array access.';
ELSE
v_val := v_arr[v_idx];
RAISE NOTICE 'Value: %', v_val;
END IF;
END;
$$;
원인 2 해결: 비정수형 첨자를 정수로 명시적 캐스팅
배열 첨자에 사용되는 값이 정수형인지 확인하고, 필요시 명시적으로 캐스팅합니다.
-- 문제 발생 예시 (실수형 첨자 사용)
DO $$
DECLARE
v_arr TEXT[] := ARRAY['alpha', 'beta', 'gamma', 'delta'];
v_idx NUMERIC := 2.7; -- 실수형 인덱스
v_val TEXT;
BEGIN
-- 2202E 에러 발생 가능
v_val := v_arr[v_idx];
RAISE NOTICE 'Value: %', v_val;
END;
$$;
-- 해결 방법: FLOOR 또는 ROUND 후 INTEGER 캐스팅
DO $$
DECLARE
v_arr TEXT[] := ARRAY['alpha', 'beta', 'gamma', 'delta'];
v_idx NUMERIC := 2.7;
v_val TEXT;
BEGIN
-- FLOOR로 내림 후 INTEGER로 명시적 캐스팅
v_val := v_arr[FLOOR(v_idx)::INTEGER];
RAISE NOTICE 'Value: %', v_val; -- 'beta' 출력
END;
$$;
-- 테이블 기반 실무 예시: 외부 입력값 검증 후 배열 접근
CREATE TABLE product_categories (
id SERIAL PRIMARY KEY,
tags TEXT[],
tag_idx NUMERIC -- 외부에서 받은 인덱스 (정수 보장 안 됨)
);
INSERT INTO product_categories (tags, tag_idx)
VALUES (ARRAY['electronics', 'mobile', 'accessories'], 1.9);
-- 안전한 배열 접근 쿼리
SELECT
id,
tags,
tags[FLOOR(tag_idx)::INTEGER] AS selected_tag
FROM product_categories
WHERE tag_idx IS NOT NULL
AND FLOOR(tag_idx)::INTEGER BETWEEN 1 AND array_length(tags, 1);
원인 3 해결: 다차원 배열 첨자 구조 수정
다차원 배열에 올바른 첨자 구조를 사용하고, array_length() 또는 array_ndims()로 차원을 확인합니다.
-- 다차원 배열 구조 확인
DO $$
DECLARE
v_matrix INTEGER[][] := ARRAY[[1,2,3],[4,5,6],[7,8,9]];
BEGIN
-- 배열 차원 수 확인
RAISE NOTICE '차원 수: %', array_ndims(v_matrix);
-- 각 차원별 길이 확인
RAISE NOTICE '1차원 길이: %', array_length(v_matrix, 1);
RAISE NOTICE '2차원 길이: %', array_length(v_matrix, 2);
-- 올바른 2차원 배열 접근
RAISE NOTICE '2행 3열 값: %', v_matrix[2][3]; -- 6 출력
END;
$$;
-- 안전한 다차원 배열 접근 함수 작성
CREATE OR REPLACE FUNCTION safe_array_access(
p_arr ANYARRAY,
p_row INTEGER,
p_col INTEGER
) RETURNS TEXT AS $$
BEGIN
-- 차원 검증
IF array_ndims(p_arr) < 2 THEN
RAISE WARNING '2차원 배열이 아닙니다. 차원 수: %', array_ndims(p_arr);
RETURN NULL;
END IF;
-- 범위 검증
IF p_row < 1 OR p_row > array_length(p_arr, 1)
OR p_col < 1 OR p_col > array_length(p_arr, 2) THEN
RAISE WARNING '첨자 범위 초과: [%, %]', p_row, p_col;
RETURN NULL;
END IF;
RETURN p_arr[p_row][p_col]::TEXT;
END;
$$ LANGUAGE plpgsql;
-- 함수 사용 예시
SELECT safe_array_access(ARRAY[[1,2,3],[4,5,6]], 2, 3); -- '6' 반환
SELECT safe_array_access(ARRAY[[1,2,3],[4,5,6]], 5, 1); -- NULL 반환 (범위 초과)
예방 방법
1. 배열 접근 전 입력값 유효성 검사 함수 표준화
배열을 다루는 모든 함수와 프로시저에서 첨자 값의 유효성을 사전에 검증하는 공통 유틸리티 함수를 만들어 사용하세요. 특히 사용자 입력, API 파라미터, 외부 시스템 연동 데이터처럼 신뢰하기 어려운 값이 배열 인덱스로 사용될 경우 반드시 검증 레이어를 추가해야 합니다.
-- 배열 첨자 유효성 검사 공통 함수
CREATE OR REPLACE FUNCTION validate_array_subscript(
p_subscript ANYELEMENT,
p_arr_length INTEGER
) RETURNS BOOLEAN AS $$
BEGIN
-- NULL 체크
IF p_subscript IS NULL THEN
RETURN FALSE;
END IF;
-- 정수 범위 체크
IF p_subscript::INTEGER < 1 OR p_subscript::INTEGER > p_arr_length THEN
RETURN FALSE;
END IF;
RETURN TRUE;
END;
$$ LANGUAGE plpgsql;
2. EXCEPTION 블록으로 배열 에러 핸들링
PL/pgSQL 코드 내에서 배열을 다루는 블록에는 반드시 EXCEPTION 절을 추가하여 2202E 에러를 포함한 배열 관련 에러를 안전하게 처리하세요. 에러 발생 시 로그를 남기고, 비즈니스 로직이 중단되지 않도록 기본값을 반환하는 패턴을 표준으로 정착시키는 것이 좋습니다.
DO $$
DECLARE
v_arr INTEGER[] := ARRAY[1, 2, 3];
v_idx INTEGER := NULL;
v_val INTEGER;
BEGIN
v_val := v_arr[v_idx];
RAISE NOTICE 'Value: %', v_val;
EXCEPTION
WHEN SQLSTATE '2202E' THEN
RAISE WARNING '[2202E] 배열 첨자 에러 발생. 기본값 0으로 대체합니다.';
v_val := 0;
WHEN OTHERS THEN
RAISE WARNING '예기치 않은 에러: % - %', SQLSTATE, SQLERRM;
v_val := 0;
END;
$$;
관련 에러
2202(array_subscript_error):2202E의 상위 카테고리 에러 클래스로, 배열 첨자와 관련된 모든 에러를 포괄합니다.2202D(invalid_row_count_in_result_offset_clause): 결과 오프셋 절에서의 유효하지 않은 행 수 에러로, 배열 슬라이싱 작업과 유사한 맥락에서 발생할 수 있습니다.42703(undefined_column): 동적 SQL에서 배열 컬럼을 잘못 참조할 때 함께 나타나는 경우가 있습니다.22P02(invalid_text_representation): 문자열을 배열 첨자 정수로 변환할 때 형식이 잘못된 경우 발생하며,2202E와 혼동될 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.