2026년 06월 17일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-00921 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-00921 unexpected end of SQL command 는?
ORA-00921 에러는 Oracle 데이터베이스가 SQL 명령문을 파싱(Parsing)하는 도중, 문장이 완전히 끝나지 않은 상태에서 갑자기 종료되었을 때 발생하는 구문 오류입니다. 즉, Oracle 파서(Parser)가 SQL 문법적으로 추가적인 키워드나 절(Clause)이 더 있어야 한다고 기대하는데, 실제 입력된 SQL이 그보다 일찍 끊겨버린 상황입니다. 주로 SQL을 동적으로 생성하는 애플리케이션 코드나, SQL*Plus, SQL Developer 등 툴에서 직접 쿼리를 작성할 때 오탈자나 문법 실수로 자주 발생합니다.
주요 발생 원인
1. SELECT, INSERT, UPDATE, DELETE 등 DML 문장의 필수 절(Clause) 누락
가장 흔한 원인은 SQL 문장의 핵심 구성 요소가 빠진 경우입니다. 예를 들어 SELECT 키워드만 작성하고 컬럼명이나 FROM 절을 누락하거나, INSERT INTO 테이블명 까지만 작성하고 VALUES 절이나 서브쿼리를 빠뜨리는 경우가 대표적입니다. 특히 동적 SQL을 문자열 연결(concatenation)로 생성하는 Java, Python, PL/SQL 코드에서 조건에 따라 특정 절이 누락되는 버그가 자주 발생합니다.
2. 괄호(Parenthesis) 미완성 또는 서브쿼리 불완전 작성
SQL 문장 내에서 괄호를 열었지만 닫지 않았거나, 서브쿼리의 본문이 완성되지 않은 채 문장이 종료된 경우에도 이 에러가 발생합니다. 복잡한 중첩 서브쿼리(Nested Subquery)나 IN 절, EXISTS 절을 작성할 때 괄호의 짝이 맞지 않으면 Oracle은 문장이 아직 끝나지 않았다고 판단합니다. 쿼리가 길어질수록 육안으로 괄호 짝을 맞추기 어려워지므로 각별한 주의가 필요합니다.
3. 주석(Comment) 처리 오류 또는 특수문자로 인한 문장 조기 종료
-- 단일 행 주석이나 / / 블록 주석이 잘못 처리되어 SQL의 핵심 부분이 주석으로 묻혀버리거나, 세미콜론(;)이 SQL 문장 중간에 삽입되어 Oracle이 그 지점에서 문장이 끝났다고 판단하는 경우도 있습니다. 또한 애플리케이션에서 사용자 입력값을 SQL에 직접 삽입할 때 입력값에 특수문자나 개행문자가 포함되어 의도치 않게 SQL 구조가 깨지는 경우도 이에 해당합니다.
해결 방법
원인 1 해결: 필수 절 누락 교정
아래는 FROM 절이 누락된 잘못된 예시와 올바른 수정 예시입니다.
-- ❌ 잘못된 SQL: FROM 절 누락으로 ORA-00921 발생
SELECT employee_id, first_name, last_name;
-- ✅ 올바른 SQL: FROM 절 추가
SELECT employee_id, first_name, last_name
FROM employees;
INSERT 문에서 VALUES 절이 누락된 경우:
-- ❌ 잘못된 SQL: VALUES 절 누락
INSERT INTO departments (department_id, department_name)
-- ✅ 올바른 SQL: VALUES 절 추가
INSERT INTO departments (department_id, department_name)
VALUES (10, 'IT Support');
UPDATE 문에서 SET 절이 누락된 경우:
-- ❌ 잘못된 SQL: SET 절 누락
UPDATE employees
WHERE employee_id = 100;
-- ✅ 올바른 SQL: SET 절 추가
UPDATE employees
SET salary = salary * 1.1
WHERE employee_id = 100;
원인 2 해결: 괄호 불일치 및 서브쿼리 교정
-- ❌ 잘못된 SQL: 서브쿼리 괄호 미닫힘
SELECT *
FROM employees
WHERE department_id IN (
SELECT department_id
FROM departments
WHERE location_id = 1700
;
-- ✅ 올바른 SQL: 괄호 닫힘 추가
SELECT *
FROM employees
WHERE department_id IN (
SELECT department_id
FROM departments
WHERE location_id = 1700
);
복잡한 쿼리에서 괄호 짝을 확인하는 실용적인 방법으로, SQL Developer나 Toad 같은 툴의 괄호 하이라이팅 기능을 활용하거나 아래처럼 단계별로 분리해 테스트하는 것을 권장합니다.
-- 서브쿼리를 먼저 단독 실행하여 문법 검증
SELECT department_id
FROM departments
WHERE location_id = 1700;
-- 검증 완료 후 메인 쿼리에 포함
SELECT e.employee_id, e.first_name, e.last_name
FROM employees e
WHERE e.department_id IN (
SELECT d.department_id
FROM departments d
WHERE d.location_id = 1700
);
원인 3 해결: 주석 및 특수문자 처리
-- ❌ 잘못된 SQL: 블록 주석이 FROM 절을 삼킴
SELECT employee_id, first_name /* 이름 컬럼
FROM employees */
WHERE department_id = 10;
-- ✅ 올바른 SQL: 주석 위치 교정
SELECT employee_id, first_name /* 이름 컬럼 */
FROM employees
WHERE department_id = 10;
동적 SQL에서 사용자 입력을 처리할 때는 반드시 바인드 변수(Bind Variable)를 사용해야 합니다.
-- ❌ 위험한 동적 SQL (SQL Injection 및 구문 오류 위험)
-- v_sql := 'SELECT * FROM employees WHERE last_name = ''' || v_input || '''';
-- ✅ 안전한 바인드 변수 방식
DECLARE
v_last_name VARCHAR2(50) := 'King';
v_emp_id NUMBER;
v_salary NUMBER;
BEGIN
SELECT employee_id, salary
INTO v_emp_id, v_salary
FROM employees
WHERE last_name = v_last_name -- 바인드 변수 사용
AND ROWNUM = 1;
DBMS_OUTPUT.PUT_LINE('EMP_ID: ' || v_emp_id || ', SALARY: ' || v_salary);
END;
/
PL/SQL에서 동적 SQL을 사용할 경우 EXECUTE IMMEDIATE와 USING 절을 조합하세요.
DECLARE
v_sql VARCHAR2(500);
v_dept_id NUMBER := 50;
v_count NUMBER;
BEGIN
-- 동적 SQL 작성 시 반드시 완전한 문장 구조 확인
v_sql := 'SELECT COUNT(*) FROM employees WHERE department_id = :1';
EXECUTE IMMEDIATE v_sql INTO v_count USING v_dept_id;
DBMS_OUTPUT.PUT_LINE('Count: ' || v_count);
END;
/
예방 방법
1. SQL 코드 리뷰 및 정적 분석 도구 활용
SQL을 작성할 때는 반드시 키워드 기반으로 들여쓰기(Indentation)를 적용하고, 각 절(SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY)을 별도 줄에 작성하는 코딩 컨벤션을 팀 내에서 표준화하세요. SQL Developer, Toad, DBeaver 등의 IDE에서 제공하는 문법 자동 완성(Auto-complete) 및 SQL 포매터(Formatter)를 활용하면, 괄호 불일치나 누락된 절을 실시간으로 감지할 수 있습니다. 특히 CI/CD 파이프라인에 SQLFluff와 같은 SQL 린터(Linter)를 통합하면 배포 전 단계에서 구문 오류를 자동으로 잡아낼 수 있어 운영 환경 장애를 예방할 수 있습니다.
2. 동적 SQL 생성 시 로깅 및 단계별 검증 체계 구축
애플리케이션에서 동적으로 SQL을 생성할 경우, 실행 전 완성된 SQL 문자열을 반드시 로그(Log)로 남기는 습관을 들여야 합니다. 개발 및 테스트 환경에서는 DBMS_OUTPUT.PUT_LINE 또는 애플리케이션 로거를 통해 최종 SQL을 출력하고, SQL*Plus나 SQL Developer에서 직접 붙여넣기하여 실행 가능 여부를 검증하세요. 또한 PL/SQL 코드 내에서는 예외 처리 블록(EXCEPTION WHEN OTHERS)에 SQL 에러 코드와 에러 메시지를 함께 기록하는 로깅 체계를 구축하면, 운영 중 발생하는 동적 SQL 오류를 빠르게 추적하고 수정할 수 있습니다.
관련 에러
- ORA-00900: Invalid SQL statement — SQL 문장 자체가 유효하지 않은 경우로, ORA-00921과 유사하게 구문 오류 계열에 속합니다.
- ORA-00907: Missing right parenthesis — 괄호 누락 에러로, ORA-00921의 원인 2번(괄호 불일치)과 밀접하게 연관되어 있습니다.
- ORA-00933: SQL command not properly ended — SQL 문장이 적절히 끝나지 않은 경우로, ORA-00921과 반대 개념(너무 일찍 끝남 vs 잘못된 방식으로 끝남)의 쌍을 이루는 에러입니다.
- ORA-00936: Missing expression — 필수 표현식(Expression)이 누락된 경우로, 역시 SQL 구문 오류 계열에 속하며 ORA-00921과 함께 동적 SQL 디버깅 시 자주 마주치는 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.