2026년 06월 27일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-01008 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-01008 not all variables bound 는?
ORA-01008 에러는 SQL 문장 내에 선언된 바인드 변수(Bind Variable)의 수와 실제로 값이 할당된 변수의 수가 일치하지 않을 때 발생하는 오류입니다. 즉, SQL 문장에 :variable 형태로 플레이스홀더를 작성했지만, 실행 전에 모든 변수에 값을 바인딩하지 않은 경우 Oracle이 이 에러를 반환합니다. 이 에러는 주로 애플리케이션 개발 단계나 Pro*C, JDBC, OCI, Python cx_Oracle, Java 등 다양한 언어에서 Oracle DB에 접근할 때 자주 발생하며, 즉각적인 원인 파악과 수정이 필요합니다.
주요 발생 원인
1. 바인드 변수 개수 불일치 (가장 흔한 원인)
SQL 문장 내에 선언한 바인드 변수의 총 개수와 실제 애플리케이션 코드에서 바인딩한 변수의 개수가 맞지 않을 때 발생합니다. 예를 들어 SQL에는 :1, :2, :3 세 개의 플레이스홀더가 있는데, 코드에서 두 개만 바인딩하면 반드시 이 에러가 발생합니다. 이는 SQL 수정 후 바인딩 코드를 업데이트하지 않거나, 복사-붙여넣기 실수로 인해 매우 빈번하게 발생하는 패턴입니다.
2. 동일한 바인드 변수명 재사용 문제
Oracle은 기본적으로 동일한 이름의 바인드 변수가 SQL 내에 여러 번 등장하더라도, 사용하는 언어 드라이버나 API에 따라 각각 별도의 바인딩을 요구하는 경우가 있습니다. 특히 JDBC PreparedStatement의 위치 기반 바인딩(1-based index)에서 :name 형태의 변수를 사용하면 동일한 변수명이라도 등장 횟수만큼 바인딩해야 하는 상황이 발생할 수 있습니다. 이를 인지하지 못하고 변수명이 같으니 한 번만 바인딩하면 된다고 착각하면 ORA-01008이 발생합니다.
3. 동적 SQL(Dynamic SQL) 생성 오류
애플리케이션에서 조건에 따라 SQL을 동적으로 생성할 때, 특정 분기에서 바인드 변수를 SQL에 추가하고 실제 값 바인딩은 누락하는 경우가 있습니다. 또는 반대로 SQL에는 바인드 변수가 빠졌는데 바인딩 코드에는 값을 추가하는 로직이 남아 있는 경우도 있습니다. 복잡한 동적 SQL일수록 이런 불일치는 디버깅이 어렵고, 특정 조건에서만 에러가 재현되어 원인 파악에 시간이 걸립니다.
해결 방법
원인 1 해결: 바인드 변수 개수 맞추기
SQL 내의 바인드 변수 개수를 정확히 세고, 코드에서 동일한 수만큼 바인딩해야 합니다.
-- 잘못된 예 (3개의 바인드 변수 중 2개만 바인딩 시도)
-- SQL: INSERT INTO employees (emp_id, emp_name, dept_id) VALUES (:1, :2, :3)
-- 코드에서 :1, :2만 바인딩 → ORA-01008 발생
-- 올바른 예: 모든 바인드 변수에 값을 할당
DECLARE
v_emp_id employees.emp_id%TYPE := 1001;
v_emp_name employees.emp_name%TYPE := 'Hong Gil-dong';
v_dept_id employees.dept_id%TYPE := 10;
BEGIN
-- 모든 바인드 변수(:1, :2, :3)에 대응하는 값을 정확히 바인딩
EXECUTE IMMEDIATE
'INSERT INTO employees (emp_id, emp_name, dept_id) VALUES (:1, :2, :3)'
USING v_emp_id, v_emp_name, v_dept_id; -- 3개 모두 바인딩
COMMIT;
END;
/
-- SELECT 문에서의 올바른 바인드 변수 사용 예
DECLARE
v_dept_id NUMBER := 20;
v_sal NUMBER := 3000;
v_count NUMBER;
BEGIN
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM employees WHERE dept_id = :1 AND salary >= :2'
INTO v_count
USING v_dept_id, v_sal; -- :1과 :2 모두 정확히 바인딩
DBMS_OUTPUT.PUT_LINE('Count: ' || v_count);
END;
/
원인 2 해결: 동일 변수명 반복 사용 시 주의
Oracle PL/SQL에서는 같은 이름의 바인드 변수가 여러 번 등장해도 하나만 바인딩하면 되지만, JDBC 등 외부 드라이버에서는 등장 횟수만큼 바인딩해야 합니다.
-- PL/SQL EXECUTE IMMEDIATE: 동일 변수명은 한 번만 바인딩 (Oracle 기본 동작)
DECLARE
v_dept NUMBER := 10;
v_result NUMBER;
BEGIN
-- :dept가 두 번 사용되지만 PL/SQL에서는 USING절에 한 번만 명시
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM employees
WHERE dept_id = :dept
AND manager_dept_id = :dept'
INTO v_result
USING v_dept; -- PL/SQL에서는 한 번만 바인딩하면 정상 동작
DBMS_OUTPUT.PUT_LINE('Result: ' || v_result);
END;
/
-- JDBC (Java) 사용 시에는 위치 기반으로 등장 횟수만큼 바인딩 필요
-- Java 예시 (주석 형태로 표현):
-- String sql = "SELECT COUNT(*) FROM employees WHERE dept_id = ? AND manager_dept_id = ?";
-- PreparedStatement pstmt = conn.prepareStatement(sql);
-- pstmt.setInt(1, 10); // 첫 번째 ?
-- pstmt.setInt(2, 10); // 두 번째 ? (동일 값이어도 별도 바인딩 필요)
-- ResultSet rs = pstmt.executeQuery();
-- Oracle JDBC에서 Named Parameter 사용 시 (OraclePreparedStatement)
-- String sql = "SELECT COUNT(*) FROM employees WHERE dept_id = :dept AND manager_dept_id = :dept";
-- OraclePreparedStatement opst = (OraclePreparedStatement) conn.prepareStatement(sql);
-- opst.setIntAtName("dept", 10); -- Named parameter이므로 한 번만 바인딩 가능
SELECT 'JDBC Named Parameter 방식 권장' AS tip FROM dual;
원인 3 해결: 동적 SQL 검증 로직 추가
-- 동적 SQL 생성 시 바인드 변수 카운트를 검증하는 안전한 패턴
DECLARE
v_sql VARCHAR2(4000);
v_where VARCHAR2(1000) := '';
v_dept_id NUMBER := NULL;
v_hire_date DATE := NULL;
v_count NUMBER;
-- 바인딩 변수를 컬렉션으로 관리하는 방법
TYPE t_bind_vals IS TABLE OF VARCHAR2(100);
-- 실제로는 ANYDATA나 별도 타입을 사용하지만, 개념 설명을 위한 예시
BEGIN
v_sql := 'SELECT COUNT(*) FROM employees WHERE 1=1';
-- 조건 추가 시 반드시 바인드 변수 추가와 동기화
IF v_dept_id IS NOT NULL THEN
v_where := v_where || ' AND dept_id = :dept_id';
END IF;
IF v_hire_date IS NOT NULL THEN
v_where := v_where || ' AND hire_date >= :hire_date';
END IF;
v_sql := v_sql || v_where;
-- 조건 분기별로 정확한 바인딩 실행
IF v_dept_id IS NOT NULL AND v_hire_date IS NOT NULL THEN
EXECUTE IMMEDIATE v_sql INTO v_count USING v_dept_id, v_hire_date;
ELSIF v_dept_id IS NOT NULL THEN
EXECUTE IMMEDIATE v_sql INTO v_count USING v_dept_id;
ELSIF v_hire_date IS NOT NULL THEN
EXECUTE IMMEDIATE v_sql INTO v_count USING v_hire_date;
ELSE
EXECUTE IMMEDIATE v_sql INTO v_count;
END IF;
DBMS_OUTPUT.PUT_LINE('조회 건수: ' || v_count);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQL: ' || v_sql);
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
RAISE;
END;
/
예방 방법
1. 바인드 변수 명명 규칙 및 코드 리뷰 프로세스 도입
SQL 문자열과 바인딩 코드를 항상 함께 검토하는 코드 리뷰 체크리스트를 만들어 운영하세요. SQL 문 내의 바인드 변수 개수(: 기호 수)와 USING 절 또는 바인딩 함수 호출 횟수를 반드시 1:1로 대응시키는 규칙을 팀 전체에 공유하고, PR(Pull Request) 리뷰 시 필수 확인 항목으로 지정하면 대부분의 실수를 사전에 방지할 수 있습니다.
2. 단위 테스트 및 SQL 로깅 강화
동적 SQL을 사용하는 모든 프로시저와 애플리케이션 코드에 대해 다양한 파라미터 조합(NULL 포함)으로 단위 테스트를 작성하세요. 또한 개발/스테이징 환경에서 실행되는 SQL과 바인드 변수 값을 로그로 남기는 습관을 들이면, ORA-01008 발생 시 원인 파악 시간을 대폭 줄일 수 있습니다. Oracle의 V$SQL, V$SQL_BIND_CAPTURE 뷰를 활용하면 실제 실행된 SQL의 바인드 변수 정보를 확인할 수 있습니다.
관련 에러
- ORA-01006: 바인드 변수가 존재하지 않음 (Bind variable does not exist). SQL에 선언되지 않은 변수명으로 바인딩을 시도할 때 발생하며, ORA-01008과 함께 동적 SQL 개발 시 자주 만나는 에러입니다.
- ORA-00904: 유효하지 않은 식별자 (Invalid identifier). 바인드 변수명 오타나 컬럼명 오류로 인해 ORA-01008과 혼동될 수 있으니 SQL 구문을 꼼꼼히 확인해야 합니다.
- ORA-01036: 변수명이 허용되지 않음 (Illegal variable name/number). 바인드 변수의 명명 규칙을 위반했을 때 발생하며, 변수명에 특수문자나 예약어를 사용하지 않도록 주의해야 합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.