2026년 10월 05일 | DBMS Error 가이드
이 글에서 다루는 내용
01004 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
01004 string data right truncation 는?
PostgreSQL 에러 코드 01004는 문자열 데이터가 대상 컬럼 또는 변수의 최대 길이를 초과할 때 발생하는 경고(Warning) 수준의 에러입니다. 이 에러는 INSERT, UPDATE, CAST 연산 또는 PL/pgSQL 함수 내부에서 문자열을 더 짧은 길이의 타입으로 저장하려 할 때 주로 발생합니다. 일반적으로 PostgreSQL은 character varying(n) 또는 char(n) 컬럼에 초과 길이의 문자열을 삽입하려 할 때 이 에러를 반환하며, 엄격한 설정에서는 데이터 손실을 방지하기 위해 트랜잭션 자체를 중단시키기도 합니다.
주요 발생 원인
1. VARCHAR(n) 또는 CHAR(n) 컬럼에 초과 길이 데이터 삽입
가장 흔한 원인입니다. 테이블 설계 시 컬럼 길이를 짧게 정의해두었는데, 실제 애플리케이션에서 그보다 긴 문자열을 삽입하려 할 때 발생합니다. 예를 들어 사용자 이름 컬럼을 VARCHAR(10)으로 설정했을 때 11자 이상의 이름이 들어오면 바로 이 에러가 발생합니다. 운영 환경에서 데이터 요구사항이 변경되었음에도 스키마가 업데이트되지 않은 경우에 특히 자주 나타납니다.
2. PL/pgSQL 함수 내 변수 선언 길이 불일치
PL/pgSQL 함수나 프로시저 내에서 VARCHAR(n) 타입으로 선언된 지역 변수에 더 긴 문자열을 대입하려 할 때 발생합니다. 외부에서 받아온 파라미터 값이나 SELECT 결과를 변수에 담을 때 변수의 길이 제한을 미처 고려하지 못한 경우입니다. 특히 레거시 코드에서 데이터 길이 가정이 잘못된 경우 이 문제가 반복적으로 나타납니다.
3. CAST 또는 타입 변환 중 묵시적 잘림
명시적 또는 묵시적 타입 캐스팅 과정에서 대상 타입의 길이 제한보다 긴 문자열을 변환하려 할 때 발생합니다. ETL 파이프라인이나 데이터 마이그레이션 작업 중에 소스 시스템과 타겟 시스템 간의 컬럼 길이 정의가 다를 경우 대량으로 이 에러가 발생할 수 있습니다. 이 경우 단순 경고로 처리되어 데이터가 잘린 채 저장될 수 있어 데이터 무결성 관점에서 매우 위험합니다.
해결 방법
원인 1 해결: 컬럼 길이 확장
현재 컬럼에 저장 가능한 최대 길이를 확인하고, 필요하다면 컬럼 길이를 늘려야 합니다.
-- 현재 컬럼 정의 확인
SELECT column_name, character_maximum_length, data_type
FROM information_schema.columns
WHERE table_name = 'users' AND column_name = 'username';
-- 컬럼 길이 확장 (예: VARCHAR(10) → VARCHAR(100))
ALTER TABLE users ALTER COLUMN username TYPE VARCHAR(100);
-- 변경 후 데이터 삽입 재시도
INSERT INTO users (username, email)
VALUES ('홍길동테스트사용자이름', 'hong@example.com');
길이 제한이 비즈니스 요구상 불명확하다면 TEXT 타입으로 변경하는 것도 좋은 방법입니다.
-- TEXT 타입으로 변경 (길이 제한 없음)
ALTER TABLE users ALTER COLUMN username TYPE TEXT;
원인 2 해결: PL/pgSQL 변수 타입 수정
-- 문제가 되는 함수 예시
CREATE OR REPLACE FUNCTION get_user_label(p_user_id INT)
RETURNS TEXT AS $$
DECLARE
v_label VARCHAR(10); -- 너무 짧은 선언
BEGIN
SELECT username || ' (' || email || ')'
INTO v_label
FROM users
WHERE id = p_user_id;
RETURN v_label;
END;
$$ LANGUAGE plpgsql;
-- 수정된 함수: 변수 타입을 TEXT로 변경하거나 충분한 길이로 확장
CREATE OR REPLACE FUNCTION get_user_label(p_user_id INT)
RETURNS TEXT AS $$
DECLARE
v_label TEXT; -- TEXT로 변경하여 길이 제한 제거
BEGIN
SELECT username || ' (' || email || ')'
INTO v_label
FROM users
WHERE id = p_user_id;
RETURN v_label;
END;
$$ LANGUAGE plpgsql;
원인 3 해결: CAST 시 명시적 잘림 처리 또는 타입 조정
-- 문제 발생 예시: 긴 문자열을 짧은 타입으로 캐스팅
SELECT CAST('이것은 매우 긴 문자열입니다 길이초과' AS VARCHAR(10));
-- 에러 발생: value too long for type character varying(10)
-- 해결책 1: LEFT() 함수로 명시적으로 잘라서 저장 (데이터 손실 인지 후 허용하는 경우)
SELECT CAST(LEFT('이것은 매우 긴 문자열입니다 길이초과', 10) AS VARCHAR(10));
-- 해결책 2: 마이그레이션 시 충분한 길이의 타입 사용
INSERT INTO target_table (short_desc)
SELECT LEFT(long_description, 100) -- 명시적으로 잘라서 삽입
FROM source_table;
-- 해결책 3: 삽입 전 데이터 길이 검증
DO $$
DECLARE
v_input TEXT := '이것은 매우 긴 문자열입니다 길이초과';
BEGIN
IF LENGTH(v_input) > 10 THEN
RAISE EXCEPTION '입력 문자열이 최대 길이(10자)를 초과합니다: % 자', LENGTH(v_input);
END IF;
INSERT INTO test_table (short_col) VALUES (v_input);
END;
$$;
데이터 마이그레이션 시 길이 초과 데이터 사전 탐지
-- 삽입 전 길이 초과 데이터 사전 확인
SELECT id, username, LENGTH(username) AS len
FROM staging_users
WHERE LENGTH(username) > 50 -- 타겟 컬럼 길이 기준
ORDER BY len DESC;
-- 초과 건수 집계
SELECT COUNT(*) AS overflow_count
FROM staging_users
WHERE LENGTH(username) > 50;
예방 방법
1. 컬럼 길이는 여유 있게 설계하고, 변경이 쉬운 TEXT 타입을 우선 고려하라
초기 스키마 설계 시 비즈니스 요구사항이 확정되지 않은 컬럼은 TEXT 타입을 기본으로 사용하는 것을 권장합니다. 이미 VARCHAR(n)을 사용 중이라면 실제 저장된 데이터의 최대 길이를 주기적으로 모니터링하고 컬럼 길이의 80% 이상을 사용하는 컬럼은 미리 확장하는 정책을 수립하세요.
-- 컬럼별 실제 사용 최대 길이 모니터링 쿼리
SELECT
'username' AS column_name,
MAX(LENGTH(username)) AS max_actual_length,
50 AS defined_length, -- 현재 정의된 길이
ROUND(MAX(LENGTH(username))::NUMERIC / 50 * 100, 2) AS usage_pct
FROM users;
2. 애플리케이션 레이어와 DB 레이어 모두에서 입력 길이 유효성 검사를 이중으로 적용하라
애플리케이션 단에서만 길이 검증을 하면 직접 DB에 접근하는 배치 작업이나 API 우회 경로에서 에러가 발생할 수 있습니다. DB 레이어에서는 CHECK 제약 조건이나 트리거를 활용하여 이중 방어선을 구축하는 것이 실무 Best Practice입니다.
-- CHECK 제약 조건으로 최소/최대 길이 동시 검증
ALTER TABLE users
ADD CONSTRAINT chk_username_length
CHECK (LENGTH(username) BETWEEN 2 AND 50);
-- 트리거를 활용한 삽입/수정 전 길이 검증
CREATE OR REPLACE FUNCTION validate_username_length()
RETURNS TRIGGER AS $$
BEGIN
IF LENGTH(NEW.username) > 50 THEN
RAISE EXCEPTION 'username은 최대 50자까지 허용됩니다. 입력된 길이: %자', LENGTH(NEW.username);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_check_username_length
BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION validate_username_length();
관련 에러
- 22001 (string_data_right_truncation): 01004와 동일한 상황에서 발생하지만, 22001은 ERROR 수준으로 트랜잭션을 즉시 중단시키는 반면 01004는 WARNING 수준으로 처리됩니다. PostgreSQL의 엄격 모드 설정 여부에 따라 같은 상황에서 다른 에러 코드가 반환될 수 있습니다.
- 22000 (data_exception): 데이터 값이 대상 타입의 범위나 형식에 맞지 않을 때 발생하는 상위 범주 에러로, 01004와 함께 데이터 타입 관련 문제 트러블슈팅 시 함께 참조해야 합니다.
- 42804 (datatype_mismatch): 타입 자체가 다를 때 발생하는 에러로, 01004가 길이 초과 문제라면 42804는 타입 자체의 불일치 문제입니다. 마이그레이션 작업 중 두 에러가 함께 나타나는 경우가 많습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.