PostgreSQL 22034 오류 원인과 해결 방법 완벽 가이드

22034
2026년 06월 17일 | DBMS Error 가이드

이 글에서 다루는 내용

22034 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

22034 more than one sql json item 는?

PostgreSQL 에러 코드 22034more than one sql json item이라는 메시지로 발생하며, JSON 경로 표현식(JSON Path Expression)이 단일 값을 반환해야 하는 컨텍스트에서 복수의 항목을 반환할 때 발생합니다. 주로 JSON_VALUE(), JSON_QUERY() 등의 SQL/JSON 함수가 경로 표현식의 결과로 둘 이상의 JSON 항목을 만났을 때 트리거됩니다. 이 에러는 PostgreSQL 15 이상에서 SQL 표준 JSON 함수들이 도입되면서 실무에서 점점 더 자주 접하게 되는 오류입니다.


주요 발생 원인

1. JSON_VALUE() 함수에서 배열 경로가 복수 결과를 반환하는 경우

JSON_VALUE() 함수는 반드시 스칼라(단일) 값 하나만 반환해야 합니다. JSON 데이터 내에 배열이 존재하고, 그 배열의 모든 요소를 참조하는 경로(예: $[] 또는 $.items[].name)를 사용하면 복수의 결과가 생성되어 이 에러가 발생합니다. 실무에서는 JSON 구조를 충분히 파악하지 않고 와일드카드 경로를 무분별하게 사용할 때 빈번히 발생합니다.

2. JSON_QUERY() 함수에서 WITH WRAPPER 옵션 없이 복수 항목 조회 시

JSON_QUERY() 함수 역시 기본 동작에서는 단일 JSON 객체 또는 배열을 반환해야 합니다. JSON 경로가 여러 개의 독립적인 값(예: 배열의 각 원소들)을 동시에 선택할 경우, WITH ARRAY WRAPPER 옵션 없이 사용하면 22034 에러가 발생합니다. 이 경우 반환되는 항목들을 하나의 JSON 배열로 묶어주는 처리가 필요합니다.

3. JSON_TABLE() 없이 중첩 배열 구조를 단순 경로로 탐색하는 경우

중첩된 JSON 배열 구조(예: 배열 안에 또 다른 배열)를 JSON_VALUE()JSON_QUERY()로 단순 경로 탐색하면 복수의 항목이 반환될 수 있습니다. 복잡한 중첩 구조에서는 경로의 각 단계마다 복수 결과 가능성이 증폭되므로, 이를 적절히 처리하는 함수 선택이 매우 중요합니다.


해결 방법

원인 1 해결: 배열 인덱스를 명시하거나 집계 함수 활용

복수 결과를 반환하는 경로 대신, 특정 인덱스를 지정하거나 ERROR ON ERROR / NULL ON ERROR 동작 절을 명시적으로 설정합니다.

-- 문제가 되는 쿼리 (22034 에러 발생)
SELECT JSON_VALUE('{"items": ["apple", "banana", "cherry"]}', '$.items[*]');

-- 해결책 1: 특정 인덱스 지정
SELECT JSON_VALUE('{"items": ["apple", "banana", "cherry"]}', '$.items[0]');
-- 결과: "apple"

-- 해결책 2: NULL ON ERROR 로 에러 억제 (값이 필요없을 때)
SELECT JSON_VALUE(
    '{"items": ["apple", "banana", "cherry"]}',
    '$.items[*]'
    NULL ON ERROR
);
-- 결과: NULL

-- 해결책 3: 첫 번째 값만 필요한 경우 명시적으로 first 사용
SELECT JSON_VALUE(
    '{"items": ["apple", "banana", "cherry"]}',
    'strict $.items[0]'
);

원인 2 해결: JSON_QUERY()에서 WITH ARRAY WRAPPER 사용

JSON_QUERY() 함수에서 복수의 결과를 하나의 JSON 배열로 감싸서 반환하도록 WITH ARRAY WRAPPER 옵션을 사용합니다.

-- 문제가 되는 쿼리 (22034 에러 발생)
SELECT JSON_QUERY('{"scores": [95, 87, 76]}', '$.scores[*]');

-- 해결책: WITH ARRAY WRAPPER 옵션 추가
SELECT JSON_QUERY(
    '{"scores": [95, 87, 76]}',
    '$.scores[*]'
    WITH ARRAY WRAPPER
);
-- 결과: [95, 87, 76]

-- 실무 예: 테이블 컬럼에서 활용
CREATE TABLE user_data (
    user_id  INT,
    profile  JSONB
);

INSERT INTO user_data VALUES
(1, '{"name": "Alice", "tags": ["admin", "editor", "viewer"]}'),
(2, '{"name": "Bob",   "tags": ["viewer"]}');

-- 각 사용자의 태그 목록을 JSON 배열로 추출
SELECT
    user_id,
    JSON_QUERY(profile::json, '$.tags[*]' WITH ARRAY WRAPPER) AS all_tags
FROM user_data;

원인 3 해결: JSON_TABLE() 또는 jsonb_array_elements() 활용

복잡한 중첩 배열 구조는 JSON_TABLE() 또는 PostgreSQL 고유 함수인 jsonb_array_elements()를 사용하여 행(row) 단위로 언패킹합니다.

-- 복잡한 중첩 JSON 데이터
WITH sample_data AS (
    SELECT '{
        "orders": [
            {"id": 1, "items": ["book", "pen"]},
            {"id": 2, "items": ["laptop", "mouse", "keyboard"]}
        ]
    }'::jsonb AS doc
)

-- 잘못된 접근 (22034 에러 발생 가능)
-- SELECT JSON_VALUE(doc::json, '$.orders[*].id') FROM sample_data;

-- 해결책 1: jsonb_array_elements() 활용 (PostgreSQL 전통 방식)
SELECT
    (order_item->>'id')::INT   AS order_id,
    order_item->'items'        AS order_items
FROM sample_data,
     jsonb_array_elements(doc->'orders') AS order_item;

-- 해결책 2: JSON_TABLE() 활용 (PostgreSQL 17+, SQL 표준)
SELECT *
FROM sample_data,
     JSON_TABLE(
         doc,
         '$.orders[*]'
         COLUMNS (
             order_id   INT    PATH '$.id',
             item_count INT    PATH '$.items.size()'
         )
     ) AS jt;

-- jsonb_path_query() 로 복수 결과를 집합으로 처리
SELECT
    user_id,
    jsonb_path_query(profile, '$.tags[*]') AS tag
FROM user_data;

예방 방법

1. JSON 경로 작성 시 반환 카디널리티를 항상 검증하라

실제 운영 데이터에 배포하기 전, jsonb_path_query_array() 또는 jsonb_path_query_first()로 경로 표현식이 반환하는 결과 수를 사전에 확인하는 습관을 가지세요. JSON_VALUE()나 단일 결과를 기대하는 함수에 경로를 전달하기 전, 아래처럼 검증 쿼리를 먼저 실행하는 것이 Best Practice입니다.

-- 경로가 반환하는 항목 수 사전 확인
SELECT jsonb_array_length(
    jsonb_path_query_array(
        '{"items": ["apple", "banana", "cherry"]}'::jsonb,
        '$.items[*]'
    )
);
-- 결과가 1보다 크면 JSON_VALUE() 사용 불가 → JSON_QUERY(WITH ARRAY WRAPPER) 또는 jsonb_path_query() 사용

2. ERROR ON ERROR / NULL ON ERROR 동작 절을 명시적으로 지정하라

SQL/JSON 함수를 사용할 때는 항상 에러 발생 시 동작을 명시적으로 선언하세요. 기본값에 의존하지 않고 NULL ON ERROR를 지정하면 예기치 않은 에러로 인한 쿼리 전체 실패를 방지할 수 있으며, 로그에서 문제를 추적하기도 용이해집니다. 특히 JSON 스키마가 불규칙하거나 외부에서 유입되는 데이터를 다룰 때 필수적인 습관입니다.

-- 방어적 코딩: 에러 발생 시 NULL 반환
SELECT JSON_VALUE(
    your_json_column::json,
    '$.some.path[*]'
    NULL ON ERROR
    NULL ON EMPTY
)
FROM your_table;

관련 에러

  • 22033 (invalid sql json subscript): JSON 경로에서 잘못된 배열 인덱스나 서브스크립트를 사용할 때 발생하며, 경로 문법 오류와 함께 22034와 유사한 맥락에서 접하게 됩니다.
  • 22032 (invalid json text): JSON 데이터 자체가 유효하지 않은 형식일 때 발생하며, JSON 파싱 단계에서 22034 이전에 먼저 마주칠 수 있는 에러입니다.
  • 22035 (no sql json item): 22034의 반대 상황으로, JSON 경로 표현식이 아무런 항목도 반환하지 못할 때 발생합니다. EMPTY ON EMPTY 옵션으로 제어 가능합니다.
  • 2203A (sql json scalar required): JSON_VALUE()가 스칼라가 아닌 객체나 배열을 반환하려 할 때 발생하며, 22034와 함께 JSON 함수 설계 시 주의해야 할 연관 에러입니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기