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

ORA-00984
2026년 06월 24일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-00984 column not allowed here 는?

ORA-00984 에러는 SQL 문장에서 컬럼명이 허용되지 않는 위치에 사용되었을 때 발생하는 오류입니다. 주로 INSERT 문의 VALUES 절, DEFAULT 절, 또는 제약 조건 정의 부분에서 컬럼명을 직접 참조하려 할 때 Oracle 옵티마이저가 이를 감지하고 에러를 반환합니다. 예를 들어, VALUES 절에 리터럴 값이나 바인드 변수 대신 다른 테이블의 컬럼명을 잘못 기재하거나, DDL 문장 내 기본값 지정 시 컬럼을 참조하는 경우 이 에러가 발생합니다.


주요 발생 원인

  • INSERT 문의 VALUES 절에 컬럼명을 직접 사용한 경우

가장 흔한 원인으로, INSERT INTO ... VALUES(...) 구문에서 실제 값 대신 다른 테이블의 컬럼명 또는 현재 테이블의 컬럼명을 그대로 기입하는 실수입니다. VALUES 절은 리터럴 값, 함수, 바인드 변수, 시퀀스의 NEXTVAL/CURRVAL 등만 허용하며, 컬럼명을 직접 참조하는 것은 문법적으로 허용되지 않습니다. 이 경우 INSERT INTO ... SELECT ... 구문으로 변경하거나 올바른 리터럴 값을 제공해야 합니다.

  • DDL 문장(CREATE TABLE, ALTER TABLE)에서 DEFAULT 값으로 컬럼을 참조한 경우

테이블 생성 또는 컬럼 추가 시 DEFAULT 키워드 다음에 다른 컬럼명을 참조하는 것은 Oracle에서 허용되지 않습니다. DEFAULT 절은 상수 값, SQL 함수(SYSDATE, SYSTIMESTAMP, USER 등), 시퀀스(NEXTVAL, Oracle 12c 이상)만 허용합니다. 개발자들이 다른 DBMS(예: MySQL의 계산된 컬럼 개념)에 익숙한 경우 이 실수를 자주 범합니다.

  • CHECK 제약 조건 또는 함수 기반 인덱스 정의 오류

CHECK 제약 조건 내에서 잘못된 컬럼 참조 방식을 사용하거나, 서브쿼리 내부에서 외부 쿼리의 컬럼을 부적절하게 참조하는 경우에도 이 에러가 발생할 수 있습니다. 특히 복잡한 DML 또는 PL/SQL 블록 내에서 동적 SQL을 구성할 때 문자열 조합 실수로 컬럼명이 VALUES 절 내에 들어가는 경우가 실무에서 종종 나타납니다.


해결 방법

원인 1 해결: INSERT VALUES 절 수정

잘못된 예시:

-- employees 테이블에서 salary 컬럼값을 그대로 쓰려고 잘못 작성한 경우
INSERT INTO salary_backup (emp_id, sal_amount, backup_date)
VALUES (emp_id, salary, SYSDATE);
-- ORA-00984: column not allowed here 발생

올바른 예시 1 – 리터럴 값 사용:

INSERT INTO salary_backup (emp_id, sal_amount, backup_date)
VALUES (1001, 5000000, SYSDATE);

올바른 예시 2 – INSERT INTO … SELECT 구문으로 변경:

-- 다른 테이블의 컬럼 값을 가져와 삽입하는 올바른 방법
INSERT INTO salary_backup (emp_id, sal_amount, backup_date)
SELECT emp_id, salary, SYSDATE
FROM employees
WHERE department_id = 10;

올바른 예시 3 – PL/SQL에서 변수 활용:

DECLARE
  v_emp_id    employees.emp_id%TYPE;
  v_salary    employees.salary%TYPE;
BEGIN
  v_emp_id := 1001;
  v_salary := 5000000;

  INSERT INTO salary_backup (emp_id, sal_amount, backup_date)
  VALUES (v_emp_id, v_salary, SYSDATE);

  COMMIT;
END;
/

원인 2 해결: DEFAULT 절 수정

잘못된 예시:

-- 다른 컬럼을 DEFAULT 값으로 참조하려는 잘못된 DDL
CREATE TABLE order_detail (
  order_id     NUMBER,
  order_date   DATE DEFAULT SYSDATE,
  confirm_date DATE DEFAULT order_date  -- ORA-00984 발생!
);

올바른 예시 1 – 허용되는 DEFAULT 값 사용:

-- DEFAULT에는 상수, SQL 함수, 시퀀스(12c 이상)만 허용
CREATE TABLE order_detail (
  order_id     NUMBER,
  order_date   DATE DEFAULT SYSDATE,
  confirm_date DATE DEFAULT SYSDATE,  -- 동일한 함수 사용
  status       VARCHAR2(20) DEFAULT 'PENDING',
  created_by   VARCHAR2(50) DEFAULT USER
);

올바른 예시 2 – Oracle 12c 이상 시퀀스 DEFAULT 사용:

CREATE SEQUENCE order_seq START WITH 1 INCREMENT BY 1;

CREATE TABLE order_detail (
  order_id     NUMBER DEFAULT order_seq.NEXTVAL,
  order_date   DATE   DEFAULT SYSDATE,
  status       VARCHAR2(20) DEFAULT 'PENDING'
);

올바른 예시 3 – 컬럼 간 의존 값은 트리거로 처리:

-- confirm_date를 order_date 기준으로 설정하려면 트리거 활용
CREATE OR REPLACE TRIGGER trg_order_detail_bi
BEFORE INSERT ON order_detail
FOR EACH ROW
BEGIN
  IF :NEW.confirm_date IS NULL THEN
    :NEW.confirm_date := :NEW.order_date;
  END IF;
END;
/

원인 3 해결: 동적 SQL 및 복잡한 쿼리 수정

잘못된 동적 SQL 예시:

-- 동적 SQL 문자열 조합 시 실수로 컬럼명이 VALUES에 들어간 경우
DECLARE
  v_col_name VARCHAR2(30) := 'SALARY';
  v_sql      VARCHAR2(500);
BEGIN
  -- 잘못된 방식: 컬럼명이 VALUES 절에 직접 삽입됨
  v_sql := 'INSERT INTO log_table (col_name, col_value) VALUES (' 
            || v_col_name || ', 5000)';
  -- 위 문장은 VALUES (SALARY, 5000) 이 되어 ORA-00984 발생
  EXECUTE IMMEDIATE v_sql;
END;
/

올바른 동적 SQL 예시:

DECLARE
  v_col_name VARCHAR2(30) := 'SALARY';
  v_sql      VARCHAR2(500);
BEGIN
  -- 올바른 방식: 문자열 리터럴로 감싸거나 바인드 변수 사용
  v_sql := 'INSERT INTO log_table (col_name, col_value) VALUES (:1, :2)';
  EXECUTE IMMEDIATE v_sql USING v_col_name, 5000;
  COMMIT;
END;
/

예방 방법

  • INSERT 문 작성 시 VALUES 절과 SELECT 절 구분 원칙 수립

팀 내 코딩 컨벤션으로 “다른 테이블의 데이터를 기반으로 INSERT 할 때는 반드시 INSERT INTO ... SELECT 구문을 사용한다”는 규칙을 정의하세요. VALUES 절에는 명확한 리터럴 값, 바인드 변수(:variable), 또는 단순 함수(SYSDATE, SYS_GUID(), SYSTIMESTAMP 등)만 사용하도록 팀 전체에 가이드를 공유하고, 코드 리뷰 체크리스트에 해당 항목을 포함시키는 것이 효과적입니다. SQL Developer, Toad 등의 IDE에서 제공하는 SQL 문법 검사 기능을 적극 활용하면 실행 전에 이 유형의 오류를 사전 차단할 수 있습니다.

  • DDL 작성 시 DEFAULT 절 허용 범위 문서화 및 트리거/가상 컬럼 활용

Oracle의 DEFAULT 절에서 허용되는 값의 범위(상수, 내장 SQL 함수, 12c 이상 시퀀스)를 팀 내 DB 설계 가이드 문서에 명확히 기술해 두세요. 컬럼 간의 종속적인 기본값 설정이 필요한 경우, Oracle 11g 이상의 가상 컬럼(Virtual Column) 또는 BEFORE INSERT 트리거를 적극 활용하여 비즈니스 로직을 구현하는 것이 올바른 방법입니다. 또한 개발 환경에서 DDL 스크립트를 실행하기 전 반드시 SQL 검증 단계를 거치는 CI/CD 파이프라인을 구성하면 운영 환경 반영 전 에러를 조기에 발견할 수 있습니다.


관련 에러

  • ORA-00904: invalid identifier — 존재하지 않는 컬럼명이나 잘못된 식별자를 참조할 때 발생하며, ORA-00984와 함께 컬럼 참조 오류의 대표적인 쌍입니다.
  • ORA-00936: missing expression — VALUES 절이나 SELECT 절에서 필수 표현식이 누락되었을 때 발생하며, 잘못된 INSERT 문 작성 시 ORA-00984와 함께 나타날 수 있습니다.
  • ORA-01747: invalid user.table.column, table.column, or column specification — 컬럼 지정 방식이 잘못된 경우 발생하며, 복잡한 JOIN 쿼리나 UPDATE 문 작성 시 ORA-00984와 혼동될 수 있습니다.
  • ORA-02270: no matching unique or primary key for this column-list — 외래 키 제약 조건 정의 시 참조 컬럼이 잘못 지정된 경우 발생하며, DDL 오류 맥락에서 ORA-00984와 연관될 수 있습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기