2026년 10월 18일 | DBMS Error 가이드
이 글에서 다루는 내용
2202G 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2202G invalid tablesample repeat 는?
PostgreSQL 에러 코드 2202G: invalid tablesample repeat는 TABLESAMPLE 절에서 사용하는 반복(repeat) 시드(seed) 값이 유효하지 않을 때 발생하는 에러입니다. TABLESAMPLE 기능은 테이블에서 무작위 샘플 데이터를 추출할 때 사용하며, REPEATABLE 키워드를 통해 동일한 시드 값으로 재현 가능한 샘플링을 지원합니다. 그러나 REPEATABLE 절에 전달된 값이 허용 범위를 벗어나거나 잘못된 데이터 타입이 입력되면 이 에러가 트리거됩니다.
쉽게 말해, SELECT * FROM my_table TABLESAMPLE BERNOULLI(10) REPEATABLE(시드값) 구문에서 시드값이 PostgreSQL이 기대하는 형식이나 범위를 벗어날 경우 데이터베이스 엔진이 해당 요청을 거부하며 이 에러를 반환합니다. 실무에서는 동적 쿼리 생성 시 프로그래밍 언어로부터 잘못된 값이 바인딩될 때 자주 마주치는 에러입니다.
주요 발생 원인
1. REPEATABLE 시드 값으로 NULL 또는 NaN이 전달된 경우
REPEATABLE 절은 부동소수점 숫자(double precision)를 인자로 받습니다. 이 값에 NULL이나 NaN(Not a Number)이 전달되면 PostgreSQL은 유효하지 않은 반복 값으로 판단하고 즉시 에러를 발생시킵니다. 특히 애플리케이션에서 동적으로 시드 값을 생성할 때, 초기화되지 않은 변수나 계산 실패로 인해 NULL 또는 NaN이 넘어오는 경우가 빈번합니다.
2. REPEATABLE 시드 값이 허용 범위를 초과한 경우
PostgreSQL의 TABLESAMPLE 메서드(BERNOULLI, SYSTEM)에서 REPEATABLE에 사용할 수 있는 시드 값은 내부적으로 특정 범위의 숫자를 요구합니다. 무한대(Infinity) 값이나 표현 불가능한 극단적인 부동소수점 값이 입력되면 샘플링 알고리즘이 올바르게 동작할 수 없어 에러가 발생합니다. ORM(Object-Relational Mapper) 또는 BI 툴에서 자동으로 생성된 쿼리에서 이런 경우가 종종 발생합니다.
3. 잘못된 데이터 타입이 REPEATABLE 절에 전달된 경우
REPEATABLE 절은 숫자형 리터럴만 허용하는데, 문자열이나 날짜 타입 등 호환되지 않는 타입이 명시적 혹은 묵시적으로 전달될 경우 에러가 발생할 수 있습니다. 동적 SQL을 생성하는 스크립트나 저장 프로시저에서 변수 타입을 잘못 처리하면 이런 상황이 만들어집니다. PostgreSQL은 타입 캐스팅이 불가능하다고 판단하면 쿼리 파싱 혹은 실행 단계에서 해당 에러를 반환합니다.
해결 방법
원인 1 해결: NULL 또는 NaN 값 방지
시드 값이 NULL이거나 NaN인지 사전에 검사하고, 유효한 기본값으로 대체합니다.
-- 잘못된 예: NULL이 시드로 전달되는 경우
-- SELECT * FROM orders TABLESAMPLE BERNOULLI(10) REPEATABLE(NULL);
-- 위 쿼리는 2202G 에러를 발생시킵니다.
-- 올바른 예: COALESCE를 사용하여 NULL을 기본 시드값으로 대체
DO $$
DECLARE
v_seed DOUBLE PRECISION := NULL; -- 애플리케이션에서 NULL이 전달된 상황 가정
v_safe_seed DOUBLE PRECISION;
BEGIN
-- NULL이면 기본값 42를 사용
v_safe_seed := COALESCE(v_seed, 42);
-- 안전한 시드값으로 샘플링 수행
EXECUTE format(
'SELECT * FROM orders TABLESAMPLE BERNOULLI(10) REPEATABLE(%s)',
v_safe_seed
);
RAISE NOTICE 'Sampling completed with seed: %', v_safe_seed;
END;
$$;
-- 직접 쿼리에서 NaN 방지 예제
SELECT *
FROM orders
TABLESAMPLE BERNOULLI(10)
REPEATABLE(
CASE
WHEN pg_typeof(42.0::float8) = 'double precision'::regtype
AND 42.0 = 42.0 -- NaN 체크: NaN != NaN은 TRUE
THEN 42.0
ELSE 1234.0 -- 기본 안전 시드
END
);
원인 2 해결: 허용 범위 내의 유효한 시드 값 사용
무한대나 극단적인 부동소수점 값 대신, 일반적인 정수 또는 소수를 시드로 사용합니다.
-- 잘못된 예: 무한대 값 사용
-- SELECT * FROM products TABLESAMPLE SYSTEM(5) REPEATABLE('Infinity'::float8);
-- 이 쿼리는 2202G 에러를 발생시킵니다.
-- 올바른 예 1: 정적 시드 값 사용
SELECT *
FROM products
TABLESAMPLE SYSTEM(5)
REPEATABLE(12345);
-- 올바른 예 2: 현재 날짜 기반의 동적 시드 값 생성 (재현 가능한 일별 샘플링)
SELECT *
FROM products
TABLESAMPLE BERNOULLI(10)
REPEATABLE(
EXTRACT(EPOCH FROM CURRENT_DATE)::BIGINT % 1000000
);
-- 올바른 예 3: 저장 프로시저에서 안전한 시드 범위 보장
CREATE OR REPLACE FUNCTION safe_tablesample(
p_table_name TEXT,
p_percent NUMERIC,
p_seed DOUBLE PRECISION DEFAULT 42.0
)
RETURNS SETOF RECORD AS $$
DECLARE
v_safe_seed DOUBLE PRECISION;
v_query TEXT;
BEGIN
-- 무한대, NaN, NULL 모두 방어
IF p_seed IS NULL OR p_seed != p_seed OR p_seed = 'Infinity'::float8
OR p_seed = '-Infinity'::float8 THEN
v_safe_seed := 42.0;
ELSE
-- 범위를 0 ~ 999999 사이로 제한
v_safe_seed := ABS(p_seed) % 1000000;
END IF;
v_query := format(
'SELECT * FROM %I TABLESAMPLE BERNOULLI(%s) REPEATABLE(%s)',
p_table_name, p_percent, v_safe_seed
);
RETURN QUERY EXECUTE v_query;
END;
$$ LANGUAGE plpgsql;
원인 3 해결: 명시적 타입 캐스팅 적용
REPEATABLE 절에 전달되는 값을 항상 double precision 타입으로 명시적으로 캐스팅합니다.
-- 잘못된 예: 문자열 타입이 넘어올 수 있는 상황
-- 동적 SQL에서 타입이 불명확한 경우
DO $$
DECLARE
v_seed_str TEXT := '99999'; -- 문자열로 들어온 시드값
BEGIN
-- 잘못된 방법: 타입 변환 없이 그대로 사용
-- EXECUTE 'SELECT * FROM users TABLESAMPLE BERNOULLI(10) REPEATABLE(' || v_seed_str || ')';
-- 올바른 방법: 명시적으로 double precision으로 캐스팅
EXECUTE format(
'SELECT * FROM users TABLESAMPLE BERNOULLI(10) REPEATABLE(%s)',
v_seed_str::DOUBLE PRECISION
);
RAISE NOTICE 'Query executed successfully.';
END;
$$;
-- 뷰 생성 시 안전한 캐스팅 적용 예제
CREATE OR REPLACE VIEW v_sample_customers AS
SELECT *
FROM customers
TABLESAMPLE BERNOULLI(20)
REPEATABLE(20240101::DOUBLE PRECISION); -- 명시적 캐스팅으로 안전하게
-- 검증 쿼리: 시드 값의 유효성을 사전에 확인
SELECT
CASE
WHEN '99999'::TEXT ~ '^-?[0-9]+(\.[0-9]+)?$' THEN '유효한 숫자 시드'
ELSE '유효하지 않은 시드값 - 기본값 사용 필요'
END AS seed_validation;
예방 방법
1. 시드 값 생성 함수 표준화 및 공통 유틸리티 함수 사용
팀 내에서 TABLESAMPLE REPEATABLE을 사용할 때는 검증된 공통 래퍼 함수를 만들어 사용하는 것을 표준으로 삼아야 합니다. 아래처럼 시드 유효성 검사를 캡슐화한 함수를 DB 레벨에서 제공하면, 개발자가 실수로 잘못된 값을 전달하는 것을 원천 차단할 수 있습니다.
-- 공통 시드 검증 함수 예제
CREATE OR REPLACE FUNCTION validate_tablesample_seed(p_seed ANYELEMENT)
RETURNS DOUBLE PRECISION AS $$
DECLARE
v_seed DOUBLE PRECISION;
BEGIN
BEGIN
v_seed := p_seed::DOUBLE PRECISION;
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Invalid seed value provided: %. Using default seed 42.', p_seed;
RETURN 42.0;
END;
IF v_seed IS NULL OR v_seed != v_seed OR
v_seed = 'Infinity'::float8 OR v_seed = '-Infinity'::float8 THEN
RAISE WARNING 'Seed value % is not finite. Using default seed 42.', v_seed;
RETURN 42.0;
END IF;
RETURN ABS(v_seed) % 1000000;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- 사용 예
SELECT * FROM large_table
TABLESAMPLE BERNOULLI(5)
REPEATABLE(validate_tablesample_seed(NULL)); -- NULL이어도 안전하게 42 반환
2. CI/CD 파이프라인 및 코드 리뷰에서 TABLESAMPLE 쿼리 정적 분석
동적으로 TABLESAMPLE 쿼리를 생성하는 코드는 반드시 코드 리뷰 체크리스트에 포함시키고, REPEATABLE 절의 인자가 항상 안전하게 처리되는지 확인해야 합니다. pgTAP 같은 PostgreSQL 테스팅 프레임워크를 활용해 경계값(NULL, NaN, Infinity, 음수)을 포함한 단위 테스트를 작성해두면 사전에 에러를 잡을 수 있으며, 배포 전 자동화된 쿼리 검증 단계를 파이프라인에 통합하는 것이 좋습니다.
관련 에러
- 22003 numeric_value_out_of_range:
TABLESAMPLE퍼센트 값(0~100)이 범위를 벗어날 때 발생하며,REPEATABLE시드 관련 문제와 함께 발생하기도 합니다. - 2202H invalid tablesample argument:
TABLESAMPLE절의 샘플 비율 인자 자체가 유효하지 않을 때 발생하는 에러로, 2202G와 유사한 맥락의 에러입니다. 시드 값 대신 샘플링 비율(BERNOULLI(percent))의 값이 NULL이거나 범위를 벗어날 경우 이 에러가 발생합니다. - 42601 syntax_error:
REPEATABLE절의 문법 자체가 잘못되었을 때 발생하며, 동적 SQL 생성 시 괄호 누락 등으로 자주 발생합니다. - 42883 undefined_function: 커스텀
TABLESAMPLE메서드를 사용하는 경우 해당 메서드가 등록되지 않았을 때 발생할 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.