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

ORA-00907
2026년 06월 15일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-00907 missing right parenthesis 는?

ORA-00907 에러는 SQL 문장에서 닫는 괄호 )가 누락되었거나, 괄호가 문법적으로 올바르지 않은 위치에 있을 때 발생하는 Oracle 파싱 에러입니다. Oracle 파서가 SQL을 분석하는 과정에서 열린 괄호 (에 대응하는 닫는 괄호를 찾지 못하거나, 괄호 내부에 유효하지 않은 구문이 포함되어 있을 때 이 에러가 트리거됩니다. 단순한 오타부터 복잡한 서브쿼리 구조의 문법 오류까지 다양한 원인으로 발생하기 때문에, 특히 긴 SQL 문장에서는 원인을 찾기가 까다로울 수 있습니다.


주요 발생 원인

1. CREATE TABLE 또는 DDL 문장에서 괄호 불일치

DDL 문장에서 컬럼 정의 시 데이터 타입 뒤에 제약 조건을 잘못 기술하거나, 괄호의 열고 닫음이 맞지 않는 경우가 가장 흔한 원인입니다. 특히 복합 제약 조건이나 CHECK 제약 조건을 정의할 때 중첩 괄호가 많아지면서 실수가 발생하기 쉽습니다. 또한 VARCHAR2, NUMBER 등 크기를 지정해야 하는 데이터 타입에서 크기 지정 괄호를 누락하거나 잘못 기입하는 경우도 자주 발생합니다.

2. 서브쿼리(Subquery) 구문에서의 괄호 오류

인라인 뷰(Inline View), WHERE 절 서브쿼리, WITH 절(CTE) 등 서브쿼리를 사용하는 복잡한 SQL에서 괄호를 빠뜨리거나 잘못 닫는 경우에 이 에러가 발생합니다. 쿼리가 길어질수록 중첩 서브쿼리의 괄호 구조를 추적하기 어려워지고, 잘못된 위치에 ) 를 배치하거나 누락하게 됩니다. 특히 여러 개발자가 함께 작업하거나 동적 SQL을 생성할 때 이런 실수가 자주 발생합니다.

3. CASE 문, IN 절, 함수 호출에서의 문법 오류

CASE WHEN ... END, IN (...), NVL(), TO_DATE() 등의 함수나 구문에서 괄호를 정확히 닫지 않으면 ORA-00907이 발생합니다. 특히 CASE 문 내부에 함수 호출이 중첩되거나, IN 절에 서브쿼리가 포함될 경우 괄호 구조가 복잡해져 오류가 생기기 쉽습니다. Oracle은 이 경우 단순히 괄호 개수만 세는 것이 아니라 문법 구조 전체를 파싱하기 때문에, 괄호가 개수상 맞더라도 위치가 틀리면 에러가 발생합니다.


해결 방법

원인 1 해결: DDL 문장 괄호 수정

잘못된 예시:

-- 오류: NUMBER 타입에 크기 지정 괄호 누락 및 CHECK 제약 조건 괄호 오류
CREATE TABLE employees (
    emp_id     NUMBER,
    emp_name   VARCHAR2(100,
    salary     NUMBER(10,2,
    dept_id    NUMBER,
    CONSTRAINT chk_salary CHECK salary > 0
);

올바른 예시:

-- 수정: 모든 괄호를 정확히 열고 닫음
CREATE TABLE employees (
    emp_id     NUMBER,
    emp_name   VARCHAR2(100),
    salary     NUMBER(10, 2),
    dept_id    NUMBER,
    CONSTRAINT chk_salary CHECK (salary > 0)
);

괄호 개수 확인 팁:

-- 디버깅용: 괄호 수를 직접 세어 비교
SELECT
    LENGTH('CREATE TABLE test (id NUMBER(10), name VARCHAR2(100))') 
    - LENGTH(REPLACE('CREATE TABLE test (id NUMBER(10), name VARCHAR2(100))', '(', '')) AS open_count,
    LENGTH('CREATE TABLE test (id NUMBER(10), name VARCHAR2(100))') 
    - LENGTH(REPLACE('CREATE TABLE test (id NUMBER(10), name VARCHAR2(100))', ')', '')) AS close_count
FROM DUAL;

원인 2 해결: 서브쿼리 괄호 수정

잘못된 예시:

-- 오류: 인라인 뷰의 닫는 괄호 누락
SELECT a.emp_name, b.dept_name
FROM employees a,
     (SELECT dept_id, dept_name
      FROM departments
      WHERE location_id = 100  -- 닫는 괄호 ) 누락
WHERE a.dept_id = b.dept_id;

올바른 예시:

-- 수정: 인라인 뷰 괄호 정상 닫음
SELECT a.emp_name, b.dept_name
FROM employees a,
     (SELECT dept_id, dept_name
      FROM departments
      WHERE location_id = 100) b   -- 닫는 괄호와 별칭 추가
WHERE a.dept_id = b.dept_id;

WITH 절(CTE) 올바른 예시:

-- CTE 구문에서의 올바른 괄호 사용
WITH dept_summary AS (
    SELECT dept_id,
           COUNT(*) AS emp_count,
           AVG(salary) AS avg_salary
    FROM employees
    GROUP BY dept_id
),
high_salary_dept AS (
    SELECT dept_id, avg_salary
    FROM dept_summary
    WHERE avg_salary > 5000
)
SELECT d.dept_name, h.avg_salary
FROM departments d
JOIN high_salary_dept h ON d.dept_id = h.dept_id
ORDER BY h.avg_salary DESC;

원인 3 해결: CASE 문과 IN 절 괄호 수정

잘못된 예시:

-- 오류: CASE 문과 IN 절에서 괄호 오류
SELECT emp_name,
       CASE
           WHEN salary > 10000 THEN 'HIGH'
           WHEN salary > 5000 THEN 'MEDIUM'
           ELSE 'LOW'
       END AS salary_grade,
       dept_id
FROM employees
WHERE dept_id IN (
    SELECT dept_id
    FROM departments
    WHERE location_id IN (100, 200, 300)
    -- 서브쿼리 닫는 괄호 누락
AND emp_name IS NOT NULL;

올바른 예시:

-- 수정: 모든 괄호 정확히 처리
SELECT emp_name,
       CASE
           WHEN salary > 10000 THEN 'HIGH'
           WHEN salary > 5000  THEN 'MEDIUM'
           ELSE 'LOW'
       END AS salary_grade,
       dept_id
FROM employees
WHERE dept_id IN (
    SELECT dept_id
    FROM departments
    WHERE location_id IN (100, 200, 300)
)                          -- 서브쿼리 닫는 괄호 추가
AND emp_name IS NOT NULL;

함수 중첩 올바른 예시:

-- NVL, TO_DATE, TRUNC 함수 중첩 시 괄호 주의
SELECT emp_name,
       NVL(TO_CHAR(hire_date, 'YYYY-MM-DD'), 'N/A') AS hire_date_str,
       TRUNC(MONTHS_BETWEEN(SYSDATE, hire_date) / 12) AS years_of_service
FROM employees
WHERE hire_date >= TO_DATE('2000-01-01', 'YYYY-MM-DD')
  AND salary BETWEEN NVL(5000, 0) AND NVL(20000, 999999);

예방 방법

1. SQL 포맷터 및 IDE 자동 괄호 검사 도구 활용

SQL Developer, Toad, DBeaver 등의 IDE는 괄호 짝 맞춤 기능과 실시간 문법 검사 기능을 제공합니다. SQL을 작성할 때 반드시 이러한 도구를 사용하고, 특히 복잡한 서브쿼리나 DDL 작성 시에는 들여쓰기(Indentation)를 일관되게 유지하여 괄호 구조를 시각적으로 확인할 수 있도록 합니다. 대형 쿼리는 작성 후 반드시 SQL 포맷터로 정렬하여 괄호 쌍이 맞는지 육안으로 검토하는 습관을 들이세요.

2. 분할 작성 및 단계별 테스트 습관화

복잡한 SQL을 한 번에 작성하지 말고, 서브쿼리나 CTE를 먼저 독립적으로 실행하여 검증한 뒤 전체 쿼리에 통합하는 방식을 사용하세요. 각 서브쿼리를 작성할 때는 여는 괄호 (를 입력하는 즉시 닫는 괄호 )를 먼저 입력해두고 그 사이를 채우는 방식(괄호 선행 입력 방식)을 습관화하면 누락을 크게 줄일 수 있습니다. 배포 전 반드시 개발·테스트 환경에서 전체 SQL을 실행해보는 프로세스를 팀 내 규칙으로 정하는 것도 효과적입니다.


관련 에러

  • ORA-00906: missing left parenthesis — 여는 괄호 (가 필요한 위치에 없을 때 발생하며, ORA-00907과 함께 괄호 관련 에러의 대표적인 쌍입니다.
  • ORA-00933: SQL command not properly ended — SQL 문장의 끝 구조가 올바르지 않을 때 발생하며, 괄호 오류와 함께 발생하는 경우가 많습니다.
  • ORA-00936: missing expression — 표현식이 있어야 할 자리에 아무것도 없을 때 발생하며, 빈 괄호 () 또는 불완전한 절과 함께 나타납니다.
  • ORA-00902: invalid datatype — DDL에서 데이터 타입 관련 괄호 오류 시 ORA-00907과 함께 발생할 수 있습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기