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

ORA-30088
2026년 10월 09일 | DBMS Error 가이드

이 글에서 다루는 내용

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

ORA-30088 datetime/interval precision is out of range 는?

ORA-30088 에러는 Oracle에서 날짜/시간(datetime) 또는 인터벌(interval) 데이터 타입의 정밀도(precision) 값이 허용된 범위를 벗어났을 때 발생합니다. Oracle은 각 날짜/시간 및 인터벌 타입에 대해 명확하게 허용되는 정밀도 범위를 정의하고 있으며, 이 범위를 초과하거나 미달하는 값을 지정하면 이 에러가 트리거됩니다. 예를 들어 TIMESTAMP(9) 처럼 허용되지 않는 정밀도 값을 사용하거나, INTERVAL YEAR(10) TO MONTH 처럼 지나치게 큰 정밀도를 지정할 때 주로 발생합니다.


주요 발생 원인

1. TIMESTAMP 타입에 허용 범위를 벗어난 정밀도 지정

Oracle의 TIMESTAMP 데이터 타입은 소수점 이하 초(fractional seconds)의 정밀도를 0부터 9까지만 허용합니다. 개발자가 실수로 10 이상의 값을 지정하거나 음수 값을 입력하면 ORA-30088 에러가 즉시 발생합니다. 이는 테이블 생성(DDL), 변수 선언(PL/SQL), 또는 형변환 함수 사용 시 모두 해당됩니다.

2. INTERVAL 타입의 leading precision 또는 fractional seconds precision 초과

INTERVAL YEAR TO MONTH 또는 INTERVAL DAY TO SECOND 타입에서 허용되는 leading precision은 0에서 9까지이며, fractional seconds precision 역시 0에서 9까지입니다. 하지만 일부 개발자나 마이그레이션 스크립트에서 이 범위를 초과하는 값(예: INTERVAL DAY(10) TO SECOND(10))을 지정하는 실수를 범합니다. 특히 타 DBMS에서 Oracle로 마이그레이션할 때 데이터 타입 매핑이 잘못되어 이 문제가 빈번하게 발생합니다.

3. PL/SQL 또는 동적 SQL에서 변수 선언 시 잘못된 정밀도 사용

PL/SQL 블록 내에서 TIMESTAMP 또는 INTERVAL 변수를 선언할 때, 동적으로 생성된 SQL 문자열이나 사용자 입력값이 정밀도에 반영되는 경우 범위 초과 에러가 발생할 수 있습니다. 특히 외부 애플리케이션에서 정밀도 값을 파라미터로 전달받아 동적 DDL이나 DML을 생성하는 경우, 입력값 검증 없이 그대로 사용하면 ORA-30088이 발생합니다.


해결 방법

원인 1 해결: TIMESTAMP 정밀도를 허용 범위(0~9)로 수정

잘못된 예시와 올바른 예시를 비교해 보겠습니다.

-- ❌ 잘못된 예: 정밀도 10은 허용되지 않음
CREATE TABLE order_log (
    order_id     NUMBER,
    created_at   TIMESTAMP(10)   -- ORA-30088 발생!
);

-- ✅ 올바른 예: 정밀도는 0~9 사이여야 함
CREATE TABLE order_log (
    order_id     NUMBER,
    created_at   TIMESTAMP(6)    -- 마이크로초 단위, 일반적으로 가장 많이 사용
);

-- ✅ PL/SQL 변수 선언 시 올바른 정밀도 사용
DECLARE
    v_created_at  TIMESTAMP(6);  -- 0~9 범위 내
    v_updated_at  TIMESTAMP(3);  -- 밀리초 단위
BEGIN
    v_created_at := SYSTIMESTAMP;
    DBMS_OUTPUT.PUT_LINE(TO_CHAR(v_created_at, 'YYYY-MM-DD HH24:MI:SS.FF6'));
END;
/

원인 2 해결: INTERVAL 타입의 정밀도를 허용 범위로 수정

-- ❌ 잘못된 예: leading precision이 10으로 범위 초과
CREATE TABLE task_duration (
    task_id   NUMBER,
    duration  INTERVAL DAY(10) TO SECOND(10)  -- ORA-30088 발생!
);

-- ✅ 올바른 예: leading precision 0~9, fractional seconds precision 0~9
CREATE TABLE task_duration (
    task_id   NUMBER,
    duration  INTERVAL DAY(2) TO SECOND(6)  -- 2자리 일수, 마이크로초
);

-- ✅ INTERVAL YEAR TO MONTH 올바른 사용 예
CREATE TABLE subscription_info (
    sub_id     NUMBER,
    sub_period INTERVAL YEAR(4) TO MONTH  -- 4자리 연도 표현 가능
);

-- ✅ INTERVAL 리터럴 올바른 삽입 예
INSERT INTO task_duration (task_id, duration)
VALUES (1, INTERVAL '3 12:30:45.123456' DAY(1) TO SECOND(6));

COMMIT;

원인 3 해결: PL/SQL 동적 SQL에서 정밀도 값 검증 로직 추가

-- ✅ 동적 SQL 생성 전 정밀도 값을 검증하는 PL/SQL 예제
CREATE OR REPLACE PROCEDURE create_log_table (
    p_table_name   IN VARCHAR2,
    p_ts_precision IN NUMBER DEFAULT 6
)
AS
    v_sql          VARCHAR2(1000);
    v_precision    NUMBER;
BEGIN
    -- 정밀도 값 유효성 검증 (0~9 범위만 허용)
    IF p_ts_precision < 0 OR p_ts_precision > 9 THEN
        RAISE_APPLICATION_ERROR(
            -20001,
            'TIMESTAMP precision must be between 0 and 9. Provided: ' || p_ts_precision
        );
    END IF;

    v_precision := p_ts_precision;

    v_sql := 'CREATE TABLE ' || DBMS_ASSERT.SIMPLE_SQL_NAME(p_table_name) || ' ('
          || '  log_id    NUMBER GENERATED ALWAYS AS IDENTITY, '
          || '  log_msg   VARCHAR2(4000), '
          || '  log_at    TIMESTAMP(' || v_precision || ') DEFAULT SYSTIMESTAMP '
          || ')';

    EXECUTE IMMEDIATE v_sql;

    DBMS_OUTPUT.PUT_LINE('Table ' || p_table_name || ' created with TIMESTAMP(' || v_precision || ').');

EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
        RAISE;
END;
/

-- 실행 예
EXEC create_log_table('APP_LOG', 6);    -- 정상 실행
EXEC create_log_table('APP_LOG2', 10); -- 에러 처리됨

기존 테이블 컬럼의 정밀도 확인 및 수정

-- 현재 테이블의 datetime/interval 컬럼 정밀도 확인
SELECT table_name,
       column_name,
       data_type,
       data_precision,
       data_scale
FROM   user_tab_columns
WHERE  data_type IN ('TIMESTAMP', 'TIMESTAMP WITH TIME ZONE',
                     'TIMESTAMP WITH LOCAL TIME ZONE',
                     'INTERVAL YEAR TO MONTH',
                     'INTERVAL DAY TO SECOND')
ORDER BY table_name, column_id;

-- 잘못된 정밀도로 생성된 컬럼 수정 (ALTER TABLE)
-- TIMESTAMP 정밀도 변경 예 (Oracle 11g 이상)
ALTER TABLE order_log MODIFY (created_at TIMESTAMP(6));

예방 방법

1. DDL 작성 표준화 및 코드 리뷰 프로세스 도입

조직 내 개발 표준에 Oracle datetime/interval 타입의 허용 정밀도 범위를 명시적으로 문서화하고, 모든 DDL 스크립트는 반드시 DBA 또는 시니어 개발자의 코드 리뷰를 거치도록 프로세스를 수립합니다. 특히 타 DBMS에서 Oracle로 마이그레이션하는 프로젝트의 경우, 데이터 타입 매핑 테이블을 별도로 작성하여 팀 전체가 공유하도록 합니다.

-- 개발 표준 참고: 허용되는 Oracle datetime/interval 정밀도 범위
-- TIMESTAMP(0~9)                 : 소수점 이하 초 정밀도, 기본값 6 권장
-- INTERVAL YEAR(0~9) TO MONTH   : 연도 leading precision, 기본값 2
-- INTERVAL DAY(0~9) TO SECOND(0~9) : 일 leading precision, 초 정밀도

-- 권장 표준 타입 정의 예
CREATE OR REPLACE TYPE std_datetime_types AS OBJECT (
    dummy NUMBER
);
-- 팀 내부 위키 또는 문서에 아래 내용을 표준으로 등록할 것:
-- 일반 타임스탬프    : TIMESTAMP(6)
-- 밀리초 정밀도      : TIMESTAMP(3)
-- 연도-월 인터벌     : INTERVAL YEAR(2) TO MONTH
-- 일-초 인터벌       : INTERVAL DAY(2) TO SECOND(6)

2. 동적 SQL 생성 시 반드시 입력값 검증 로직 구현

애플리케이션 또는 PL/SQL 프로시저에서 동적으로 datetime/interval 타입의 정밀도를 지정할 경우, 반드시 0~9 범위 내인지 사전 검증하는 로직을 구현합니다. Oracle의 DBMS_ASSERT 패키지를 적극 활용하여 SQL Injection 방지와 동시에 입력값의 유효성을 보장합니다.

-- 정밀도 검증 함수 예제
CREATE OR REPLACE FUNCTION validate_dt_precision(p_precision IN NUMBER)
RETURN NUMBER
AS
BEGIN
    IF p_precision IS NULL OR p_precision < 0 OR p_precision > 9 THEN
        RAISE_APPLICATION_ERROR(-20002,
            'Invalid datetime precision: ' || NVL(TO_CHAR(p_precision), 'NULL')
            || '. Must be between 0 and 9.');
    END IF;
    RETURN p_precision;
END;
/

-- 사용 예
DECLARE
    v_precision NUMBER := validate_dt_precision(6);  -- 정상
BEGIN
    DBMS_OUTPUT.PUT_LINE('Validated precision: ' || v_precision);
END;
/

관련 에러

  • ORA-30085: datetime/interval value is invalid — datetime 또는 interval 값 자체가 유효하지 않은 경우 발생합니다. ORA-30088과 달리 정밀도가 아닌 실제 값의 범위 문제입니다.
  • ORA-01843: not a valid month — 날짜 문자열 변환 시 월(month) 값이 올바르지 않을 때 발생하며, datetime 타입 처리 중 함께 검토해야 할 에러입니다.
  • ORA-01867: the interval is invalid — INTERVAL 리터럴 또는 변환 시 값이 유효하지 않을 때 발생합니다. INTERVAL 타입 작업 중 ORA-30088과 함께 접할 수 있습니다.
  • ORA-30086: interval fields value is out of range — INTERVAL 타입에서 필드 값(예: 초, 분, 시간)이 허용 범위를 초과했을 때 발생하며, ORA-30088과 매우 유사한 맥락에서 발생합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기