2026년 09월 09일 | DBMS Error 가이드
이 글에서 다루는 내용
42804 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
42804 datatype mismatch 는?
PostgreSQL 에러 코드 42804는 datatype mismatch, 즉 데이터 타입 불일치 오류입니다. 이 에러는 SQL 문에서 서로 다른 데이터 타입이 호환되지 않는 방식으로 사용될 때 발생하며, 예를 들어 정수형 컬럼에 문자열을 삽입하거나, UNION 연산에서 서로 다른 타입의 컬럼을 결합하려 할 때 트리거됩니다. PostgreSQL은 강타입(strongly typed) 시스템을 채택하고 있어, 암묵적 형변환이 허용되지 않는 경우 이 에러를 명시적으로 발생시킵니다.
주요 발생 원인
- UNION / UNION ALL에서 컬럼 타입 불일치
UNION 또는 UNION ALL을 사용할 때, 두 SELECT 절의 대응하는 컬럼은 동일하거나 자동 변환 가능한 타입이어야 합니다. 예를 들어 첫 번째 SELECT에서 INTEGER 타입 컬럼을 반환하고, 두 번째 SELECT에서 동일한 위치에 TEXT 타입 컬럼을 반환하면 PostgreSQL은 즉시 42804 에러를 발생시킵니다. 이 경우는 대규모 리포팅 쿼리나 레거시 뷰를 수정할 때 자주 등장하는 실수입니다.
- 함수 인자 또는 반환 타입 불일치
사용자 정의 함수(UDF)나 내장 함수를 호출할 때, 선언된 파라미터 타입과 실제 전달된 인자의 타입이 다를 경우 이 에러가 발생합니다. 특히 CASE 표현식에서 각 WHEN 브랜치가 서로 다른 데이터 타입을 반환하거나, PL/pgSQL 함수의 RETURNS 절에 선언된 타입과 실제 반환값의 타입이 다를 때 매우 빈번하게 나타납니다. 함수 오버로딩이 많은 환경에서는 의도치 않은 버전의 함수가 호출되어 타입 불일치가 발생하기도 합니다.
- 테이블 컬럼과 INSERT/UPDATE 값의 타입 불일치
INSERT 또는 UPDATE 구문에서 컬럼에 정의된 타입과 실제 삽입/수정하려는 값의 타입이 다를 때 발생합니다. 특히 애플리케이션 레이어에서 동적으로 SQL을 생성하거나, ORM을 사용할 때 타입 매핑이 잘못되면 이 에러가 런타임에 발생합니다. BOOLEAN 컬럼에 'yes' 또는 1 같은 문자열/정수를 직접 삽입하려 할 때도 이 에러가 나타날 수 있습니다.
해결 방법
1. UNION에서 타입 불일치 해결 — 명시적 CAST 사용
-- 에러 발생 예시
SELECT employee_id, salary FROM employees -- salary: INTEGER
UNION ALL
SELECT employee_id, salary_text FROM contractors; -- salary_text: TEXT
-- 해결 방법: 명시적 CAST로 타입 통일
SELECT employee_id, salary::TEXT AS salary_value FROM employees
UNION ALL
SELECT employee_id, salary_text AS salary_value FROM contractors;
-- 또는 숫자로 통일하고 싶을 경우
SELECT employee_id, salary AS salary_value FROM employees
UNION ALL
SELECT employee_id, salary_text::INTEGER AS salary_value FROM contractors;
2. CASE 표현식에서 타입 통일
-- 에러 발생 예시: CASE 브랜치 타입 혼재
SELECT
CASE
WHEN score >= 90 THEN 'A' -- TEXT
WHEN score >= 80 THEN 85 -- INTEGER (타입 불일치!)
ELSE 'F'
END AS grade
FROM students;
-- 해결 방법: 모든 브랜치를 동일 타입으로 통일
SELECT
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
ELSE 'F'
END AS grade
FROM students;
-- 숫자형으로 통일하는 경우
SELECT
CASE
WHEN score >= 90 THEN 90
WHEN score >= 80 THEN 85
ELSE 0
END AS grade_score
FROM students;
3. INSERT/UPDATE 시 명시적 타입 변환
-- 에러 발생 예시: BOOLEAN 컬럼에 정수 삽입
CREATE TABLE user_settings (
user_id INTEGER,
is_active BOOLEAN,
created_at TIMESTAMP
);
-- 에러 발생
INSERT INTO user_settings (user_id, is_active, created_at)
VALUES (1, 1, '2024-01-15'); -- 1은 BOOLEAN이 아님
-- 해결 방법 1: 올바른 BOOLEAN 리터럴 사용
INSERT INTO user_settings (user_id, is_active, created_at)
VALUES (1, TRUE, '2024-01-15'::TIMESTAMP);
-- 해결 방법 2: 명시적 CAST 사용
INSERT INTO user_settings (user_id, is_active, created_at)
VALUES (1, 1::BOOLEAN, NOW());
4. 함수 반환 타입 불일치 해결
-- 에러 발생 예시: 반환 타입 선언과 실제 반환값 불일치
CREATE OR REPLACE FUNCTION get_user_score(p_user_id INTEGER)
RETURNS INTEGER AS $$
DECLARE
v_score TEXT; -- TEXT로 선언했지만 INTEGER 반환 선언
BEGIN
SELECT score::TEXT INTO v_score FROM user_scores WHERE user_id = p_user_id;
RETURN v_score; -- 42804 에러 발생!
END;
$$ LANGUAGE plpgsql;
-- 해결 방법: 반환 타입에 맞게 변수 타입 및 반환값 수정
CREATE OR REPLACE FUNCTION get_user_score(p_user_id INTEGER)
RETURNS INTEGER AS $$
DECLARE
v_score INTEGER; -- 반환 타입과 일치하도록 수정
BEGIN
SELECT score INTO v_score FROM user_scores WHERE user_id = p_user_id;
RETURN v_score;
END;
$$ LANGUAGE plpgsql;
5. 컬럼 타입 확인 후 CAST 적용
-- 현재 테이블 컬럼 타입 확인
SELECT
column_name,
data_type,
udt_name
FROM information_schema.columns
WHERE table_name = 'your_table_name'
AND table_schema = 'public'
ORDER BY ordinal_position;
-- pg_catalog을 활용한 상세 타입 확인
SELECT
a.attname AS column_name,
pg_catalog.format_type(a.atttypid, a.atttypmod) AS data_type
FROM pg_catalog.pg_attribute a
JOIN pg_catalog.pg_class c ON a.attrelid = c.oid
WHERE c.relname = 'your_table_name'
AND a.attnum > 0
AND NOT a.attisdropped;
예방 방법
- 스키마 설계 시 도메인(Domain) 타입 활용 및 타입 명세 문서화
PostgreSQL의 CREATE DOMAIN 기능을 활용하면 비즈니스 도메인에 맞는 사용자 정의 타입을 생성하고 일관성을 유지할 수 있습니다. 또한 테이블 설계 단계에서 각 컬럼의 타입과 허용 범위를 문서화하고, 코드 리뷰 시 타입 일관성을 반드시 검토하는 문화를 정착시켜야 합니다. 특히 여러 팀이 같은 데이터베이스를 공유하는 환경에서는 타입 스펙을 공유 문서로 관리하는 것이 필수입니다.
“`sql
— 도메인 타입 생성 예시
CREATE DOMAIN positive_integer AS INTEGER
CONSTRAINT positive_check CHECK (VALUE > 0);
CREATE DOMAIN email_address AS TEXT
CONSTRAINT email_format CHECK (VALUE ~* ‘^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$’);
— 도메인 타입을 컬럼에 적용
CREATE TABLE employees (
employee_id positive_integer PRIMARY KEY,
email email_address NOT NULL
);
“`
- 개발/스테이징 환경에서
pg_stat_statements및 쿼리 검증 자동화
운영 환경에 배포하기 전, CI/CD 파이프라인에 SQL 린터(예: sqlfluff, pgTAP)를 통합하여 타입 관련 오류를 사전에 탐지해야 합니다. 특히 마이그레이션 스크립트를 적용하기 전 스테이징 환경에서 모든 쿼리를 실행해보고, PostgreSQL의 EXPLAIN 명령으로 타입 변환이 올바르게 처리되는지 확인하는 것이 중요합니다.
“`sql
— 타입 변환 가능 여부 사전 확인
SELECT pg_typeof(‘2024-01-15’::DATE);
SELECT pg_typeof(42::FLOAT8);
— EXPLAIN으로 타입 처리 확인
EXPLAIN (VERBOSE, FORMAT TEXT)
SELECT employee_id::TEXT, salary FROM employees;
“`
관련 에러
- 42883 (undefined_function): 특정 타입 조합에 대한 연산자나 함수가 존재하지 않을 때 발생하며, 42804와 함께 자주 등장합니다.
- 42P18 (indeterminate_datatype): 데이터 타입을 결정할 수 없을 때 발생하며,
NULL리터럴만 사용하는 UNION 등에서 나타납니다. - 22007 (invalid_datetime_format): 날짜/시간 타입으로의 변환 시 형식이 잘못된 경우로, 42804와 혼동되기 쉬운 타입 관련 에러입니다.
- 22P02 (invalid_text_representation): 텍스트를 다른 타입으로 CAST할 때 값 자체가 유효하지 않은 경우 발생합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.