2026년 10월 15일 | DBMS Error 가이드
이 글에서 다루는 내용
2201G 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2201G invalid argument for width bucket function 는?
PostgreSQL 에러 코드 2201G는 width_bucket() 함수에 잘못된 인자가 전달되었을 때 발생하는 오류입니다. width_bucket() 함수는 주어진 값이 균등하게 나뉜 버킷(bucket) 중 몇 번째 버킷에 속하는지를 반환하는 히스토그램 관련 함수인데, 이 함수의 인자로 허용되지 않는 값(예: 버킷 수가 0 이하, 하한값과 상한값이 동일한 경우 등)이 전달될 때 이 에러가 트리거됩니다. 데이터 분석, 통계 쿼리, 데이터 분포 시각화 등의 작업에서 자주 접하게 되며, 특히 동적으로 인자를 생성하는 환경에서 예상치 못하게 발생할 수 있습니다.
주요 발생 원인
- 버킷 수(count)가 0 이하인 경우
width_bucket() 함수의 세 번째 인자인 버킷 수는 반드시 1 이상의 양의 정수여야 합니다. 버킷 수로 0이나 음수를 전달하면 PostgreSQL은 이를 유효하지 않은 인자로 판단하고 즉시 2201G 에러를 발생시킵니다. 특히 버킷 수를 다른 컬럼의 값이나 계산식으로부터 동적으로 가져오는 경우, 해당 값이 0이 되거나 음수가 되는 상황이 의외로 빈번하게 발생합니다.
- 하한값(lower bound)과 상한값(upper bound)이 동일한 경우
width_bucket(operand, lower, upper, count) 형식에서 lower와 upper가 같은 값이면 버킷의 구간 크기가 0이 되어 의미 있는 분할이 불가능합니다. PostgreSQL은 이 경우에도 2201G 에러를 반환하며, 범위 없는 구간으로는 값을 분류할 수 없기 때문입니다. 데이터 정제가 완벽하지 않거나, MIN()과 MAX()로 경계를 자동 산출할 때 모든 데이터가 동일한 값인 상황에서 이 문제가 발생하기 쉽습니다.
- NaN 또는 Infinity 값이 인자로 전달되는 경우
부동소수점(float) 타입을 다루는 쿼리에서는 NaN(Not a Number)이나 Infinity 값이 하한, 상한, 또는 피연산자로 들어오는 경우가 있습니다. 이런 특수 값들은 수학적으로 유효한 버킷 범위를 정의할 수 없기 때문에 2201G 에러를 유발합니다. 센서 데이터, 금융 계산 결과, 외부 API로부터 유입된 데이터를 그대로 사용할 경우 이 문제를 특히 주의해야 합니다.
해결 방법
원인 1 해결: 버킷 수 검증 및 보정
버킷 수가 항상 1 이상이 되도록 GREATEST() 함수나 CASE 문을 활용하여 안전하게 처리합니다.
-- 문제 발생 예시
SELECT width_bucket(score, 0, 100, 0)
FROM exam_results;
-- ERROR: invalid argument for width bucket function
-- 해결 방법 1: GREATEST로 최솟값 보장
SELECT width_bucket(score, 0, 100, GREATEST(1, bucket_count))
FROM exam_results;
-- 해결 방법 2: CASE 문으로 방어적 처리
SELECT
CASE
WHEN bucket_count <= 0 THEN NULL
ELSE width_bucket(score, 0, 100, bucket_count)
END AS bucket
FROM exam_results;
-- 해결 방법 3: 집계 쿼리에서 동적 버킷 수 사용 시
SELECT width_bucket(amount, 0, 10000, GREATEST(1, num_buckets))
FROM transactions
CROSS JOIN (SELECT COUNT(DISTINCT category)::int AS num_buckets FROM transactions) t;
원인 2 해결: 하한값과 상한값이 같은 경우 처리
MIN()과 MAX()를 사용해 자동으로 경계를 설정할 때, 두 값이 동일할 가능성을 반드시 처리해야 합니다.
-- 문제 발생 예시: 모든 값이 동일한 경우
SELECT width_bucket(price, 100, 100, 10)
FROM products;
-- ERROR: invalid argument for width bucket function
-- 해결 방법 1: 상하한 동일 시 NULL 반환
SELECT
CASE
WHEN min_price = max_price THEN 1 -- 단일 버킷으로 처리
ELSE width_bucket(price, min_price, max_price, 10)
END AS price_bucket
FROM products
CROSS JOIN (
SELECT MIN(price) AS min_price, MAX(price) AS max_price
FROM products
) bounds;
-- 해결 방법 2: 소폭의 오프셋을 추가하여 안전하게 처리
SELECT width_bucket(
price,
min_price,
CASE WHEN min_price = max_price THEN max_price + 1 ELSE max_price END,
10
) AS price_bucket
FROM products
CROSS JOIN (
SELECT MIN(price) AS min_price, MAX(price) AS max_price
FROM products
) bounds;
원인 3 해결: NaN 및 Infinity 값 필터링
데이터 입력 전 또는 쿼리 실행 전에 특수 부동소수점 값을 제거하거나 대체합니다.
-- 문제 발생 예시
SELECT width_bucket(sensor_value::float, 0.0, 100.0, 10)
FROM sensor_data;
-- NaN이나 Infinity가 포함된 경우 ERROR 발생
-- 해결 방법 1: IS FINITE 조건으로 필터링
SELECT width_bucket(sensor_value, 0.0, 100.0, 10) AS bucket
FROM sensor_data
WHERE sensor_value IS NOT NULL
AND sensor_value != 'NaN'::float
AND sensor_value != 'Infinity'::float
AND sensor_value != '-Infinity'::float;
-- 해결 방법 2: NULLIF와 CASE를 활용한 안전한 변환
SELECT
CASE
WHEN sensor_value IS NULL
OR sensor_value = 'NaN'::float
OR NOT isfinite(sensor_value)
THEN NULL
ELSE width_bucket(sensor_value, 0.0, 100.0, 10)
END AS bucket
FROM sensor_data;
-- 해결 방법 3: 배열 형식 width_bucket 사용 (더 유연한 대안)
SELECT width_bucket(sensor_value, ARRAY[0, 10, 20, 50, 100]::float[]) AS bucket
FROM sensor_data
WHERE isfinite(sensor_value);
예방 방법
- 입력 데이터 유효성 검사 제약 조건 추가
테이블 설계 단계에서부터 CHECK 제약 조건을 활용하여 비정상적인 값이 데이터베이스에 저장되지 않도록 원천 차단합니다. 또한 width_bucket()을 자주 사용하는 컬럼에는 CHECK (value IS NOT NULL AND isfinite(value)) 같은 제약을 명시적으로 추가하고, 뷰(View)나 래퍼 함수를 만들어 항상 검증된 인자만 전달되도록 아키텍처를 설계하는 것이 좋습니다.
“`sql
— 안전한 width_bucket 래퍼 함수 생성
CREATE OR REPLACE FUNCTION safe_width_bucket(
operand float,
lower_bound float,
upper_bound float,
bucket_count int
)
RETURNS int AS $$
BEGIN
IF operand IS NULL OR NOT isfinite(operand) THEN RETURN NULL; END IF;
IF lower_bound IS NULL OR upper_bound IS NULL THEN RETURN NULL; END IF;
IF lower_bound >= upper_bound THEN RETURN NULL; END IF;
IF bucket_count < 1 THEN RETURN NULL; END IF;
RETURN width_bucket(operand, lower_bound, upper_bound, bucket_count);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
“`
- 통계 쿼리 실행 전 데이터 분포 사전 확인
width_bucket()을 사용하는 분석 쿼리를 작성할 때는 항상 사전에 데이터의 분포를 확인하는 습관을 들이세요. SELECT MIN(), MAX(), COUNT(DISTINCT ...), COUNT(*) FILTER (WHERE NOT isfinite(...)) 등의 사전 점검 쿼리를 실행하여 경계값 설정이 유효한지 확인한 후 본 쿼리를 실행하면 런타임 에러를 크게 줄일 수 있습니다. CI/CD 파이프라인이나 ETL 프로세스에 이러한 데이터 품질 검사를 자동화하여 포함시키는 것을 강력히 권장합니다.
관련 에러
22003(numeric_value_out_of_range):width_bucket()의 결과값이 정수 범위를 초과할 때 발생할 수 있으며, 버킷 수를 지나치게 크게 설정한 경우 연관되어 나타납니다.22012(division_by_zero): 내부적으로 버킷 구간 크기를 계산하는 과정에서 범위가 0이 되는 경우 유사하게 발생할 수 있습니다.22P02(invalid_text_representation): 문자열을 숫자로 캐스팅하여width_bucket()에 전달할 때 캐스팅 실패로 이어지는 경우 함께 마주치는 에러입니다.2201F(invalid_argument_for_power_function): 같은 카테고리(수학 함수 인자 오류)에 속하는 관련 에러로, 수학 함수 인자 처리 로직을 공통화할 때 함께 고려해야 합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.