2026년 07월 28일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-01731 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-01731 circular view definition encountered 는?
ORA-01731 에러는 뷰(View)를 생성하거나 참조할 때 순환 참조(Circular Reference)가 발생하는 경우에 나타납니다. 쉽게 말해, 뷰 A가 뷰 B를 참조하고, 뷰 B가 다시 뷰 A를 참조하는 구조처럼 뷰 정의가 서로 맞물려 무한 루프를 형성할 때 Oracle이 이 에러를 발생시킵니다. 이 에러는 복잡한 데이터 모델 환경이나 여러 개발자가 동시에 뷰를 생성·수정하는 팀 환경에서 특히 자주 발생하며, 런타임 시 쿼리 실행이 불가능해지기 때문에 즉각적인 조치가 필요합니다.
주요 발생 원인
1. 두 개의 뷰가 서로를 직접 참조하는 경우 (직접 순환 참조)
가장 흔한 원인으로, VIEW_A가 VIEW_B를 SELECT하고 VIEW_B가 다시 VIEW_A를 SELECT하는 구조입니다. 이러한 직접 순환 참조는 뷰를 생성하는 시점에 Oracle이 곧바로 감지하지 못할 수도 있으나, 실제 쿼리 실행 시 또는 뷰 컴파일 시점에 ORA-01731이 발생합니다. 특히 기존 뷰를 수정할 때 이미 자신을 참조하는 뷰가 존재한다는 사실을 인지하지 못한 채 다른 뷰를 추가하면 순환 참조가 만들어지는 경우가 많습니다.
2. 세 개 이상의 뷰가 체인 형태로 순환 참조하는 경우 (간접 순환 참조)
VIEW_A → VIEW_B → VIEW_C → VIEW_A처럼 세 개 이상의 뷰가 연쇄적으로 서로를 참조하는 경우입니다. 이 경우에는 개발자가 각 뷰를 개별적으로 보면 순환 참조를 쉽게 인지하지 못하기 때문에 더욱 디버깅이 까다롭습니다. 특히 뷰의 수가 많아질수록 참조 관계가 복잡해져 간접 순환 참조를 추적하기 어려워지므로, 체계적인 의존성 관리가 필요합니다.
3. CREATE OR REPLACE VIEW로 뷰를 재정의할 때 의존성을 고려하지 않은 경우
기존 뷰를 CREATE OR REPLACE VIEW 구문으로 수정하면서, 수정된 뷰의 SELECT 절에 자신을 참조하는 다른 뷰를 실수로 포함시키는 경우입니다. 뷰가 처음 생성될 때는 문제가 없었으나, 시간이 지나면서 뷰 구조가 점점 복잡해지고 의존성을 추적하지 않은 채 수정이 반복되면 순환 참조가 생길 수 있습니다. 이 경우 에러가 즉시 발생하지 않고 나중에 뷰를 조회할 때 발생하기도 하여 원인 파악이 더 어렵습니다.
해결 방법
원인 1 해결: 순환 참조 구조 파악 및 뷰 재설계
먼저 아래 쿼리로 뷰 간의 의존성을 확인합니다.
-- 특정 뷰의 의존성 확인 (어떤 객체를 참조하는지 조회)
SELECT name, type, referenced_name, referenced_type
FROM user_dependencies
WHERE type = 'VIEW'
ORDER BY name, referenced_name;
-- 순환 참조 예시 (문제 상황)
-- VIEW_A 생성
CREATE OR REPLACE VIEW view_a AS
SELECT a.emp_id, a.emp_name, b.dept_name
FROM employees a, view_b b -- view_b를 참조
WHERE a.dept_id = b.dept_id;
-- VIEW_B 생성 (view_a를 다시 참조 → 순환 발생)
CREATE OR REPLACE VIEW view_b AS
SELECT b.dept_id, b.dept_name, a.emp_name
FROM departments b, view_a a -- view_a를 참조 → ORA-01731 발생!
WHERE b.dept_id = a.dept_id;
-- 해결: 뷰 대신 기본 테이블을 직접 참조하도록 재설계
-- VIEW_A 수정
CREATE OR REPLACE VIEW view_a AS
SELECT a.emp_id, a.emp_name, b.dept_name
FROM employees a, departments b -- 기본 테이블 직접 참조
WHERE a.dept_id = b.dept_id;
-- VIEW_B 수정
CREATE OR REPLACE VIEW view_b AS
SELECT b.dept_id, b.dept_name, COUNT(a.emp_id) AS emp_count
FROM departments b, employees a -- 기본 테이블 직접 참조
WHERE b.dept_id = a.dept_id (+)
GROUP BY b.dept_id, b.dept_name;
원인 2 해결: 간접 순환 참조 추적 및 의존성 체인 분석
-- 계층적 쿼리로 뷰 의존성 체인을 시각화
SELECT LPAD(' ', 2*(LEVEL-1)) || name AS view_name,
referenced_name,
LEVEL AS depth
FROM user_dependencies
WHERE type = 'VIEW'
AND referenced_type = 'VIEW'
CONNECT BY PRIOR name = referenced_name
START WITH referenced_name = 'VIEW_A' -- 시작 뷰 이름 지정
ORDER SIBLINGS BY name;
-- 간접 순환 참조 예시 (A → B → C → A)
CREATE OR REPLACE VIEW view_c AS
SELECT c.product_id, c.product_name, a.emp_name
FROM products c, view_a a -- view_a를 참조
WHERE c.sales_emp_id = a.emp_id;
-- 해결: 중간 뷰(view_c)가 기본 테이블을 참조하도록 수정
CREATE OR REPLACE VIEW view_c AS
SELECT c.product_id, c.product_name, e.emp_name
FROM products c, employees e -- 기본 테이블 직접 참조
WHERE c.sales_emp_id = e.emp_id;
원인 3 해결: 뷰 재정의 전 의존성 검증 절차 수행
-- 뷰를 수정하기 전 현재 뷰 정의 확인
SELECT text
FROM user_views
WHERE view_name = 'VIEW_A';
-- 해당 뷰를 참조하는 다른 뷰 목록 조회 (수정 전 반드시 확인)
SELECT name AS dependent_view,
referenced_name AS referenced_view
FROM user_dependencies
WHERE referenced_name = 'VIEW_A'
AND type = 'VIEW';
-- 잘못된 수정 방식 (순환 참조 유발)
CREATE OR REPLACE VIEW view_dept_summary AS
SELECT d.dept_id,
d.dept_name,
v.total_salary
FROM departments d,
view_dept_summary v -- 자기 자신을 참조! ORA-01731 발생
WHERE d.dept_id = v.dept_id;
-- 올바른 수정 방식 (서브쿼리로 대체)
CREATE OR REPLACE VIEW view_dept_summary AS
SELECT d.dept_id,
d.dept_name,
NVL(sal.total_salary, 0) AS total_salary
FROM departments d,
(SELECT dept_id, SUM(salary) AS total_salary
FROM employees
GROUP BY dept_id) sal -- 인라인 뷰로 대체
WHERE d.dept_id = sal.dept_id (+);
예방 방법
1. 뷰 의존성 관리 문서화 및 변경 전 사전 검증 프로세스 도입
뷰를 생성하거나 수정하기 전에 반드시 USER_DEPENDENCIES 또는 ALL_DEPENDENCIES 딕셔너리 뷰를 조회하여 참조 관계를 확인하는 절차를 팀 표준으로 만들어야 합니다. 특히 여러 개발자가 동시에 작업하는 환경에서는 ERD(Entity Relationship Diagram)나 별도의 뷰 의존성 문서를 유지·관리하고, 코드 리뷰 시 뷰 참조 구조를 반드시 점검하는 문화를 정착시키는 것이 중요합니다.
2. 뷰 계층 구조 단순화 및 깊이 제한 정책 적용
뷰가 다른 뷰를 참조하는 깊이(Depth)를 팀 내 규약으로 최대 2~3단계로 제한하는 것을 권장합니다. 깊이가 깊어질수록 순환 참조 발생 가능성이 높아지고 성능도 저하될 수 있으므로, 복잡한 비즈니스 로직은 뷰의 중첩 대신 인라인 뷰(Inline View)나 CTE(Common Table Expression, WITH 절)를 활용하는 방향으로 설계하는 것이 좋습니다.
관련 에러
- ORA-00942: 테이블 또는 뷰가 존재하지 않을 때 발생하며, 뷰 생성 시 참조 객체가 없는 경우에도 나타납니다.
- ORA-04063: 뷰에 오류가 있어 컴파일에 실패했을 때 발생하며, 순환 참조로 인해 뷰가 INVALID 상태가 된 경우 함께 확인해야 합니다.
- ORA-32004: 초기화 파라미터 관련 에러이나, 뷰 의존성 문제와 혼동되는 경우가 있습니다.
- ORA-01775: 동의어(Synonym)의 순환 참조 시 발생하는 에러로, 뷰의 순환 참조와 유사한 개념입니다. 동의어가 뷰를 경유하여 다시 동의어를 참조하는 구조에서 발생할 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.