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

22005
2026년 08월 09일 | DBMS Error 가이드

이 글에서 다루는 내용

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

22005 error in assignment 는?

PostgreSQL 에러 코드 22005: error in assignment는 SQL 구문에서 특정 컬럼이나 변수에 값을 할당(assignment)할 때, 해당 값의 데이터 타입이 대상 타입과 호환되지 않거나 암묵적 변환(implicit cast)이 불가능할 경우 발생하는 에러입니다. 주로 INSERT, UPDATE, SET 구문 또는 PL/pgSQL 블록 내부에서 변수에 값을 대입할 때 자주 등장합니다. 이 에러는 단순한 타입 불일치 문제처럼 보이지만, 실무에서는 애플리케이션 로직의 오류나 스키마 변경 이후 발생하는 경우가 많아 정확한 원인 파악이 중요합니다.


주요 발생 원인

1. 데이터 타입 불일치로 인한 암묵적 캐스팅 실패

가장 흔한 원인은 컬럼 또는 변수의 데이터 타입과 할당하려는 값의 타입이 서로 맞지 않아 PostgreSQL이 자동으로 변환을 시도하지만 실패하는 경우입니다. 예를 들어 INTEGER 타입의 컬럼에 'abc'와 같은 문자열을 직접 삽입하거나, DATE 타입 컬럼에 포맷이 잘못된 날짜 문자열을 넣으려고 할 때 이 에러가 발생합니다. PostgreSQL은 엄격한 타입 시스템을 갖추고 있어 명시적으로 캐스팅하지 않으면 대부분의 타입 간 자동 변환을 허용하지 않습니다.

2. PL/pgSQL 함수 또는 프로시저 내부의 변수 할당 오류

PL/pgSQL 코드 블록에서 변수를 선언할 때 지정한 타입과 실제 할당되는 값의 타입이 불일치할 경우 22005 에러가 발생합니다. 특히 SELECT INTO 구문을 사용하여 쿼리 결과를 변수에 담을 때, 반환되는 컬럼의 타입이 변수 타입과 다르면 에러가 발생할 수 있습니다. 함수 내부에서는 에러 메시지가 추상적으로 출력되는 경우가 많아, RAISE NOTICE를 활용한 디버깅이 필요합니다.

3. 도메인(Domain) 타입 또는 커스텀 타입에 대한 잘못된 값 할당

PostgreSQL의 도메인(Domain)은 기본 타입 위에 추가적인 제약조건(CHECK constraint)을 정의한 사용자 정의 타입입니다. 도메인 타입이 정의된 컬럼에 도메인의 제약조건을 위반하는 값을 할당하려 할 때 이 에러가 발생하기도 합니다. 또한 ENUM 타입이나 복합 타입(Composite Type)에 잘못된 값을 넣으려는 시도도 동일한 에러를 유발할 수 있어, 커스텀 타입 사용 시 각별한 주의가 필요합니다.


해결 방법

원인 1 해결: 명시적 타입 캐스팅 사용

타입 불일치 문제는 명시적 CAST를 사용하거나 PostgreSQL의 :: 연산자를 활용하여 해결할 수 있습니다.

-- 문제 상황: INTEGER 컬럼에 문자열 삽입 시도
CREATE TABLE sample_table (
    id      SERIAL PRIMARY KEY,
    score   INTEGER,
    reg_date DATE
);

-- 에러 발생 예시
INSERT INTO sample_table (score, reg_date)
VALUES ('abc', '2024-13-45');  -- 22005: error in assignment

-- 해결책 1: 올바른 타입의 값으로 수정
INSERT INTO sample_table (score, reg_date)
VALUES (95, '2024-06-15');

-- 해결책 2: 명시적 캐스팅 사용 (문자열 -> 정수)
INSERT INTO sample_table (score, reg_date)
VALUES (CAST('95' AS INTEGER), CAST('2024-06-15' AS DATE));

-- 해결책 3: PostgreSQL :: 연산자 사용
INSERT INTO sample_table (score, reg_date)
VALUES ('95'::INTEGER, '2024-06-15'::DATE);

-- 해결책 4: UPDATE 시 명시적 캐스팅
UPDATE sample_table
SET score = '100'::INTEGER
WHERE id = 1;

원인 2 해결: PL/pgSQL 변수 타입 확인 및 수정

PL/pgSQL 함수에서 변수 선언 타입과 할당 값의 타입을 일치시키거나, %TYPE 속성을 활용하여 동적으로 타입을 맞추는 방법을 사용합니다.

-- 문제 상황: 변수 타입 불일치
CREATE OR REPLACE FUNCTION get_user_score(p_user_id INTEGER)
RETURNS TEXT AS $$
DECLARE
    v_score INTEGER;   -- INTEGER로 선언
    v_result TEXT;
BEGIN
    -- score 컬럼이 NUMERIC(5,2) 타입이라면 할당 시 에러 발생 가능
    SELECT score INTO v_score
    FROM sample_table
    WHERE id = p_user_id;

    v_result := '점수: ' || v_score::TEXT;
    RETURN v_result;

EXCEPTION
    WHEN OTHERS THEN
        RAISE NOTICE 'Error Code: %, Message: %', SQLSTATE, SQLERRM;
        RETURN NULL;
END;
$$ LANGUAGE plpgsql;

-- 해결책: %TYPE을 사용하여 컬럼 타입 자동 참조
CREATE OR REPLACE FUNCTION get_user_score_fixed(p_user_id INTEGER)
RETURNS TEXT AS $$
DECLARE
    -- 테이블 컬럼 타입을 자동으로 참조
    v_score sample_table.score%TYPE;
    v_result TEXT;
BEGIN
    SELECT score INTO v_score
    FROM sample_table
    WHERE id = p_user_id;

    IF NOT FOUND THEN
        RETURN '사용자를 찾을 수 없습니다.';
    END IF;

    v_result := '점수: ' || v_score::TEXT;
    RETURN v_result;
END;
$$ LANGUAGE plpgsql;

-- 함수 실행 테스트
SELECT get_user_score_fixed(1);

원인 3 해결: 도메인 타입 및 ENUM 타입 값 검증

-- 도메인 타입 정의 예시
CREATE DOMAIN positive_score AS INTEGER
    CHECK (VALUE >= 0 AND VALUE <= 100);

CREATE TABLE exam_result (
    student_id  INTEGER,
    score       positive_score
);

-- 에러 발생: 도메인 범위 초과
INSERT INTO exam_result (student_id, score)
VALUES (1, 150);  -- 22005 또는 23514 에러 발생

-- 해결책: 도메인 정의 확인 후 유효한 값 사용
INSERT INTO exam_result (student_id, score)
VALUES (1, 95);  -- 정상 삽입

-- ENUM 타입 문제 해결
CREATE TYPE status_type AS ENUM ('active', 'inactive', 'pending');

CREATE TABLE user_status (
    user_id INTEGER,
    status  status_type
);

-- 에러 발생: ENUM에 없는 값 할당
INSERT INTO user_status (user_id, status)
VALUES (1, 'deleted');  -- 22005 에러

-- 해결책: 유효한 ENUM 값 사용
INSERT INTO user_status (user_id, status)
VALUES (1, 'inactive');

-- ENUM에 새 값 추가가 필요한 경우
ALTER TYPE status_type ADD VALUE 'deleted';

-- 이후 삽입 가능
INSERT INTO user_status (user_id, status)
VALUES (2, 'deleted');

예방 방법

1. 스키마 설계 시 타입 일관성 유지 및 입력 유효성 검사 레이어 구축

데이터베이스 스키마를 설계할 때부터 컬럼 타입을 명확히 정의하고, 애플리케이션 레이어와 DB 레이어 모두에서 입력값에 대한 유효성 검사를 수행하는 이중 방어 전략을 채택해야 합니다. 특히 외부 API나 사용자 입력을 직접 DB에 넣는 경우, 데이터가 DB에 도달하기 전에 타입 검증을 반드시 수행해야 합니다. 또한 PL/pgSQL 함수 작성 시 변수 선언에 %TYPE%ROWTYPE을 적극 활용하면, 스키마 변경 시에도 타입 불일치 에러를 방지할 수 있습니다.

-- 예방을 위한 CHECK 제약조건과 도메인 활용 예시
CREATE DOMAIN valid_email AS TEXT
    CHECK (VALUE ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$');

CREATE TABLE users (
    user_id     SERIAL PRIMARY KEY,
    email       valid_email NOT NULL,
    age         INTEGER CHECK (age >= 0 AND age <= 150),
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

2. 개발 및 스테이징 환경에서 엄격한 타입 검사 설정 및 테스트 자동화

pg_stat_statements와 같은 도구를 활용하여 프로덕션 환경에서 실제로 실행되는 쿼리를 모니터링하고, CI/CD 파이프라인에서 DB 스키마 변경 시 회귀 테스트(regression test)를 자동화하는 것이 좋습니다. pgTAP 같은 PostgreSQL용 테스트 프레임워크를 도입하면 스키마와 함수의 타입 일관성을 자동으로 검증할 수 있습니다.

-- pgTAP을 활용한 타입 검증 테스트 예시
SELECT plan(3);

SELECT has_table('public', 'users', 'users 테이블이 존재해야 함');
SELECT col_type_is('public', 'users', 'age', 'integer', 'age 컬럼은 INTEGER 타입이어야 함');
SELECT col_not_null('public', 'users', 'email', 'email은 NOT NULL이어야 함');

SELECT * FROM finish();

관련 에러

  • 42804 (datatype_mismatch): 쿼리 내에서 데이터 타입이 기대하는 타입과 맞지 않을 때 발생하며, 22005와 함께 자주 등장합니다. 주로 함수의 반환 타입이나 연산자 피연산자 타입이 맞지 않을 때 발생합니다.
  • 23514 (check_violation): 도메인이나 테이블에 정의된 CHECK 제약조건을 위반했을 때 발생합니다. 도메인 타입에 잘못된 값을 할당할 때 22005 대신 이 에러가 발생하기도 합니다.
  • 22P02 (invalid_text_representation): 문자열을 특정 타입(예: INTEGER, DATE, UUID 등)으로 변환(캐스팅)할 때 형식이 올바르지 않으면 발생합니다. 22005와 매우 유사한 상황에서 함께 발생할 수 있습니다.
  • 42883 (undefined_function): 타입 불일치로 인해 적합한 연산자나 함수를 찾지 못할 때 발생하며, 잘못된 타입의 값을 특정 함수에 전달할 때 22005와 연계되어 나타납니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기