2026년 08월 18일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-02299 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-02299 cannot validate – duplicate keys found 는?
ORA-02299 에러는 Oracle 데이터베이스에서 기존 테이블에 UNIQUE 또는 PRIMARY KEY 제약 조건을 활성화(ENABLE VALIDATE)하려고 할 때, 해당 컬럼에 이미 중복된 값이 존재하는 경우 발생합니다. 즉, 제약 조건을 추가하거나 비활성화된 제약 조건을 다시 활성화하는 시점에 데이터 무결성 검사를 통과하지 못할 때 이 에러가 나타납니다. 특히 대용량 데이터 마이그레이션 이후 또는 장기간 제약 조건이 DISABLE 상태였던 테이블에서 자주 목격되는 에러입니다.
주요 발생 원인
1. 비활성화된 제약 조건 재활성화 시 중복 데이터 존재
운영 중 대량 데이터 입력이나 배치 작업의 성능 향상을 위해 제약 조건을 DISABLE 상태로 전환한 뒤, 다시 ENABLE VALIDATE 명령을 실행할 때 그동안 삽입된 데이터에 중복 키가 존재하면 에러가 발생합니다. DISABLE 상태에서는 Oracle이 중복 여부를 체크하지 않으므로, 의도치 않게 중복 데이터가 쌓이는 경우가 많습니다. 이는 실무에서 가장 빈번하게 발생하는 원인입니다.
2. 데이터 마이그레이션 또는 ETL 작업 후 중복 데이터 유입
레거시 시스템이나 외부 소스에서 데이터를 이관할 때 원천 데이터 자체에 중복이 포함되어 있거나, 변환(Transformation) 과정의 로직 오류로 인해 중복 레코드가 생성되는 경우가 많습니다. 이후 해당 테이블에 PRIMARY KEY나 UNIQUE 제약 조건을 생성하려 하면 ORA-02299 에러가 발생합니다. 데이터 품질 검증 없이 무조건 적재하는 ETL 파이프라인에서 특히 주의가 필요합니다.
3. 복수 컬럼 복합 키의 중복 조합 존재
단일 컬럼이 아닌 두 개 이상의 컬럼으로 구성된 복합 UNIQUE 또는 PRIMARY KEY를 생성할 때, 개별 컬럼 값은 고유하더라도 컬럼 조합이 중복되는 경우에도 이 에러가 발생합니다. 예를 들어 (ORDER_ID, PRODUCT_ID)를 복합 키로 설정할 때, 같은 ORDER_ID와 PRODUCT_ID 조합을 가진 행이 여러 개 존재하면 제약 조건 생성에 실패합니다. 복합 키 구조를 충분히 이해하지 못한 상태에서 제약 조건을 추가하는 경우에 자주 발생합니다.
해결 방법
1단계: 중복 데이터 조회
제약 조건을 적용하려는 컬럼에서 중복 데이터를 먼저 확인합니다.
-- 단일 컬럼 중복 확인
SELECT employee_id, COUNT(*) AS cnt
FROM employees
GROUP BY employee_id
HAVING COUNT(*) > 1;
-- 복합 컬럼 중복 확인
SELECT order_id, product_id, COUNT(*) AS cnt
FROM order_details
GROUP BY order_id, product_id
HAVING COUNT(*) > 1;
2단계: 중복 행 상세 조회 (ROWID 활용)
중복 데이터 중 어떤 행을 남기고 어떤 행을 삭제할지 파악하기 위해 ROWID를 활용합니다.
-- 중복 행 전체 확인 (ROWID 포함)
SELECT ROWID, employee_id, first_name, last_name, hire_date
FROM employees
WHERE employee_id IN (
SELECT employee_id
FROM employees
GROUP BY employee_id
HAVING COUNT(*) > 1
)
ORDER BY employee_id, ROWID;
3단계: 중복 데이터 제거
가장 최신 ROWID를 제외하고 나머지 중복 행을 삭제하거나 별도 테이블로 이동합니다.
-- 방법 A: 중복 행 삭제 (최소 ROWID만 남기기)
DELETE FROM employees
WHERE ROWID NOT IN (
SELECT MIN(ROWID)
FROM employees
GROUP BY employee_id
);
-- 방법 B: 중복 행을 백업 테이블로 이동 후 삭제
CREATE TABLE employees_dup_backup AS
SELECT *
FROM employees
WHERE ROWID NOT IN (
SELECT MIN(ROWID)
FROM employees
GROUP BY employee_id
);
DELETE FROM employees
WHERE ROWID NOT IN (
SELECT MIN(ROWID)
FROM employees
GROUP BY employee_id
);
COMMIT;
4단계: 제약 조건 활성화 또는 생성
중복 데이터를 정리한 후 제약 조건을 적용합니다.
-- 기존 비활성 제약 조건 활성화
ALTER TABLE employees ENABLE VALIDATE CONSTRAINT pk_employees;
-- 새로운 PRIMARY KEY 제약 조건 추가
ALTER TABLE employees
ADD CONSTRAINT pk_employees PRIMARY KEY (employee_id);
-- 새로운 UNIQUE 제약 조건 추가
ALTER TABLE order_details
ADD CONSTRAINT uq_order_product UNIQUE (order_id, product_id);
보조 방법: ENABLE NOVALIDATE 임시 활용
즉각적인 운영 복구가 필요한 경우, 기존 데이터는 검증하지 않고 이후 입력 데이터만 제약 조건을 적용하는 임시 방법입니다. 단, 이 방법은 기존 중복 데이터를 허용하는 것이므로 반드시 후속 데이터 정제 작업이 필요합니다.
-- 기존 데이터 검증 없이 제약 조건 활성화 (임시방편)
ALTER TABLE employees ENABLE NOVALIDATE CONSTRAINT pk_employees;
-- 이후 중복 데이터 정제 완료 후 VALIDATE로 전환
ALTER TABLE employees ENABLE VALIDATE CONSTRAINT pk_employees;
예방 방법
1. 데이터 적재 전 사전 중복 검증 프로세스 수립
ETL 작업이나 대량 데이터 삽입 전에 반드시 중복 데이터 여부를 사전 검증하는 스크립트를 파이프라인에 포함시켜야 합니다. 또한 제약 조건을 DISABLE 상태로 전환하는 경우, 작업 완료 후 즉시 ENABLE VALIDATE로 복원하는 절차를 표준화하고 자동화하는 것이 중요합니다.
-- 사전 검증 스크립트 예시
DECLARE
v_dup_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_dup_count
FROM (
SELECT employee_id
FROM employees
GROUP BY employee_id
HAVING COUNT(*) > 1
);
IF v_dup_count > 0 THEN
RAISE_APPLICATION_ERROR(-20001,
'중복 데이터 ' || v_dup_count || '건 발견. 적재를 중단합니다.');
END IF;
END;
/
2. UNIQUE 인덱스를 통한 선제적 데이터 품질 관리
제약 조건 적용 전에 UNIQUE 인덱스를 먼저 생성하여 중복 여부를 미리 확인하는 방법을 활용할 수 있습니다. 인덱스 생성 시에도 중복이 있으면 실패하므로, 실제 제약 조건 추가 전에 데이터 품질 상태를 점검하는 용도로 사용할 수 있습니다. 또한 애플리케이션 레벨에서도 INSERT/UPDATE 전에 중복 체크 로직을 구현하여 이중 방어선을 구축하는 것이 Best Practice입니다.
-- 제약 조건 추가 전 UNIQUE 인덱스로 사전 검증
CREATE UNIQUE INDEX idx_emp_id_test ON employees(employee_id);
-- 성공 시 인덱스 삭제 후 제약 조건 추가
DROP INDEX idx_emp_id_test;
ALTER TABLE employees ADD CONSTRAINT pk_employees PRIMARY KEY (employee_id);
관련 에러
- ORA-00001 (unique constraint violated): INSERT 또는 UPDATE 시 이미 활성화된 UNIQUE/PRIMARY KEY 제약 조건을 위반할 때 발생하며, ORA-02299와 유사한 맥락의 에러입니다.
- ORA-02298 (cannot validate – parent keys not found): FOREIGN KEY 제약 조건을 활성화할 때 참조 대상 부모 키가 존재하지 않는 경우 발생하는 에러로, ORA-02299와 함께 제약 조건 활성화 시 자주 함께 마주치는 에러입니다.
- ORA-02290 (check constraint violated): CHECK 제약 조건 위반 시 발생하며, 제약 조건 활성화 관련 에러 그룹에 속합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.