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

ORA-01733
2026년 07월 29일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-01733 virtual column not allowed here 는?

ORA-01733 에러는 Oracle 데이터베이스에서 가상 컬럼(Virtual Column)에 대해 DML 작업(INSERT, UPDATE, DELETE)을 시도하거나, 가상 컬럼을 허용하지 않는 문맥에서 해당 컬럼을 사용할 때 발생합니다. 가상 컬럼은 실제 데이터를 저장하지 않고 다른 컬럼의 표현식(Expression)으로부터 계산되어 반환되는 읽기 전용(Read-Only) 컬럼이기 때문에, 직접적인 값 할당이 불가능합니다. 특히 뷰(View)의 특정 컬럼이나 표현식으로 정의된 컬럼에 데이터를 삽입하거나 수정하려 할 때 자주 발생하며, 초보 개발자뿐 아니라 숙련된 DBA도 복잡한 뷰 구조에서 간과하기 쉬운 에러입니다.


주요 발생 원인

  • 뷰(View)의 표현식 컬럼에 DML 시도

가장 흔한 원인으로, 뷰가 집계 함수(SUM, AVG, COUNT 등), 산술 연산, 또는 함수 표현식을 포함한 컬럼을 가진 경우, 그 컬럼에 INSERT 또는 UPDATE를 시도할 때 발생합니다. 예를 들어 SELECT salary * 12 AS annual_salary FROM employees 형태로 정의된 뷰에서 annual_salary 컬럼을 직접 수정하려 하면 Oracle은 해당 컬럼의 원본 테이블 컬럼을 특정할 수 없어 이 에러를 발생시킵니다. 뷰는 단순 컬럼 매핑이 아닌 복합 표현식일 경우 본질적으로 수정 불가능합니다.

  • 테이블의 가상 컬럼(Virtual Column)에 직접 값 할당

Oracle 11g부터 도입된 테이블 레벨 가상 컬럼(Virtual Column)은 GENERATED ALWAYS AS (expression) VIRTUAL 구문으로 정의되며, 이 컬럼에 직접 INSERT 또는 UPDATE를 시도할 경우 ORA-01733이 발생합니다. 가상 컬럼은 데이터베이스 엔진이 쿼리 시점에 자동으로 계산해주는 파생 값이므로, 사용자가 임의로 값을 지정할 수 없습니다. INSERT 문에서 명시적으로 가상 컬럼을 컬럼 리스트에 포함시키거나 VALUES 절에 값을 지정하는 것 모두 이 에러를 유발합니다.

  • WITH READ ONLY 또는 복합 뷰에 대한 DML 시도

뷰가 WITH READ ONLY 옵션으로 생성된 경우, 또는 여러 테이블을 JOIN한 복합 뷰(Complex View)에서 키-보존(Key-Preserved)되지 않은 테이블의 컬럼을 수정하려 할 때 이 에러가 발생할 수 있습니다. 또한 DISTINCT, GROUP BY, UNION, CONNECT BY 등을 포함한 뷰의 경우에도 기본적으로 DML이 불가능합니다. 이러한 뷰에는 INSTEAD OF 트리거를 사용해야만 DML 작업이 가능합니다.


해결 방법

원인 1 해결: 뷰 대신 기본 테이블에 직접 DML 수행

표현식 컬럼을 포함한 뷰에 DML을 시도하는 대신, 원본 기본 테이블(Base Table)에 직접 DML을 수행하세요.

-- 문제가 되는 상황: 표현식 컬럼이 포함된 뷰 생성
CREATE OR REPLACE VIEW v_emp_salary AS
SELECT
    employee_id,
    first_name,
    last_name,
    salary,
    salary * 12 AS annual_salary,  -- 가상 표현식 컬럼
    department_id
FROM employees;

-- ORA-01733 발생하는 잘못된 DML
UPDATE v_emp_salary
SET annual_salary = 60000  -- 에러 발생!
WHERE employee_id = 100;

-- 올바른 해결 방법: 기본 테이블에 직접 UPDATE
UPDATE employees
SET salary = 60000 / 12  -- 연봉을 월급으로 환산하여 기본 테이블에 적용
WHERE employee_id = 100;

-- 또는 salary 컬럼을 직접 수정
UPDATE employees
SET salary = 5000
WHERE employee_id = 100;

COMMIT;

원인 2 해결: 가상 컬럼을 INSERT/UPDATE 대상에서 제외

테이블 레벨 가상 컬럼이 포함된 경우, INSERT 문의 컬럼 리스트에서 가상 컬럼을 명시적으로 제외하거나, 가상 컬럼에 DEFAULT 키워드를 사용하세요.

-- 가상 컬럼이 포함된 테이블 예시
CREATE TABLE order_items (
    order_id      NUMBER,
    product_id    NUMBER,
    quantity      NUMBER,
    unit_price    NUMBER(10,2),
    total_amount  NUMBER(12,2) GENERATED ALWAYS AS (quantity * unit_price) VIRTUAL
    -- total_amount는 가상 컬럼: 직접 값 입력 불가
);

-- ORA-01733 발생하는 잘못된 INSERT
INSERT INTO order_items (order_id, product_id, quantity, unit_price, total_amount)
VALUES (1001, 205, 3, 150.00, 450.00);  -- 에러 발생!

-- 올바른 해결 방법 1: 가상 컬럼을 컬럼 리스트에서 제외
INSERT INTO order_items (order_id, product_id, quantity, unit_price)
VALUES (1001, 205, 3, 150.00);  -- total_amount는 자동 계산됨

-- 올바른 해결 방법 2: DEFAULT 키워드 사용
INSERT INTO order_items (order_id, product_id, quantity, unit_price, total_amount)
VALUES (1001, 205, 3, 150.00, DEFAULT);  -- DEFAULT 지정으로 자동 계산

-- UPDATE도 동일하게 가상 컬럼 제외
UPDATE order_items
SET quantity = 5, unit_price = 150.00  -- total_amount는 자동 재계산됨
WHERE order_id = 1001;

COMMIT;

-- 가상 컬럼 확인 방법
SELECT column_name, data_type, virtual_column
FROM user_tab_columns
WHERE table_name = 'ORDER_ITEMS';

원인 3 해결: INSTEAD OF 트리거 활용

복합 뷰나 READ ONLY 뷰에 DML이 필요한 경우, INSTEAD OF 트리거를 생성하여 DML 로직을 우회 처리합니다.

-- 복합 뷰 예시 (두 테이블 JOIN)
CREATE OR REPLACE VIEW v_employee_dept AS
SELECT
    e.employee_id,
    e.first_name,
    e.last_name,
    e.salary,
    e.salary * 12 AS annual_salary,  -- 가상 표현식 컬럼
    d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id;

-- INSTEAD OF 트리거 생성으로 해결
CREATE OR REPLACE TRIGGER trg_v_emp_dept_update
INSTEAD OF UPDATE ON v_employee_dept
FOR EACH ROW
BEGIN
    -- 가상 컬럼(annual_salary)을 통해 월급을 역산하여 기본 테이블 업데이트
    IF :NEW.annual_salary IS NOT NULL THEN
        UPDATE employees
        SET salary = :NEW.annual_salary / 12
        WHERE employee_id = :OLD.employee_id;
    END IF;

    -- salary 직접 수정도 처리
    IF :NEW.salary IS NOT NULL AND :NEW.annual_salary IS NULL THEN
        UPDATE employees
        SET salary = :NEW.salary
        WHERE employee_id = :OLD.employee_id;
    END IF;
END;
/

-- 트리거 생성 후 뷰를 통한 UPDATE 가능
UPDATE v_employee_dept
SET annual_salary = 72000
WHERE employee_id = 100;

COMMIT;

-- 뷰의 DML 가능 여부 사전 확인
SELECT view_name, text
FROM user_views
WHERE view_name = 'V_EMPLOYEE_DEPT';

예방 방법

  • DDL 설계 시 가상 컬럼 및 뷰 구조 문서화 철저히 수행

테이블 설계 단계에서 가상 컬럼(VIRTUAL)과 일반 컬럼을 명확히 구분하고, 팀 내 공유 문서나 데이터 딕셔너리 뷰(USER_TAB_COLUMNS의 VIRTUAL_COLUMN 컬럼)를 통해 가상 컬럼 목록을 항상 최신 상태로 유지하세요. 애플리케이션 개발 단계에서 DML을 작성하는 개발자가 실수로 가상 컬럼을 포함시키지 않도록, ORM 프레임워크 설정이나 코드 리뷰 프로세스에 가상 컬럼 제외 규칙을 명시적으로 포함시키는 것이 좋습니다.

“`sql

— 가상 컬럼 사전 확인 쿼리 (개발/배포 전 점검용)

SELECT

table_name,

column_name,

data_type,

virtual_column,

data_default

FROM user_tab_columns

WHERE virtual_column = ‘YES’

ORDER BY table_name, column_id;

“`

  • 뷰 설계 시 DML 가능 여부를 명시적으로 설정하고 검증

뷰를 생성할 때 DML이 필요하지 않은 조회 전용 뷰는 반드시 WITH READ ONLY 옵션을 명시하여 실수로 DML이 시도되는 것을 방지하고, DML이 필요한 복합 뷰에는 사전에 INSTEAD OF 트리거를 함께 구현하는 것을 표준 개발 절차로 삼으세요. 또한 뷰 생성 후 SELECT * FROM user_updatable_columns WHERE table_name = '뷰이름'을 통해 수정 가능한 컬럼 목록을 확인하는 습관을 들이면 사전에 잠재적인 ORA-01733 상황을 예방할 수 있습니다.

“`sql

— 뷰의 수정 가능 컬럼 사전 확인

SELECT

column_name,

updatable,

insertable,

deletable

FROM user_updatable_columns

WHERE table_name = ‘V_EMP_SALARY’;

— 조회 전용 뷰에는 WITH READ ONLY 명시

CREATE OR REPLACE VIEW v_emp_report AS

SELECT

employee_id,

first_name || ‘ ‘ || last_name AS full_name,

salary * 12 AS annual_salary,

hire_date

FROM employees

WITH READ ONLY; — DML 시도 시 명확한 에러 메시지 반환

“`


관련 에러

  • ORA-01732: data manipulation operation not legal on this view — 뷰에 대한 DML이 허용되지 않을 때 발생하며, ORA-01733과 함께 뷰 관련 DML 에러의 대표적인 쌍입니다. ORA-01732는 뷰 자체에 DML이 불가한 경우이고, ORA-01733은 특정 컬럼(가상 컬럼/표현식 컬럼)이 문제인 경우입니다.
  • ORA-54013: INSERT operation disallowed on virtual columns — Oracle 11g 이상에서 테이블의 가상 컬럼에 직접 INSERT를 시도할 때 발생하는 에러로, ORA-01733과 유사한 맥락에서 나타납니다.
  • ORA-01779: cannot modify a column which maps to a non key-preserved table — 복합 뷰에서 키-보존 테이블이 아닌 테이블의 컬럼을 수정하려 할 때 발생하며, INSTEAD OF 트리거로 해결하는 접근법이 동일합니다.
  • ORA-01776: cannot modify more than one base table through a join view — JOIN 뷰를 통해 여러 기본 테이블을 동시에 수정하려 할 때 발생합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기