Oracle ORA-02261 오류 원인과 해결 방법 완벽 가이드

ORA-02261
2026년 08월 14일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-02261 such unique or primary key already exists in the table 는?

ORA-02261 에러는 테이블에 동일한 컬럼 조합으로 이미 UNIQUE 키 또는 PRIMARY KEY 제약 조건이 존재하는 상황에서 동일한 제약 조건을 다시 추가하려 할 때 발생합니다. Oracle은 하나의 테이블에 중복된 유일성 제약 조건을 허용하지 않으며, 이는 데이터 무결성을 보호하기 위한 데이터베이스 엔진 수준의 보호 장치입니다. 주로 DDL 스크립트를 반복 실행하거나, 데이터 마이그레이션 도중, 또는 ORM 프레임워크가 자동으로 제약 조건을 생성하려 할 때 빈번하게 목격되는 에러입니다.


주요 발생 원인

1. 동일한 DDL 스크립트의 반복 실행

배포 자동화 파이프라인(CI/CD)이나 수동 DB 패치 적용 과정에서 동일한 ALTER TABLE 또는 CREATE TABLE 스크립트를 두 번 이상 실행할 때 가장 흔하게 발생합니다. 개발 환경에서는 멱등성(idempotency)을 고려하지 않은 스크립트가 운영 환경에 그대로 배포되면서 이 에러를 유발하는 경우가 매우 많습니다. 특히 테이블 생성 이후 제약 조건을 별도로 추가하는 패턴의 스크립트에서 자주 목격됩니다.

2. 이미 존재하는 PRIMARY KEY가 있는 테이블에 PRIMARY KEY 재추가 시도

테이블에는 PRIMARY KEY가 오직 하나만 존재할 수 있습니다. ORM(Hibernate, JPA 등)이나 마이그레이션 툴(Flyway, Liquibase 등)이 상태를 제대로 추적하지 못하거나, DBA가 현재 제약 조건 현황을 확인하지 않고 스크립트를 실행할 경우 이 에러가 발생합니다. 데이터 마이그레이션이나 스키마 리팩터링 작업 중에도 이전 PRIMARY KEY가 DROP되지 않은 상태에서 새 키를 추가하려 할 때 동일한 문제가 발생합니다.

3. 동일한 컬럼 조합의 UNIQUE 제약 조건 중복 생성

서로 다른 이름을 가진 UNIQUE 제약 조건이라도 동일한 컬럼 또는 컬럼 조합을 참조하면 ORA-02261이 발생합니다. 여러 개발자가 동시에 작업하거나 여러 팀이 독립적으로 스키마 변경을 적용하는 환경에서, 서로 모르게 동일한 컬럼에 UNIQUE 제약 조건을 중복으로 추가하려는 시도가 생길 수 있습니다. 제약 조건 관리 문서 또는 형상 관리가 미흡할 때 특히 자주 발생합니다.


해결 방법

1단계: 현재 테이블의 제약 조건 현황 파악

에러 해결의 첫 번째 단계는 대상 테이블에 어떤 제약 조건이 이미 존재하는지 확인하는 것입니다.

-- 특정 테이블의 제약 조건 전체 조회
SELECT constraint_name,
       constraint_type,
       status,
       validated
FROM   user_constraints
WHERE  table_name = 'EMPLOYEES'  -- 테이블명은 대문자로 입력
ORDER BY constraint_type;

-- 제약 조건에 포함된 컬럼 상세 조회
SELECT uc.constraint_name,
       uc.constraint_type,
       ucc.column_name,
       ucc.position
FROM   user_constraints  uc
JOIN   user_cons_columns ucc
       ON uc.constraint_name = ucc.constraint_name
WHERE  uc.table_name = 'EMPLOYEES'
ORDER BY uc.constraint_type, ucc.position;

2단계: 중복 제약 조건 제거 후 재생성

기존 제약 조건이 확인되었다면, 불필요한 제약 조건을 DROP한 뒤 원하는 형태로 재생성합니다.

-- 기존 PRIMARY KEY 제약 조건 삭제
ALTER TABLE employees DROP CONSTRAINT pk_employees;

-- PRIMARY KEY 재생성
ALTER TABLE employees
ADD CONSTRAINT pk_employees PRIMARY KEY (employee_id);

-- 기존 UNIQUE 제약 조건 삭제
ALTER TABLE employees DROP CONSTRAINT uq_emp_email;

-- UNIQUE 제약 조건 재생성 (복합 컬럼 예시)
ALTER TABLE employees
ADD CONSTRAINT uq_emp_email UNIQUE (email, department_id);

3단계: 멱등성 있는 스크립트 작성 (재실행 안전 처리)

배포 환경에서 동일 스크립트를 안전하게 반복 실행할 수 있도록 예외 처리를 추가합니다.

-- PL/SQL 블록을 이용한 안전한 제약 조건 추가 (멱등성 보장)
DECLARE
  v_count NUMBER;
BEGIN
  -- 해당 제약 조건이 이미 존재하는지 확인
  SELECT COUNT(*)
  INTO   v_count
  FROM   user_constraints
  WHERE  table_name      = 'EMPLOYEES'
  AND    constraint_type = 'P';  -- P: Primary Key, U: Unique

  IF v_count = 0 THEN
    EXECUTE IMMEDIATE
      'ALTER TABLE employees ADD CONSTRAINT pk_employees PRIMARY KEY (employee_id)';
    DBMS_OUTPUT.PUT_LINE('PRIMARY KEY 제약 조건이 생성되었습니다.');
  ELSE
    DBMS_OUTPUT.PUT_LINE('PRIMARY KEY 제약 조건이 이미 존재합니다. 건너뜁니다.');
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('오류 발생: ' || SQLERRM);
    RAISE;
END;
/

-- UNIQUE 제약 조건 중복 여부 확인 후 추가
DECLARE
  v_count NUMBER;
BEGIN
  SELECT COUNT(*)
  INTO   v_count
  FROM   user_constraints uc
  JOIN   user_cons_columns ucc
         ON uc.constraint_name = ucc.constraint_name
  WHERE  uc.table_name      = 'EMPLOYEES'
  AND    uc.constraint_type = 'U'
  AND    ucc.column_name    = 'EMAIL';

  IF v_count = 0 THEN
    EXECUTE IMMEDIATE
      'ALTER TABLE employees ADD CONSTRAINT uq_emp_email UNIQUE (email)';
    DBMS_OUTPUT.PUT_LINE('UNIQUE 제약 조건이 생성되었습니다.');
  ELSE
    DBMS_OUTPUT.PUT_LINE('동일 컬럼에 UNIQUE 제약 조건이 이미 존재합니다.');
  END IF;
END;
/

4단계: 기존 PRIMARY KEY를 유지하면서 컬럼 변경이 필요한 경우

-- 기존 PK를 삭제하고 새 컬럼 조합으로 재생성하는 전체 흐름
-- 1. 기존 FK 제약 조건 비활성화 (참조 테이블이 있을 경우)
ALTER TABLE orders DISABLE CONSTRAINT fk_orders_employees;

-- 2. 기존 PK 삭제
ALTER TABLE employees DROP CONSTRAINT pk_employees CASCADE;

-- 3. 새 PK 생성 (복합 키 예시)
ALTER TABLE employees
ADD CONSTRAINT pk_employees PRIMARY KEY (employee_id, company_id)
USING INDEX TABLESPACE users_idx;

-- 4. FK 재활성화
ALTER TABLE orders ENABLE CONSTRAINT fk_orders_employees;

예방 방법

1. 모든 DDL 스크립트에 사전 존재 여부 체크 로직 포함

운영 환경에 적용하는 모든 DDL 스크립트는 반드시 멱등성(Idempotency)을 보장해야 합니다. 제약 조건 추가 전에 USER_CONSTRAINTS 또는 ALL_CONSTRAINTS 딕셔너리 뷰를 조회하여 중복 여부를 사전에 확인하는 PL/SQL 래퍼 블록을 표준 템플릿으로 정의하고 팀 전체가 이를 준수하도록 코드 리뷰 프로세스에 포함시키는 것이 바람직합니다. Flyway나 Liquibase와 같은 스키마 버전 관리 도구를 사용한다면, 각 체인지셋(changeset)이 한 번만 실행되도록 체크섬 관리와 실행 이력 테이블을 반드시 활성화하십시오.

2. 제약 조건 네이밍 컨벤션 및 스키마 문서화 표준 수립

팀 내에서 제약 조건에 대한 명확한 네이밍 컨벤션(PK_테이블명, UQ_테이블명_컬럼명, FK_테이블명_참조테이블명)을 정의하고 문서화하면, 중복 생성 시도를 사전에 식별하기 훨씬 쉬워집니다. 정기적으로 USER_CONSTRAINTS 뷰를 기반으로 현재 스키마 상태를 문서화하고, 변경 사항은 반드시 형상 관리(Git 등)를 통해 이력을 남기는 습관을 조직 전체의 표준으로 정착시켜야 합니다.


관련 에러

  • ORA-02260: table can have only one primary key — PRIMARY KEY는 테이블당 하나만 허용된다는 점을 명시적으로 알려주는 에러로, ORA-02261과 유사한 맥락에서 발생합니다.
  • ORA-00955: name is already used by an existing object — 제약 조건 이름 자체가 이미 다른 오브젝트에서 사용 중일 때 발생합니다.
  • ORA-02264: name already used by an existing constraint — 동일한 제약 조건 이름이 이미 존재할 때 발생하며, ORA-02261과 함께 DDL 중복 실행 시 자주 동반됩니다.
  • ORA-01408: such column list already indexed — 동일한 컬럼 조합에 인덱스를 중복 생성하려 할 때 발생하며, UNIQUE 인덱스 생성 시 ORA-02261과 함께 발생할 수 있습니다.
DBMS 에러 코드 시리즈

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

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

댓글 남기기