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

23502
2026년 08월 25일 | DBMS Error 가이드

이 글에서 다루는 내용

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

23502 not null violation 는?

PostgreSQL 에러 코드 23502는 not null violation으로, 테이블의 특정 컬럼에 NOT NULL 제약 조건이 설정되어 있는데 해당 컬럼에 NULL 값을 삽입하거나 업데이트하려 할 때 발생합니다. 이 에러는 데이터 무결성을 보호하기 위한 PostgreSQL의 방어 메커니즘으로, 필수 데이터가 누락된 상태로 저장되는 것을 원천 차단합니다. 주로 애플리케이션 코드에서 필수 필드를 누락하거나, 데이터 마이그레이션 중 컬럼 매핑이 잘못되었을 때, 또는 기존 컬럼에 새로 NOT NULL 제약을 추가할 때 빈번하게 발생합니다.


주요 발생 원인

1. INSERT/UPDATE 시 필수 컬럼 값 누락

가장 흔한 원인으로, 애플리케이션에서 데이터를 삽입하거나 수정할 때 NOT NULL로 정의된 컬럼의 값을 명시적으로 제공하지 않는 경우입니다. ORM(Object Relational Mapping) 프레임워크를 사용할 때 모델과 실제 DB 스키마가 불일치하는 경우에도 자주 나타나며, 특히 새로운 NOT NULL 컬럼이 추가된 이후 애플리케이션 코드가 업데이트되지 않으면 반드시 이 에러가 발생합니다.

2. 기존 테이블에 DEFAULT 값 없이 NOT NULL 컬럼 추가

이미 데이터가 존재하는 테이블에 NOT NULL 제약 조건이 있는 새 컬럼을 DEFAULT 값 없이 추가하려 할 때 발생합니다. 기존 레코드들은 새로 추가된 컬럼에 대해 어떤 값도 가지지 않으므로, PostgreSQL은 이를 NULL로 처리하여 즉시 제약 조건 위반 에러를 발생시킵니다. 이 시나리오는 특히 운영 환경에서 스키마를 변경할 때 서비스 장애로 이어질 수 있어 매우 주의가 필요합니다.

3. 데이터 마이그레이션 또는 ETL 파이프라인의 컬럼 매핑 오류

외부 시스템으로부터 데이터를 가져오거나 변환하는 과정에서 소스 데이터의 컬럼이 대상 테이블의 NOT NULL 컬럼과 올바르게 매핑되지 않으면 이 에러가 발생합니다. CSV 파일 임포트, COPY 명령 사용, 또는 복잡한 INSERT INTO ... SELECT ... 구문에서 소스 컬럼이 비어 있거나 NULL을 반환하는 경우에도 동일한 문제가 생깁니다. 대용량 데이터 마이그레이션 중간에 이 에러가 터지면 트랜잭션 전체가 롤백될 수 있어 치명적입니다.


해결 방법

원인 1 해결: INSERT/UPDATE 구문 수정

먼저 에러 메시지에서 어느 테이블의 어느 컬럼이 문제인지 확인합니다. PostgreSQL 에러 메시지는 보통 column "컬럼명" of relation "테이블명" violates not-null constraint 형태로 명확히 알려줍니다.

-- 문제가 되는 상황: email 컬럼이 NOT NULL인데 값을 제공하지 않음
INSERT INTO users (username, created_at)
VALUES ('john_doe', NOW());
-- ERROR: null value in column "email" of relation "users"
-- violates not-null constraint

-- 해결 1: 누락된 컬럼 값을 명시적으로 제공
INSERT INTO users (username, email, created_at)
VALUES ('john_doe', 'john@example.com', NOW());

-- 해결 2: 해당 컬럼에 DEFAULT 값을 설정하여 자동으로 처리
ALTER TABLE users
    ALTER COLUMN email SET DEFAULT 'unknown@example.com';

-- 해결 3: NOT NULL 제약이 실제로 필요 없다면 제약 해제 (신중히 결정)
ALTER TABLE users
    ALTER COLUMN email DROP NOT NULL;

원인 2 해결: 기존 테이블에 NOT NULL 컬럼 안전하게 추가

-- 잘못된 방법: 기존 데이터가 있는 테이블에 DEFAULT 없이 NOT NULL 컬럼 추가
-- 아래 구문은 즉시 에러 발생
ALTER TABLE orders ADD COLUMN shipped_at TIMESTAMP NOT NULL;
-- ERROR: column "shipped_at" contains null values

-- 올바른 방법 (3단계 접근):

-- 1단계: 먼저 NULL 허용으로 컬럼 추가
ALTER TABLE orders ADD COLUMN shipped_at TIMESTAMP;

-- 2단계: 기존 레코드에 적절한 값으로 업데이트
UPDATE orders
SET shipped_at = created_at + INTERVAL '3 days'
WHERE shipped_at IS NULL;

-- 3단계: 모든 레코드 업데이트 완료 후 NOT NULL 제약 추가
ALTER TABLE orders ALTER COLUMN shipped_at SET NOT NULL;

-- 또는 PostgreSQL 11+ 에서는 DEFAULT와 함께 한 번에 추가 가능
-- (기존 행에 즉시 DEFAULT 값이 적용됨 - 테이블 리라이트 없이 처리)
ALTER TABLE orders
    ADD COLUMN status VARCHAR(50) NOT NULL DEFAULT 'pending';

원인 3 해결: ETL 및 데이터 마이그레이션 시 NULL 처리

-- 문제 상황: 소스 테이블에 NULL이 있는 경우 그대로 삽입 시도
INSERT INTO target_table (user_id, email, phone)
SELECT user_id, email, phone
FROM source_table;
-- phone이 NOT NULL인데 source_table에 NULL 값 존재 시 에러 발생

-- 해결 1: COALESCE를 사용해 NULL을 기본값으로 대체
INSERT INTO target_table (user_id, email, phone)
SELECT
    user_id,
    COALESCE(email, 'noemail@unknown.com'),
    COALESCE(phone, '000-0000-0000')
FROM source_table;

-- 해결 2: NULL이 있는 레코드를 사전에 필터링 후 처리
-- NULL이 있는 레코드를 별도 로그 테이블에 기록
INSERT INTO migration_error_log (user_id, reason, logged_at)
SELECT user_id, 'phone is NULL', NOW()
FROM source_table
WHERE phone IS NULL;

-- NULL이 없는 레코드만 삽입
INSERT INTO target_table (user_id, email, phone)
SELECT user_id, email, phone
FROM source_table
WHERE phone IS NOT NULL;

-- 해결 3: COPY 명령 사용 시 NULL 처리
-- CSV 파일에서 빈 문자열을 특정 값으로 대체
COPY target_table (user_id, email, phone)
FROM '/path/to/data.csv'
WITH (FORMAT csv, NULL 'NULL', DEFAULT '');

-- 현재 테이블의 NOT NULL 제약 현황 확인 쿼리
SELECT
    c.column_name,
    c.data_type,
    c.is_nullable,
    c.column_default
FROM information_schema.columns c
WHERE c.table_schema = 'public'
  AND c.table_name = 'your_table_name'
ORDER BY c.ordinal_position;

예방 방법

1. 스키마 변경 시 항상 DEFAULT 값과 함께 NOT NULL 컬럼 추가하기

운영 중인 테이블에 새 컬럼을 추가할 때는 반드시 DEFAULT 값을 함께 지정하는 습관을 들여야 합니다. 또한 스키마 변경 전에 개발/스테이징 환경에서 충분히 테스트한 후, 실제 운영 환경 데이터와 유사한 샘플로 마이그레이션 스크립트를 검증하는 프로세스를 팀 내 표준으로 만드세요. PostgreSQL 11 이상에서는 DEFAULT 값을 가진 NOT NULL 컬럼 추가 시 테이블 리라이트가 발생하지 않아 성능 부담도 크게 줄었습니다.

-- Best Practice: NOT NULL + DEFAULT 함께 사용
ALTER TABLE users
    ADD COLUMN is_verified BOOLEAN NOT NULL DEFAULT FALSE;

-- 스키마 변경 전 NOT NULL 위반 가능성 사전 점검
SELECT COUNT(*)
FROM your_table
WHERE potentially_null_column IS NULL;

2. 애플리케이션 레벨 유효성 검사와 DB 제약 조건 이중화

데이터베이스의 NOT NULL 제약만 믿지 말고, 애플리케이션 코드(API, 서비스 레이어)에서도 필수 필드 검증 로직을 반드시 구현하세요. 두 레이어에서 모두 검증하면 에러가 DB까지 도달하기 전에 사용자 친화적인 메시지로 처리할 수 있고, 불필요한 DB 왕복 비용도 줄일 수 있습니다. CI/CD 파이프라인에 스키마 검증 단계를 포함시켜 배포 전에 컬럼 매핑 오류를 자동으로 감지하는 체계를 구축하는 것도 강력히 권장합니다.


관련 에러

  • 23000 (integrity_constraint_violation): NOT NULL violation을 포함하는 상위 카테고리 에러로, 모든 무결성 제약 위반의 부모 에러 클래스입니다.
  • 23505 (unique_violation): UNIQUE 제약 조건 위반으로, 중복 값 삽입 시 발생합니다. NOT NULL과 함께 복합 제약으로 자주 설정됩니다.
  • 23503 (foreign_key_violation): 외래 키 제약 조건 위반으로, 참조하는 부모 테이블에 해당 값이 없을 때 발생합니다.
  • 23514 (check_violation): CHECK 제약 조건 위반으로, 컬럼 값이 정의된 조건식을 만족하지 못할 때 발생합니다.
  • 42804 (datatype_mismatch): 컬럼의 데이터 타입과 삽입하려는 값의 타입이 불일치할 때 발생하며, NOT NULL 에러와 함께 마이그레이션 시 자주 동반됩니다.
DBMS 에러 코드 시리즈

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

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

댓글 남기기