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

ORA-04077
2026년 08월 25일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-04077 WHEN clause cannot be used with statement triggers 는?

ORA-04077 에러는 Oracle 데이터베이스에서 트리거(Trigger)를 생성하거나 컴파일할 때, Statement-level 트리거(문장 수준 트리거)에 WHEN 절을 함께 사용하려고 할 경우 발생하는 에러입니다. WHEN 절은 오직 Row-level 트리거(행 수준 트리거), 즉 FOR EACH ROW 옵션이 지정된 트리거에서만 사용이 허용됩니다. 이 에러는 트리거 설계 시 Statement 트리거와 Row 트리거의 근본적인 차이를 이해하지 못했을 때 주로 발생하며, 개발 초기나 타 DBMS에서 Oracle로 마이그레이션하는 과정에서 자주 목격됩니다.


주요 발생 원인

1. Statement 트리거에 WHEN 절을 직접 사용한 경우

가장 흔한 원인으로, FOR EACH ROW 없이 Statement-level 트리거를 정의하면서 WHEN 절로 특정 조건을 필터링하려는 시도에서 발생합니다. WHEN 절은 개별 행(Row)의 데이터에 접근하여 조건을 평가하는 구조이기 때문에, 행 단위로 실행되지 않는 Statement 트리거에서는 논리적으로 적용될 수 없습니다.

2. FOR EACH ROW 옵션을 실수로 누락한 경우

원래 Row-level 트리거로 설계하려 했지만, 코드 작성 중 FOR EACH ROW 키워드를 누락하고 WHEN 절만 남긴 경우입니다. 이런 실수는 기존 트리거를 복사하여 새 트리거를 만들 때 특히 자주 발생하며, 일부 IDE나 편집 도구에서는 컴파일 전에는 에러를 감지하지 못하므로 주의가 필요합니다.

3. 타 DBMS의 트리거 문법을 그대로 이식한 경우

MySQL, SQL Server, PostgreSQL 등의 DBMS에서 사용하던 트리거 문법을 Oracle로 그대로 마이그레이션하면서 발생하는 경우입니다. 각 DBMS마다 트리거의 구문 규칙이 상이하며, 특히 Oracle은 WHEN 절의 사용 범위를 엄격하게 제한하고 있어 마이그레이션 과정에서 이 에러가 빈번하게 나타납니다.


해결 방법

원인 1 해결: WHEN 절 제거 또는 로직을 트리거 본문으로 이동

Statement 트리거에서 WHEN 절을 제거하고, 필요한 조건 분기 처리는 트리거 본문(BEGIN ~ END) 내부에서 IF 문으로 처리합니다.

잘못된 예시 (에러 발생):

-- ORA-04077 발생 예시
CREATE OR REPLACE TRIGGER trg_emp_salary_check
BEFORE UPDATE ON employees
WHEN (NEW.salary > 10000)  -- Statement 트리거에 WHEN절 사용 -> 에러
BEGIN
    DBMS_OUTPUT.PUT_LINE('급여가 10000 초과입니다.');
END;
/

올바른 해결 예시:

-- Statement 트리거에서는 WHEN 절 제거 후 본문에서 처리
CREATE OR REPLACE TRIGGER trg_emp_salary_check
BEFORE UPDATE ON employees
BEGIN
    -- 필요한 로직은 트리거 본문 내에서 처리
    DBMS_OUTPUT.PUT_LINE('employees 테이블 UPDATE 트리거 실행됨');
END;
/

원인 2 해결: FOR EACH ROW 추가하여 Row-level 트리거로 변환

WHEN 절을 반드시 사용해야 한다면, FOR EACH ROW를 추가하여 Row-level 트리거로 변환합니다. 이 경우 WHEN 절 내부에서는 :NEW, :OLD 대신 NEW, OLD를 콜론 없이 사용하는 점에 주의하세요.

-- FOR EACH ROW를 추가하여 Row-level 트리거로 올바르게 수정
CREATE OR REPLACE TRIGGER trg_emp_salary_check
BEFORE UPDATE ON employees
FOR EACH ROW
WHEN (NEW.salary > 10000)  -- Row 트리거에서는 WHEN 절 사용 가능
BEGIN
    DBMS_OUTPUT.PUT_LINE('변경된 급여: ' || :NEW.salary);
    -- 감사 로그 삽입 등 추가 로직
    INSERT INTO salary_audit_log (emp_id, old_salary, new_salary, changed_at)
    VALUES (:NEW.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
/

원인 3 해결: Oracle 문법에 맞게 마이그레이션 재작성

타 DBMS 문법으로 작성된 트리거를 Oracle 표준에 맞게 전면 재작성합니다. 특히 조건 분기가 필요한 경우 아래와 같이 작성합니다.

-- 복합 조건 처리가 필요한 경우의 올바른 Oracle 트리거 작성 예시
CREATE OR REPLACE TRIGGER trg_order_status_update
AFTER INSERT OR UPDATE ON orders
FOR EACH ROW
WHEN (NEW.status = 'COMPLETED' AND NEW.total_amount > 50000)
DECLARE
    v_discount  NUMBER := 0;
BEGIN
    -- 고액 완료 주문에 대해 포인트 적립 처리
    v_discount := :NEW.total_amount * 0.05;

    UPDATE customer_points
    SET    point_balance = point_balance + v_discount
    WHERE  customer_id = :NEW.customer_id;

    DBMS_OUTPUT.PUT_LINE('포인트 적립 완료: ' || v_discount || '점');
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        DBMS_OUTPUT.PUT_LINE('고객 포인트 정보 없음: ' || :NEW.customer_id);
    WHEN OTHERS THEN
        RAISE_APPLICATION_ERROR(-20001, 'ORA-POINT: ' || SQLERRM);
END;
/

현재 트리거 상태 확인 방법

-- 에러가 발생한 트리거의 상태 확인
SELECT trigger_name,
       trigger_type,
       triggering_event,
       status,
       action_type
FROM   user_triggers
WHERE  table_name = 'EMPLOYEES'
ORDER  BY trigger_name;

-- 트리거 소스 코드 확인
SELECT text
FROM   user_source
WHERE  name = 'TRG_EMP_SALARY_CHECK'
AND    type = 'TRIGGER'
ORDER  BY line;

예방 방법

1. 트리거 유형 선택 체크리스트를 표준화하기

트리거를 설계할 때, Statement 트리거와 Row 트리거 중 어느 유형이 적합한지 사전에 명확히 정의하는 설계 체크리스트를 팀 내 표준으로 도입하세요. 특히 “행 단위 데이터 조건 필터링이 필요한가?”라는 질문에 예(Yes)라면 반드시 FOR EACH ROW와 함께 WHEN 절을 사용하도록 코딩 가이드라인을 문서화하고, 코드 리뷰 단계에서 이를 확인하는 절차를 정착시켜야 합니다.

2. 트리거 생성 후 즉시 컴파일 상태 검증 자동화하기

CI/CD 파이프라인이나 배포 스크립트에 아래와 같은 검증 쿼리를 포함시켜, 트리거가 INVALID 상태로 운영 환경에 배포되는 것을 원천 차단하세요. 트리거의 상태가 INVALID이면 해당 DML 작업 중 예기치 않은 에러가 발생할 수 있으므로 배포 직후 반드시 상태를 자동으로 검증하는 습관을 팀 문화로 정착시키는 것이 중요합니다.

-- 배포 후 자동 검증 스크립트 예시
SELECT object_name,
       object_type,
       status,
       last_ddl_time
FROM   user_objects
WHERE  object_type = 'TRIGGER'
AND    status      = 'INVALID';

-- INVALID 트리거 재컴파일
ALTER TRIGGER trg_emp_salary_check COMPILE;

관련 에러

  • ORA-04076: NEW or OLD references not allowed in this context — Statement 트리거에서 :NEW 또는 :OLD 의사 레코드를 참조할 때 발생하며, ORA-04077과 유사한 Row/Statement 트리거 혼용 오류입니다.
  • ORA-04079: invalid trigger specification — 트리거 정의 자체가 잘못된 경우 발생하며, 문법 오류나 지원되지 않는 옵션 조합 시 나타납니다.
  • ORA-04098: trigger 'schema.trigger_name' is invalid and failed re-validation — 트리거가 INVALID 상태에서 실행을 시도할 때 발생하며, 위 에러들로 인해 트리거가 컴파일되지 못한 경우 연쇄적으로 발생합니다.
  • ORA-00900: invalid SQL statement — 트리거 본문의 SQL 구문 오류 시 발생하며, 트리거 디버깅 과정에서 함께 확인해야 할 에러입니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기