PostgreSQL 2202G 오류 원인과 해결 방법 완벽 가이드

2202G
2026년 08월 14일 | DBMS Error 가이드

이 글에서 다루는 내용

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

2202G invalid tablesample repeat 는?

PostgreSQL 에러 코드 2202G: invalid tablesample repeatTABLESAMPLE 절에서 사용되는 반복(repeat) 시드(seed) 값이 유효하지 않을 때 발생하는 에러입니다. TABLESAMPLE 기능은 테이블에서 무작위 샘플 데이터를 추출할 때 사용되며, 선택적으로 REPEATABLE 키워드를 통해 동일한 시드 값을 지정하면 같은 샘플 결과를 재현할 수 있습니다. 이 에러는 REPEATABLE 절에 전달된 시드 값이 허용 범위를 벗어나거나 잘못된 자료형으로 입력되었을 때 PostgreSQL 엔진이 이를 거부하면서 발생합니다.


주요 발생 원인

  • REPEATABLE 절에 NULL 값 전달

REPEATABLE 절은 샘플링의 재현성을 보장하기 위한 숫자형 시드 값을 요구합니다. 그러나 동적 쿼리나 애플리케이션 코드에서 변수 바인딩 시 의도치 않게 NULL 값이 전달되는 경우가 있으며, PostgreSQL은 NULL을 유효한 시드 값으로 허용하지 않아 즉시 에러를 반환합니다. 특히 ORM(Object-Relational Mapping) 도구나 동적 SQL 생성 로직에서 이 문제가 자주 발생합니다.

  • 허용 범위를 벗어난 시드 값 입력

TABLESAMPLEREPEATABLE 절은 특정 범위 내의 숫자 값만 유효한 시드로 인정합니다. 일부 샘플링 메서드(예: BERNOULLI, SYSTEM)는 내부 구현에 따라 허용되는 시드 값의 범위가 다를 수 있으며, 이 범위를 초과하는 값이 입력되면 에러가 발생합니다. 예를 들어, 극단적으로 큰 정수나 음수 값 등이 허용되지 않는 경우가 있습니다.

  • 잘못된 자료형 또는 표현식 사용

REPEATABLE 절에는 숫자형(numeric) 상수 또는 숫자로 평가되는 표현식이 필요합니다. 문자열이나 날짜 등 숫자로 변환될 수 없는 자료형을 직접 전달하거나, 타입 캐스팅 없이 비숫자형 컬럼을 참조하는 경우 이 에러가 발생할 수 있습니다. 특히 사용자 입력을 그대로 SQL에 삽입하는 방식의 코드에서 흔히 나타납니다.


해결 방법

원인 1: NULL 값 전달 해결

COALESCE 함수 또는 애플리케이션 레벨에서의 NULL 체크를 통해 REPEATABLE 절에 항상 유효한 숫자 값이 전달되도록 보장합니다.

-- 잘못된 예 (NULL이 전달될 경우 에러 발생)
-- SELECT * FROM orders TABLESAMPLE BERNOULLI(10) REPEATABLE(NULL);

-- 올바른 예 1: COALESCE를 사용하여 NULL을 기본값으로 대체
SELECT *
FROM orders
TABLESAMPLE BERNOULLI(10) REPEATABLE(COALESCE(NULL, 42));

-- 올바른 예 2: 애플리케이션에서 값을 검증 후 전달
-- 파라미터가 NULL인 경우 기본 시드 값 사용
DO $$
DECLARE
    v_seed NUMERIC := NULL;
    v_effective_seed NUMERIC;
BEGIN
    v_effective_seed := COALESCE(v_seed, FLOOR(EXTRACT(EPOCH FROM NOW()))::NUMERIC);
    RAISE NOTICE 'Using seed: %', v_effective_seed;
    -- 실제 쿼리에서는 동적 SQL 또는 함수로 처리
END;
$$;

-- 올바른 예 3: 현재 타임스탬프를 시드로 사용하는 안전한 패턴
SELECT *
FROM large_table
TABLESAMPLE SYSTEM(5)
REPEATABLE(FLOOR(EXTRACT(EPOCH FROM NOW()))::INT);

원인 2: 허용 범위를 벗어난 시드 값 해결

시드 값이 PostgreSQL의 허용 범위 내에 있는지 확인하고, 필요하다면 MOD 함수 또는 범위 제한 로직을 적용합니다.

-- 잘못된 예 (극단적으로 큰 값)
-- SELECT * FROM orders TABLESAMPLE BERNOULLI(10) REPEATABLE(99999999999999);

-- 올바른 예 1: MOD를 사용해 안전한 범위로 제한
SELECT *
FROM orders
TABLESAMPLE BERNOULLI(10)
REPEATABLE(MOD(ABS(123456789), 1000000));

-- 올바른 예 2: 허용 가능한 일반적인 시드 값 사용
SELECT *
FROM orders
TABLESAMPLE BERNOULLI(10) REPEATABLE(12345);

-- 올바른 예 3: SYSTEM 메서드와 함께 안전한 시드 값 사용
SELECT *
FROM large_sales_table
TABLESAMPLE SYSTEM(1)
REPEATABLE(42);

-- 시드 값 범위 검증 함수 예시
CREATE OR REPLACE FUNCTION safe_tablesample_seed(p_seed BIGINT)
RETURNS INT AS $$
BEGIN
    IF p_seed IS NULL THEN
        RETURN 1;
    END IF;
    RETURN MOD(ABS(p_seed), 2147483647)::INT;
END;
$$ LANGUAGE plpgsql;

-- 함수를 활용한 안전한 샘플링 쿼리
SELECT *
FROM orders
TABLESAMPLE BERNOULLI(10)
REPEATABLE(safe_tablesample_seed(9876543210));

원인 3: 잘못된 자료형 해결

REPEATABLE 절에 전달되는 값을 명시적으로 숫자형으로 캐스팅합니다.

-- 잘못된 예 (문자열 전달)
-- SELECT * FROM orders TABLESAMPLE BERNOULLI(10) REPEATABLE('abc');

-- 올바른 예 1: 명시적 타입 캐스팅 적용
SELECT *
FROM orders
TABLESAMPLE BERNOULLI(10)
REPEATABLE('12345'::INT);

-- 올바른 예 2: 날짜 기반 시드 값을 숫자로 변환
SELECT *
FROM orders
TABLESAMPLE SYSTEM(5)
REPEATABLE(TO_CHAR(CURRENT_DATE, 'YYYYMMDD')::INT);

-- 올바른 예 3: 해시 기반 시드 생성 (문자열 입력을 안전하게 변환)
SELECT *
FROM customer_data
TABLESAMPLE BERNOULLI(20)
REPEATABLE(ABS(HASHTEXT('my-experiment-id-2024')) % 100000);

-- 실무에서 사용하는 함수 래퍼 패턴
CREATE OR REPLACE FUNCTION sample_table_safely(
    p_table_name TEXT,
    p_percent    NUMERIC,
    p_seed       TEXT DEFAULT '42'
)
RETURNS SETOF RECORD AS $$
DECLARE
    v_numeric_seed INT;
    v_sql TEXT;
BEGIN
    -- 문자열 시드를 안전하게 정수로 변환
    BEGIN
        v_numeric_seed := p_seed::INT;
    EXCEPTION WHEN OTHERS THEN
        v_numeric_seed := ABS(HASHTEXT(p_seed)) % 1000000;
    END;

    v_sql := FORMAT(
        'SELECT * FROM %I TABLESAMPLE BERNOULLI(%s) REPEATABLE(%s)',
        p_table_name, p_percent, v_numeric_seed
    );
    RETURN QUERY EXECUTE v_sql;
END;
$$ LANGUAGE plpgsql;

예방 방법

  • 시드 값 검증 로직을 공통 유틸리티 함수로 캡슐화

TABLESAMPLE을 사용하는 모든 쿼리에서 시드 값을 직접 하드코딩하거나 외부 입력을 그대로 전달하는 방식을 지양하고, 반드시 검증된 유틸리티 함수를 거치도록 개발 컨벤션을 수립합니다. 앞서 예시로 제시한 safe_tablesample_seed() 같은 함수를 팀 공용 라이브러리에 등록하고, 코드 리뷰 시 해당 함수 사용 여부를 체크리스트로 관리하면 에러를 사전에 예방할 수 있습니다.

“`sql

— 팀 표준 시드 생성 함수 등록

CREATE OR REPLACE FUNCTION util.normalize_sample_seed(p_input ANYELEMENT)

RETURNS INT AS $$

BEGIN

RETURN COALESCE(

MOD(ABS(p_input::TEXT::BIGINT), 2147483647),

1

)::INT;

EXCEPTION WHEN OTHERS THEN

RETURN ABS(HASHTEXT(p_input::TEXT)) % 2147483647;

END;

$$ LANGUAGE plpgsql IMMUTABLE;

“`

  • 통합 테스트 환경에서 경계 값(Boundary Value) 테스트 자동화

TABLESAMPLE을 사용하는 쿼리나 함수에 대해 NULL, 0, 음수, 최대 정수값 등 경계 값을 포함한 단위 테스트를 작성하고 CI/CD 파이프라인에 통합합니다. pgTAP 등의 PostgreSQL 테스트 프레임워크를 활용하면 배포 전 에러를 조기에 발견할 수 있으며, 특히 외부 사용자 입력이 시드 값으로 사용되는 경우 반드시 자동화된 검증 테스트를 구성해야 합니다.


관련 에러

  • 22003: numeric_value_out_of_rangeREPEATABLE 절에 전달된 숫자 값이 PostgreSQL의 내부 처리 가능 범위를 초과할 때 함께 발생할 수 있는 에러입니다.
  • 2202H: invalid tablesample argumentTABLESAMPLE 절에서 샘플링 비율(퍼센트) 값 자체가 잘못된 경우 발생하며, 2202G와 혼동하기 쉬운 유사 에러입니다. 샘플링 비율은 0 이상 100 이하의 값이어야 합니다.
  • 42601: syntax_errorTABLESAMPLE 또는 REPEATABLE 절의 문법 자체가 틀린 경우 발생하며, 에러 메시지를 통해 2202G와 구분할 수 있습니다.
  • 42883: undefined_function — 존재하지 않는 샘플링 메서드 이름(예: TABLESAMPLE RANDOM())을 사용할 때 발생하는 에러로, TABLESAMPLE 관련 문제 진단 시 함께 확인해야 합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기