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

ORA-04072
2026년 08월 24일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-04072 invalid trigger type 는?

ORA-04072 에러는 Oracle 데이터베이스에서 트리거(Trigger)를 생성하거나 수정할 때 유효하지 않은 트리거 타입을 지정했을 때 발생하는 에러입니다. Oracle은 트리거의 종류(BEFORE, AFTER, INSTEAD OF 등)와 이벤트(INSERT, UPDATE, DELETE 등)의 조합이 문법적으로 올바르게 정의되어야 하며, 이를 위반할 경우 이 에러를 반환합니다. 예를 들어 테이블에 INSTEAD OF 트리거를 잘못 적용하거나, 트리거 타입 키워드를 오타 없이 정확하게 작성하지 않으면 이 에러가 발생합니다.


주요 발생 원인

1. INSTEAD OF 트리거를 일반 테이블에 적용하는 경우

INSTEAD OF 트리거는 오직 뷰(VIEW) 에만 사용할 수 있는 트리거 타입입니다. 일반 테이블(TABLE)에 INSTEAD OF 트리거를 생성하려고 하면 Oracle은 이를 유효하지 않은 트리거 타입으로 인식하고 ORA-04072 에러를 발생시킵니다. 이는 실무에서 개발자가 뷰와 테이블을 혼동하거나, 기존 뷰를 테이블로 변경한 후 트리거를 그대로 유지하려 할 때 자주 발생합니다.

2. 트리거 타입 키워드 오타 또는 잘못된 문법 사용

Oracle 트리거의 타입 키워드(BEFORE, AFTER, INSTEAD OF)를 잘못 입력하거나, 지원하지 않는 키워드를 사용하면 파서(Parser)가 해당 구문을 인식하지 못해 에러가 발생합니다. 예를 들어 BEFOR, INSTED OF 같은 오타, 혹은 다른 DBMS에서 사용하는 트리거 타입 문법을 Oracle에 그대로 옮겨 쓰는 경우 이 문제가 발생합니다. 특히 타 DBMS(MySQL, MSSQL 등)에서 Oracle로 마이그레이션할 때 자주 나타나는 실수입니다.

3. 복합 트리거(Compound Trigger) 또는 시스템 트리거 문법 오류

Oracle 11g 이상에서 지원하는 복합 트리거(Compound Trigger)나, DDL/시스템 이벤트에 반응하는 시스템 트리거(System Trigger)를 잘못된 타입으로 선언할 때 이 에러가 발생할 수 있습니다. 복합 트리거는 단일 트리거 본문에 여러 타이밍 포인트(BEFORE STATEMENT, BEFORE EACH ROW 등)를 포함해야 하며, 이 구조를 잘못 작성하면 Oracle이 트리거 타입을 인식하지 못합니다. 또한 스키마 레벨 또는 데이터베이스 레벨의 DDL 이벤트 트리거를 잘못된 오브젝트에 지정할 때도 이 에러가 나타납니다.


해결 방법

원인 1: INSTEAD OF 트리거를 뷰에 올바르게 적용

INSTEAD OF 트리거는 반드시 뷰에만 적용해야 합니다. 아래 예제를 통해 올바른 사용법을 확인하세요.

잘못된 예 (테이블에 INSTEAD OF 적용 → ORA-04072 발생):

-- 일반 테이블에 INSTEAD OF 트리거 적용 시 에러 발생
CREATE OR REPLACE TRIGGER trg_emp_instead
INSTEAD OF INSERT ON employees   -- employees가 테이블이면 에러!
FOR EACH ROW
BEGIN
    NULL;
END;
/
-- ORA-04072: invalid trigger type

올바른 예 (뷰에 INSTEAD OF 적용):

-- 먼저 뷰를 생성합니다
CREATE OR REPLACE VIEW v_emp_dept AS
    SELECT e.employee_id,
           e.first_name,
           e.last_name,
           e.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_ins
INSTEAD OF INSERT ON v_emp_dept   -- 뷰에 적용 → 정상 동작
FOR EACH ROW
BEGIN
    INSERT INTO employees (employee_id, first_name, last_name, salary)
    VALUES (:NEW.employee_id, :NEW.first_name, :NEW.last_name, :NEW.salary);
END;
/
-- 트리거가 정상적으로 생성됩니다

원인 2: 올바른 트리거 타입 키워드 사용

트리거 타입을 정확한 Oracle 문법에 맞게 작성해야 합니다.

잘못된 예 (오타로 인한 에러):

-- 오타: BEFOR (BEFORE가 올바른 키워드)
CREATE OR REPLACE TRIGGER trg_emp_salary_check
BEFOR UPDATE ON employees        -- 오타! ORA-04072 발생
FOR EACH ROW
BEGIN
    IF :NEW.salary < 0 THEN
        RAISE_APPLICATION_ERROR(-20001, '급여는 0보다 작을 수 없습니다.');
    END IF;
END;
/

올바른 예:

-- BEFORE, AFTER, INSTEAD OF 중 정확한 키워드 사용
CREATE OR REPLACE TRIGGER trg_emp_salary_check
BEFORE UPDATE ON employees       -- 정확한 키워드
FOR EACH ROW
BEGIN
    IF :NEW.salary < 0 THEN
        RAISE_APPLICATION_ERROR(-20001, '급여는 0보다 작을 수 없습니다.');
    END IF;
END;
/

-- AFTER 트리거 예시
CREATE OR REPLACE TRIGGER trg_emp_audit
AFTER INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
DECLARE
    v_action VARCHAR2(10);
BEGIN
    IF INSERTING THEN
        v_action := 'INSERT';
    ELSIF UPDATING THEN
        v_action := 'UPDATE';
    ELSE
        v_action := 'DELETE';
    END IF;

    INSERT INTO emp_audit_log (action_type, employee_id, action_date)
    VALUES (v_action, :OLD.employee_id, SYSDATE);
END;
/

원인 3: 복합 트리거(Compound Trigger) 올바른 선언

-- 잘못된 복합 트리거 예 (타입 혼용 → 에러 유발 가능)
-- 단순 BEFORE/AFTER를 COMPOUND로 선언하지 않은 경우

-- 올바른 복합 트리거 (Oracle 11g 이상)
CREATE OR REPLACE TRIGGER trg_emp_compound
FOR INSERT OR UPDATE ON employees
COMPOUND TRIGGER

    -- 패키지 수준 변수 선언
    TYPE t_emp_ids IS TABLE OF employees.employee_id%TYPE;
    v_emp_ids t_emp_ids := t_emp_ids();

    BEFORE STATEMENT IS
    BEGIN
        -- 문장 실행 전 처리
        DBMS_OUTPUT.PUT_LINE('트랜잭션 시작: ' || TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
    END BEFORE STATEMENT;

    BEFORE EACH ROW IS
    BEGIN
        -- 각 행 처리 전
        IF :NEW.salary > 100000 THEN
            :NEW.salary := 100000;  -- 최대 급여 제한
        END IF;
    END BEFORE EACH ROW;

    AFTER EACH ROW IS
    BEGIN
        -- 각 행 처리 후 ID 수집
        v_emp_ids.EXTEND;
        v_emp_ids(v_emp_ids.LAST) := :NEW.employee_id;
    END AFTER EACH ROW;

    AFTER STATEMENT IS
    BEGIN
        -- 문장 실행 후 일괄 처리
        FOR i IN 1..v_emp_ids.COUNT LOOP
            INSERT INTO emp_change_log (employee_id, changed_at)
            VALUES (v_emp_ids(i), SYSDATE);
        END LOOP;
        DBMS_OUTPUT.PUT_LINE('처리된 행 수: ' || v_emp_ids.COUNT);
    END AFTER STATEMENT;

END trg_emp_compound;
/

트리거 상태 확인 및 디버깅

-- 현재 스키마의 트리거 목록 및 상태 확인
SELECT trigger_name,
       trigger_type,
       triggering_event,
       table_name,
       status
FROM   user_triggers
ORDER  BY trigger_name;

-- 특정 트리거의 상세 정보 확인
SELECT trigger_name,
       trigger_type,
       triggering_event,
       table_owner,
       table_name,
       trigger_body
FROM   user_triggers
WHERE  trigger_name = 'TRG_EMP_COMPOUND';

-- 비활성화된 트리거 재활성화
ALTER TRIGGER trg_emp_compound ENABLE;

-- 트리거 비활성화
ALTER TRIGGER trg_emp_compound DISABLE;

-- 특정 테이블의 모든 트리거 비활성화
ALTER TABLE employees DISABLE ALL TRIGGERS;

-- 특정 테이블의 모든 트리거 활성화
ALTER TABLE employees ENABLE ALL TRIGGERS;

예방 방법

1. 트리거 생성 전 대상 오브젝트 유형 반드시 확인

트리거를 작성하기 전에 대상이 테이블인지 뷰인지 반드시 확인하는 습관을 갖는 것이 중요합니다. INSTEAD OF 트리거는 뷰 전용이라는 원칙을 팀 전체의 코딩 표준으로 문서화하고, 코드 리뷰 체크리스트에 반드시 포함시키세요. 또한 DDL 스크립트 실행 전에 아래 쿼리로 오브젝트 유형을 사전 검증하는 절차를 CI/CD 파이프라인에 포함시키는 것을 권장합니다.

-- 트리거 생성 전 대상 오브젝트 유형 확인
SELECT object_name,
       object_type,
       status
FROM   user_objects
WHERE  object_name = UPPER('대상_오브젝트명')
AND    object_type IN ('TABLE', 'VIEW');

2. 트리거 DDL 스크립트 템플릿 표준화

팀 내에서 트리거 작성 시 표준 템플릿을 미리 만들어 두고 재사용하면, 오타나 문법 오류로 인한 ORA-04072 에러를 효과적으로 예방할 수 있습니다. 아래와 같은 검증 로직이 포함된 래퍼(Wrapper) 프로시저를 두거나, 개발 환경에서 반드시 컴파일 검증 단계를 거치도록 프로세스를 수립하세요.

-- 트리거 생성 후 유효성 자동 검증 스크립트
BEGIN
    FOR r IN (
        SELECT trigger_name, status
        FROM   user_triggers
        WHERE  status = 'DISABLED'
           OR  trigger_name IN (
               SELECT name
               FROM   user_errors
               WHERE  type = 'TRIGGER'
           )
    ) LOOP
        DBMS_OUTPUT.PUT_LINE('[경고] 트리거 이상 감지: ' || r.trigger_name || ' / 상태: ' || r.status);
    END LOOP;
END;
/

관련 에러

  • ORA-04071: missing BEFORE, AFTER or INSTEAD OF keyword — 트리거 타입 키워드 자체가 누락된 경우 발생하며, ORA-04072와 함께 자주 나타나는 관련 에러입니다.
  • ORA-04073: column list not valid for this trigger type — FOR EACH ROW 트리거에서 컬럼 목록을 잘못 지정했을 때 발생합니다.
  • ORA-04074: invalid REFERENCING name — 트리거 내에서 OLD, NEW 참조 이름을 잘못 선언했을 때 발생합니다.
  • ORA-04079: invalid trigger specification — 트리거 전체 구문이 유효하지 않을 때 발생하는 포괄적 에러로, ORA-04072와 함께 확인해야 합니다.
  • ORA-25002: cannot create INSTEAD OF triggers on tables — Oracle이 INSTEAD OF 트리거를 테이블에 생성하려 할 때 명시적으로 반환하는 에러로, ORA-04072의 원인 중 하나와 직접 연관됩니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기