2026년 07월 10일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-01402 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-01402 view WITH CHECK OPTION where-clause violation 는?
ORA-01402 에러는 WITH CHECK OPTION이 설정된 뷰(View)를 통해 데이터를 INSERT 또는 UPDATE할 때, 해당 작업의 결과가 뷰의 WHERE 절 조건을 위반할 경우 발생하는 에러입니다. 즉, 뷰를 통해 삽입하거나 수정한 행이 뷰 자체의 정의 조건에 부합하지 않아 뷰에서 조회할 수 없는 상태가 되는 것을 Oracle이 방지하는 메커니즘입니다. 이 에러는 데이터 무결성 보호를 위한 의도된 제약이지만, 개발자나 DBA가 뷰의 조건을 충분히 이해하지 못한 채 DML을 수행할 때 자주 마주치게 됩니다.
주요 발생 원인
- WITH CHECK OPTION이 설정된 뷰에 조건 위반 데이터 삽입
가장 흔한 원인입니다. WITH CHECK OPTION이 적용된 뷰는 뷰의 WHERE 조건을 만족하는 데이터만 INSERT/UPDATE할 수 있도록 제한합니다. 예를 들어, 특정 부서(DEPTNO=10) 직원만 보여주는 뷰에 다른 부서 직원을 삽입하려 하면 이 에러가 발생합니다. 개발자가 뷰를 통해 데이터를 조작할 때 뷰의 필터 조건을 간과하는 경우 빈번하게 발생합니다.
- UPDATE 시 WHERE 조건의 핵심 컬럼 값 변경
뷰를 통해 데이터를 수정할 때, 뷰의 WHERE 절에 포함된 컬럼의 값을 뷰의 조건 범위 밖으로 변경하려 할 때 발생합니다. 예를 들어 DEPTNO = 10인 뷰에서 특정 사원의 DEPTNO를 20으로 변경하면, 해당 행은 더 이상 뷰에서 보이지 않게 되므로 Oracle이 이를 차단합니다. 이는 데이터 일관성을 유지하기 위한 Oracle의 보호 장치입니다.
- 복합 조건 뷰(CASCADED CHECK OPTION)에서의 다중 조건 위반
WITH CASCADED CHECK OPTION이 설정된 중첩 뷰(View on View)에서는 상위 뷰와 하위 뷰의 모든 WHERE 조건을 동시에 만족해야 합니다. 복잡한 뷰 계층 구조에서 조건들을 모두 파악하지 못하고 DML을 수행할 경우 이 에러가 발생합니다. 특히 레거시 시스템이나 복잡한 보안 뷰 구조에서 자주 발견됩니다.
해결 방법
원인 1 해결: WITH CHECK OPTION이 설정된 뷰에 조건 위반 데이터 삽입
먼저 문제 상황을 재현해 보겠습니다.
-- 테이블 생성
CREATE TABLE emp_test (
empno NUMBER,
ename VARCHAR2(20),
deptno NUMBER,
sal NUMBER
);
-- 테스트 데이터 삽입
INSERT INTO emp_test VALUES (1001, 'KIM', 10, 3000);
INSERT INTO emp_test VALUES (1002, 'LEE', 20, 2500);
COMMIT;
-- WITH CHECK OPTION이 적용된 뷰 생성
CREATE OR REPLACE VIEW v_dept10_emp AS
SELECT empno, ename, deptno, sal
FROM emp_test
WHERE deptno = 10
WITH CHECK OPTION CONSTRAINT chk_dept10;
-- 에러 발생 예시: deptno = 20인 데이터를 뷰를 통해 삽입 시도
-- ORA-01402 발생!
INSERT INTO v_dept10_emp (empno, ename, deptno, sal)
VALUES (1003, 'PARK', 20, 2800);
해결책: 뷰의 조건에 맞는 데이터만 삽입
-- 올바른 삽입 방법: deptno = 10 조건을 만족하는 데이터 삽입
INSERT INTO v_dept10_emp (empno, ename, deptno, sal)
VALUES (1003, 'PARK', 10, 2800);
COMMIT;
-- 또는 조건에 맞지 않는 데이터는 뷰를 통하지 않고 기본 테이블에 직접 삽입
INSERT INTO emp_test (empno, ename, deptno, sal)
VALUES (1004, 'CHOI', 20, 3200);
COMMIT;
원인 2 해결: UPDATE 시 핵심 컬럼 값 변경
-- 에러 발생 예시: deptno를 10에서 30으로 변경 시도
-- ORA-01402 발생!
UPDATE v_dept10_emp
SET deptno = 30
WHERE empno = 1001;
-- 해결책 1: 뷰의 조건 범위 내에서만 수정 (다른 컬럼 수정)
UPDATE v_dept10_emp
SET sal = 3500
WHERE empno = 1001;
COMMIT;
-- 해결책 2: 부서 변경이 반드시 필요하다면 기본 테이블(emp_test)을 직접 수정
UPDATE emp_test
SET deptno = 30
WHERE empno = 1001;
COMMIT;
-- 해결책 3: WITH CHECK OPTION을 제거한 뷰로 재생성 (보안 고려 필요)
CREATE OR REPLACE VIEW v_dept10_emp_nocheck AS
SELECT empno, ename, deptno, sal
FROM emp_test
WHERE deptno = 10;
-- WITH CHECK OPTION 없이 생성하면 조건 밖 데이터도 수정 가능하지만,
-- 데이터 무결성 위험이 있으므로 신중하게 결정해야 합니다.
원인 3 해결: 중첩 뷰(CASCADED CHECK OPTION) 조건 위반
-- 중첩 뷰 구조 예시
CREATE OR REPLACE VIEW v_base AS
SELECT empno, ename, deptno, sal
FROM emp_test
WHERE deptno IN (10, 20)
WITH CHECK OPTION;
-- v_base를 기반으로 한 하위 뷰 (CASCADED CHECK OPTION)
CREATE OR REPLACE VIEW v_high_sal AS
SELECT empno, ename, deptno, sal
FROM v_base
WHERE sal >= 3000
WITH CASCADED CHECK OPTION;
-- 에러 발생: sal < 3000이거나 deptno NOT IN (10,20)인 데이터 삽입 시 ORA-01402 발생
INSERT INTO v_high_sal (empno, ename, deptno, sal)
VALUES (1005, 'JUNG', 30, 3500); -- deptno 조건 위반!
INSERT INTO v_high_sal (empno, ename, deptno, sal)
VALUES (1006, 'HAN', 10, 1500); -- sal 조건 위반!
-- 해결책: 모든 계층의 조건을 만족하는 데이터만 삽입
INSERT INTO v_high_sal (empno, ename, deptno, sal)
VALUES (1007, 'YOO', 10, 4000); -- deptno IN (10,20) AND sal >= 3000 만족
COMMIT;
-- 뷰 정의 확인 쿼리 (문제 원인 파악에 유용)
SELECT view_name, text
FROM user_views
WHERE view_name IN ('V_BASE', 'V_HIGH_SAL');
-- WITH CHECK OPTION 제약 조건 확인
SELECT constraint_name, constraint_type, view_name
FROM user_constraints
WHERE view_name IN ('V_BASE', 'V_HIGH_SAL');
예방 방법
- 뷰 생성 시 WITH CHECK OPTION 사용 목적을 명확히 문서화하고, 관련 개발자에게 공유하기
WITH CHECK OPTION이 적용된 뷰를 생성할 때는 반드시 해당 뷰의 사용 목적과 DML 제약 조건을 팀 내 문서(DDL 명세서, DB 설계서 등)에 명시해야 합니다. 특히 여러 개발자가 공유하는 뷰일 경우, 어떤 조건 하에서만 INSERT/UPDATE가 허용되는지를 명확하게 안내하여 실수를 미연에 방지해야 합니다. 아래와 같이 조건을 사전 검증하는 래퍼 프로시저를 만드는 것도 좋은 방법입니다.
-- 사전 검증 프로시저 예시
CREATE OR REPLACE PROCEDURE insert_dept10_emp (
p_empno IN NUMBER,
p_ename IN VARCHAR2,
p_deptno IN NUMBER,
p_sal IN NUMBER
) AS
BEGIN
IF p_deptno != 10 THEN
RAISE_APPLICATION_ERROR(-20001,
'이 프로시저는 부서 10번 직원만 삽입 가능합니다. (deptno=' || p_deptno || ')');
END IF;
INSERT INTO v_dept10_emp (empno, ename, deptno, sal)
VALUES (p_empno, p_ename, p_deptno, p_sal);
COMMIT;
DBMS_OUTPUT.PUT_LINE('삽입 성공: ' || p_ename);
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END;
/
- 운영 환경 배포 전 뷰 조건 검증 쿼리를 테스트 절차에 포함시키기
DML 작업을 뷰를 통해 수행하기 전에, 대상 데이터가 뷰의 WHERE 조건을 만족하는지 사전에 확인하는 검증 쿼리를 테스트 케이스에 포함하는 것이 중요합니다. 아래 쿼리를 활용하면 뷰의 CHECK OPTION 제약 정보를 빠르게 파악할 수 있습니다.
-- 뷰의 CHECK OPTION 제약 확인
SELECT c.constraint_name,
c.constraint_type,
c.view_name,
c.status
FROM user_constraints c
WHERE c.constraint_type = 'V' -- V = WITH CHECK OPTION
ORDER BY c.view_name;
-- 특정 뷰의 전체 DDL 확인 (조건 파악용)
SELECT dbms_metadata.get_ddl('VIEW', 'V_DEPT10_EMP') AS view_ddl
FROM dual;
관련 에러
- ORA-01779:
cannot modify a column which maps to a non key-preserved table— 조인 뷰(Join View)에서 키 보존이 되지 않는 테이블의 컬럼을 수정하려 할 때 발생하며, ORA-01402와 함께 뷰 DML 제약 관련 에러로 자주 등장합니다. - ORA-01732:
data manipulation operation not legal on this view— 집계 함수, DISTINCT, GROUP BY 등이 포함된 뷰에 DML을 시도할 때 발생하는 에러로, 뷰를 통한 데이터 조작이 불가한 상황에서 나타납니다. - ORA-01733:
virtual column not allowed here— 뷰의 가상 컬럼(표현식 컬럼)에 직접 값을 할당하려 할 때 발생하며, 뷰 DML 오류 시 함께 검토해야 할 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.