2026년 10월 25일 | DBMS Error 가이드
이 글에서 다루는 내용
22034 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
22034 more than one sql json item 는?
PostgreSQL 에러 코드 22034(more than one sql json item)는 SQL/JSON 경로 표현식(JSON Path Expression)이 단일 값을 반환해야 하는 컨텍스트에서 두 개 이상의 JSON 항목을 반환할 때 발생합니다. 주로 JSON_VALUE(), JSON_QUERY() 함수 또는 JSON 경로 연산자를 사용할 때 경로 표현식이 배열이나 복수의 객체를 탐색하여 여러 개의 결과를 만들어낼 경우 이 에러가 트리거됩니다. 실무에서는 복잡한 JSON 문서를 다루거나 와일드카드([*]) 연산자를 무분별하게 사용할 때 빈번하게 마주치는 에러입니다.
주요 발생 원인
JSON_VALUE()함수에서 배열 요소를 복수로 반환하는 경로 사용
JSON_VALUE() 함수는 반드시 스칼라 단일 값 하나만 반환해야 합니다. 그런데 JSON 경로에 배열 와일드카드 []를 사용하거나 여러 객체를 매칭하는 경로를 지정하면 복수의 값이 반환되어 에러가 발생합니다. 예를 들어, $.items[].price처럼 배열의 모든 요소를 선택하는 경로는 JSON_VALUE()와 함께 사용할 수 없습니다.
JSON_QUERY()함수에서WITHOUT WRAPPER옵션과 다중 결과 경로의 충돌
JSON_QUERY() 함수는 기본적으로 WITHOUT ARRAY WRAPPER 모드로 동작하는데, 이 상태에서 경로 표현식이 두 개 이상의 JSON 항목을 반환하면 22034 에러가 발생합니다. JSON 경로가 배열 내 여러 객체를 동시에 선택하거나, .* 연산자로 모든 키의 값을 가져오려 할 때 이 상황이 자주 발생합니다. WITH ARRAY WRAPPER 옵션을 명시적으로 지정하지 않으면 결과를 하나의 JSON 배열로 묶을 수 없어 에러로 이어집니다.
- JSON 경로 필터 표현식의 불충분한 조건으로 인한 다중 매칭
JSON 경로 필터(?() 조건식)를 사용할 때 조건이 충분히 구체적이지 않으면 여러 JSON 노드가 동시에 매칭될 수 있습니다. 예를 들어, $.orders[?(@.status == "active")]와 같은 필터는 status가 "active"인 주문이 여러 개일 경우 복수의 결과를 반환합니다. 이 결과를 단일 값을 기대하는 함수에 그대로 전달하면 22034 에러가 발생합니다.
해결 방법
원인 1 해결: 특정 인덱스를 사용하여 단일 값 선택
배열 전체를 선택하는 [*] 대신 구체적인 인덱스를 지정하여 단일 요소만 반환하도록 수정합니다.
-- 에러 발생 예시
SELECT JSON_VALUE(
'{"items": [{"price": 100}, {"price": 200}]}'::json,
'$.items[*].price' -- 복수의 값 반환으로 22034 에러 발생
);
-- 해결책 1: 특정 인덱스 지정
SELECT JSON_VALUE(
'{"items": [{"price": 100}, {"price": 200}]}'::json,
'$.items[0].price' -- 첫 번째 요소만 반환
);
-- 결과: 100
-- 해결책 2: ERROR 동작을 DEFAULT로 변경하여 안전하게 처리
SELECT JSON_VALUE(
'{"items": [{"price": 100}, {"price": 200}]}'::json,
'$.items[*].price'
DEFAULT '-1' ON ERROR -- 에러 대신 기본값 반환
);
-- 결과: -1
원인 2 해결: WITH ARRAY WRAPPER 옵션 사용
JSON_QUERY()에서 다중 결과를 다뤄야 할 경우 WITH ARRAY WRAPPER 옵션을 명시하여 모든 결과를 배열로 감싸서 반환합니다.
-- 에러 발생 예시
SELECT JSON_QUERY(
'{"products": [{"name": "A"}, {"name": "B"}, {"name": "C"}]}'::json,
'$.products[*].name' -- WITHOUT WRAPPER 기본값 상태에서 다중 반환 → 에러
);
-- 해결책: WITH ARRAY WRAPPER 옵션 추가
SELECT JSON_QUERY(
'{"products": [{"name": "A"}, {"name": "B"}, {"name": "C"}]}'::json,
'$.products[*].name'
WITH ARRAY WRAPPER -- 결과를 배열로 묶어서 반환
);
-- 결과: ["A", "B", "C"]
-- 실무 활용: 여러 값을 추출 후 집계
SELECT
order_id,
JSON_QUERY(order_data, '$.items[*].sku' WITH ARRAY WRAPPER) AS skus
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days';
원인 3 해결: 필터 조건 강화 또는 LIMIT 활용
JSON 경로 필터를 더 구체적으로 작성하거나, 여러 결과가 예상되는 경우 jsonb_path_query()를 사용하여 집합 형태로 처리합니다.
-- 에러 발생 예시 (active 주문이 여러 건인 경우)
SELECT JSON_VALUE(
'{"orders": [{"id": 1, "status": "active"}, {"id": 2, "status": "active"}]}'::json,
'$.orders[?(@.status == "active")].id'
);
-- 22034 에러 발생
-- 해결책 1: 고유 조건 추가로 단일 결과 보장
SELECT JSON_VALUE(
'{"orders": [{"id": 1, "status": "active"}, {"id": 2, "status": "active"}]}'::json,
'$.orders[?(@.status == "active" && @.id == 1)].id'
);
-- 결과: 1
-- 해결책 2: jsonb_path_query()로 집합 처리 (다중 결과 허용)
SELECT jsonb_path_query(
'{"orders": [{"id": 1, "status": "active"}, {"id": 2, "status": "active"}]}'::jsonb,
'$.orders[?(@.status == "active")].id'
) AS active_order_id;
-- 결과: 1, 2 (각각 행으로 반환)
-- 해결책 3: jsonb_path_query_first()로 첫 번째 결과만 추출
SELECT jsonb_path_query_first(
'{"orders": [{"id": 1, "status": "active"}, {"id": 2, "status": "active"}]}'::jsonb,
'$.orders[?(@.status == "active")].id'
) AS first_active_order;
-- 결과: 1
예방 방법
- JSON 경로 표현식 설계 시 반환 카디널리티를 명확히 정의하라
JSON 경로를 작성할 때부터 해당 경로가 단일 값을 반환하는지, 복수 값을 반환하는지 명확히 파악하고 적합한 함수를 선택하는 습관을 들여야 합니다. 단일 스칼라 값에는 JSON_VALUE() 또는 jsonb_path_query_first()를, 다중 결과가 예상되면 JSON_QUERY() WITH ARRAY WRAPPER 또는 jsonb_path_query()를 사용하는 원칙을 팀 코딩 컨벤션으로 정립하세요. 또한 개발 초기부터 다양한 데이터 케이스(빈 배열, 단일 요소, 복수 요소)를 테스트하여 경로 표현식의 견고성을 검증하는 것이 중요합니다.
ON ERROR절을 활용한 방어적 코딩과 입력 데이터 검증을 병행하라
프로덕션 쿼리에서는 JSON_VALUE()와 JSON_QUERY()에 반드시 ON ERROR 절(예: DEFAULT NULL ON ERROR 또는 DEFAULT '[]' ON ERROR)을 추가하여 예기치 못한 데이터 형태로 인한 에러가 전체 쿼리를 중단시키지 않도록 방어 코드를 작성하세요. 동시에, JSON 데이터를 데이터베이스에 저장하기 전 애플리케이션 레이어에서 스키마 유효성 검사를 수행하거나 PostgreSQL의 CHECK 제약 조건과 jsonb_path_exists() 함수를 결합하여 데이터 품질을 사전에 보장하는 것이 장기적으로 22034 에러를 예방하는 가장 효과적인 방법입니다.
관련 에러
- 22032 (
invalid_json_text): JSON 문자열 자체가 유효하지 않은 형식일 때 발생하며, JSON 파싱 단계에서 실패하는 경우입니다. 22034와 달리 구조는 유효하지만 값의 개수 문제가 아닌 파싱 자체의 실패입니다. - 22033 (
cannot_coerce_sql_json_array): JSON 배열을 SQL 스칼라 타입으로 직접 변환하려 할 때 발생합니다. 22034와 유사하게 단일 값 컨텍스트에서 복수/복합 JSON 구조를 다룰 때 발생한다는 공통점이 있습니다. - 22035 (
singleton_sql_json_item_required): 일부 PostgreSQL 버전 및 SQL/JSON 표준 구현에서 단일 항목이 요구되는 상황에 연관된 에러로, 22034와 밀접한 관계가 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.