2026년 10월 24일 | DBMS Error 가이드
이 글에서 다루는 내용
22031 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
22031 invalid argument for sql json datetime function 는?
PostgreSQL 에러 코드 22031은 SQL/JSON 경로 표현식에서 날짜/시간 관련 함수(예: .datetime(), .date(), .time(), .timestamp() 등)를 사용할 때, 함수에 전달된 인자 또는 처리하려는 값이 유효하지 않을 경우 발생합니다. 이 에러는 주로 JSON 데이터 내의 날짜/시간 문자열 형식이 ISO 8601 표준을 따르지 않거나, 잘못된 포맷 템플릿이 지정되었을 때 트리거됩니다. PostgreSQL 12 이상에서 SQL/JSON 기능이 확장되면서 이 에러를 접하는 DBA 및 개발자가 꾸준히 늘고 있으며, 올바른 원인 파악과 수정이 중요합니다.
주요 발생 원인
1. JSON 내 날짜/시간 문자열이 ISO 8601 형식이 아닌 경우
가장 흔한 원인입니다. PostgreSQL의 SQL/JSON datetime() 함수는 기본적으로 ISO 8601 형식(YYYY-MM-DD, YYYY-MM-DDTHH:MI:SS 등)을 기대합니다. 예를 들어 "2024/07/15" 또는 "15-07-2024" 같이 슬래시나 다른 구분자를 사용한 날짜 문자열은 파싱에 실패하여 이 에러를 발생시킵니다. 외부 시스템에서 적재된 JSON 데이터에서 특히 자주 발생하므로, 데이터 유입 시점부터 형식을 검증하는 것이 중요합니다.
2. datetime() 함수에 잘못된 포맷 템플릿을 지정한 경우
PostgreSQL 14 이상에서는 datetime(template) 형태로 사용자 정의 포맷 템플릿을 지정할 수 있습니다. 그러나 템플릿 문자열이 PostgreSQL의 to_timestamp() 또는 to_date() 포맷 규칙에 맞지 않거나, 존재하지 않는 포맷 패턴을 사용하면 이 에러가 발생합니다. 예를 들어 Oracle 스타일의 포맷(YYYY/MM/DD)을 그대로 입력하면 PostgreSQL에서 인식하지 못하는 경우가 있습니다. 이 경우 PostgreSQL 공식 포맷 패턴 목록을 반드시 참고해야 합니다.
3. JSON 값이 null이거나 날짜/시간이 아닌 다른 타입인 경우
datetime() 함수가 적용되는 JSON 경로의 결과값이 문자열이 아닌 숫자, 불리언, 배열, 또는 SQL NULL인 경우에도 이 에러가 발생할 수 있습니다. JSON 데이터 구조가 예상과 다르거나, 특정 키가 없는 레코드가 섞여 있을 때 자주 나타납니다. 이를 방지하려면 datetime() 함수를 호출하기 전에 반드시 값의 존재 여부와 타입을 검증해야 합니다.
해결 방법
원인 1 해결: ISO 8601 형식으로 변환 후 처리
JSON 내 날짜 문자열이 비표준 형식일 경우, jsonb_path_query 등을 사용하기 전에 문자열을 표준 형식으로 변환하거나, SQL 레벨에서 정규화해야 합니다.
-- 잘못된 예: 슬래시 구분자 사용 → 에러 발생
SELECT jsonb_path_query(
'{"event_date": "2024/07/15"}',
'$.event_date.datetime()'
);
-- ERROR: 22031: invalid argument for sql json datetime function
-- 해결: replace()로 형식 정규화 후 처리
SELECT to_date(
replace(data->>'event_date', '/', '-'),
'YYYY-MM-DD'
)
FROM (
SELECT '{"event_date": "2024/07/15"}'::jsonb AS data
) t;
-- 올바른 ISO 8601 형식 사용 예
SELECT jsonb_path_query(
'{"event_date": "2024-07-15"}',
'$.event_date.datetime()'
);
-- 결과: "2024-07-15" (date 타입으로 반환)
-- timestamp 형식 올바른 예
SELECT jsonb_path_query(
'{"created_at": "2024-07-15T10:30:00"}',
'$.created_at.datetime()'
);
원인 2 해결: 올바른 PostgreSQL 포맷 템플릿 사용
-- 잘못된 템플릿 예 (에러 발생 가능)
SELECT jsonb_path_query(
'{"dt": "15/07/2024"}',
'$.dt.datetime("DD/MM/YYYY")' -- PostgreSQL 14+ 템플릿 문법
);
-- 올바른 PostgreSQL 포맷 패턴 적용
-- PostgreSQL의 to_date 포맷 규칙을 그대로 따름
SELECT jsonb_path_query(
'{"dt": "15/07/2024"}',
'$.dt.datetime("DD/MM/YYYY")'
);
-- 템플릿 없이 표준 ISO 형식으로 저장 후 사용하는 것이 가장 안전
SELECT jsonb_path_query(
'{"dt": "2024-07-15T10:30:00+09:00"}',
'$.dt.datetime()'
);
-- 다양한 datetime 파생 함수 사용 예
SELECT
jsonb_path_query('{"ts": "2024-07-15T10:30:00"}', '$.ts.datetime()') AS full_ts,
jsonb_path_query('{"ts": "2024-07-15"}', '$.ts.date()') AS date_only,
jsonb_path_query('{"ts": "10:30:00"}', '$.ts.time()') AS time_only;
원인 3 해결: 값 존재 여부 및 타입 사전 검증
-- 문제 상황: 일부 레코드에 event_date 키가 없거나 null인 경우
WITH sample_data AS (
SELECT jsonb_column FROM (
VALUES
('{"event_date": "2024-07-15"}'::jsonb),
('{"event_date": null}'::jsonb),
('{"other_field": "abc"}'::jsonb)
) t(jsonb_column)
)
-- 안전하지 않은 쿼리 (에러 발생 가능)
-- SELECT jsonb_path_query(jsonb_column, '$.event_date.datetime()') FROM sample_data;
-- 안전한 쿼리: 존재 여부와 타입 검증 후 처리
SELECT
jsonb_column,
CASE
WHEN jsonb_column ? 'event_date'
AND jsonb_column->>'event_date' IS NOT NULL
AND (jsonb_column->>'event_date') ~ '^\d{4}-\d{2}-\d{2}'
THEN jsonb_path_query_first(
jsonb_column,
'$.event_date.datetime()'
)::text
ELSE NULL
END AS parsed_date
FROM sample_data;
-- jsonb_path_query_array + 필터링 활용
SELECT jsonb_path_query_first(
'{"records": [{"dt":"2024-07-15"}, {"dt":null}, {"dt":"2024-08-01"}]}',
'$.records[*] ? (@.dt != null).dt.datetime()'
);
예방 방법
1. 데이터 유입 시점에 날짜 형식 표준화 강제
JSON 데이터를 PostgreSQL에 저장하기 전, 애플리케이션 레이어 또는 ETL 파이프라인에서 날짜/시간 값을 반드시 ISO 8601 형식으로 변환하는 정책을 수립하세요. 또한 CHECK 제약 조건이나 트리거를 활용해 비표준 형식 데이터가 DB에 적재되는 것을 원천 차단하는 것이 Best Practice입니다.
-- CHECK 제약 조건으로 날짜 형식 강제 (예시)
CREATE TABLE events (
id SERIAL PRIMARY KEY,
data JSONB,
CONSTRAINT chk_event_date_format CHECK (
data->>'event_date' IS NULL
OR (data->>'event_date') ~ '^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2})?'
)
);
2. SQL/JSON 경로 표현식 사용 시 방어적 쿼리 작성
datetime() 관련 함수를 사용할 때는 항상 값의 존재 여부와 형식을 사전에 검증하는 방어적 패턴을 코드 표준으로 채택하세요. jsonb_path_exists()나 정규식을 활용한 사전 필터링, jsonb_path_query_first()의 NULL 반환 특성을 적극 활용하면 예기치 않은 에러를 크게 줄일 수 있습니다.
-- 방어적 쿼리 패턴 예시
SELECT id, data
FROM events
WHERE jsonb_path_exists(data, '$.event_date ? (@ like_regex "^\\d{4}-\\d{2}-\\d{2}")')
AND jsonb_path_query_first(data, '$.event_date.datetime()') IS NOT NULL;
관련 에러
- 22007 (invalid_datetime_format): 날짜/시간 문자열을
to_date(),to_timestamp()등 일반 PostgreSQL 함수로 변환할 때 형식이 맞지 않을 경우 발생합니다. 22031과 유사하지만 SQL/JSON 경로 함수 외부에서 발생한다는 차이가 있습니다. - 22P02 (invalid_text_representation): 문자열을 날짜/시간 타입으로 CAST할 때 형식이 완전히 잘못된 경우 발생합니다.
'abc'::date와 같은 상황에서 볼 수 있습니다. - 22003 (numeric_value_out_of_range): 날짜/시간 값이 PostgreSQL이 허용하는 범위를 초과할 때 발생하며, SQL/JSON 파싱 과정에서도 간접적으로 연관될 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.