2026년 08월 10일 | DBMS Error 가이드
이 글에서 다루는 내용
2201E 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2201E invalid argument for logarithm 는?
PostgreSQL 에러 코드 2201E는 로그 함수(log(), ln())에 유효하지 않은 인수가 전달될 때 발생하는 오류입니다. 수학적으로 로그 함수는 양수(0보다 큰 수)에 대해서만 정의되기 때문에, 0 또는 음수를 인수로 전달하면 이 에러가 발생합니다. 실무에서는 데이터 정제가 제대로 되지 않은 상태에서 집계 연산이나 통계 계산을 수행할 때 자주 마주치는 에러입니다.
주요 발생 원인
- 0 또는 음수 값을 로그 함수에 직접 전달
가장 흔한 원인으로, 테이블의 컬럼 값이 0이거나 음수인 상태에서 log() 또는 ln() 함수를 호출할 때 발생합니다. 예를 들어 재고 수량, 매출 금액, 측정값 등을 로그 스케일로 변환하는 과정에서 데이터 품질 문제가 있는 경우 이 에러를 유발합니다. 데이터 입력 단계에서 제약 조건이 없으면 예기치 않은 값이 들어올 수 있습니다.
- NULL 처리 미흡 또는 잘못된 기본값 설정
NULL 값 자체는 로그 함수 호출 시 NULL을 반환하므로 에러를 직접 유발하지는 않지만, COALESCE나 NULLIF 등을 사용해 NULL을 0으로 대체한 경우 문제가 됩니다. 예를 들어 log(COALESCE(amount, 0))처럼 작성하면 NULL을 0으로 바꾼 뒤 로그를 취하므로 2201E 에러가 발생합니다. NULL 방어 코드를 작성할 때 수학적 도메인 제약을 함께 고려해야 합니다.
- 동적 쿼리 또는 ETL 파이프라인에서 검증 없이 데이터 처리
ETL 파이프라인이나 데이터 변환 과정에서 외부 소스로부터 유입된 데이터를 별도 검증 없이 바로 로그 연산에 사용하는 경우 이 에러가 발생할 수 있습니다. 특히 배치 처리나 스케줄링된 작업에서 발생하면 전체 작업이 실패하는 심각한 상황으로 이어질 수 있습니다. 운영 환경에서는 데이터의 범위와 품질을 사전에 검증하는 로직이 반드시 필요합니다.
해결 방법
원인 1 해결: 조건문으로 유효한 값만 처리
CASE WHEN 또는 NULLIF를 사용하여 0이나 음수를 필터링합니다.
-- 잘못된 예: 0 또는 음수가 포함된 경우 에러 발생
SELECT log(sales_amount) FROM sales;
-- 올바른 예: CASE WHEN으로 유효한 값만 처리
SELECT
id,
sales_amount,
CASE
WHEN sales_amount > 0 THEN log(sales_amount)
ELSE NULL
END AS log_sales
FROM sales;
-- NULLIF를 활용한 간결한 방법 (0 제외, 음수는 추가 처리 필요)
SELECT
id,
log(NULLIF(sales_amount, 0)) AS log_sales
FROM sales
WHERE sales_amount > 0;
원인 2 해결: NULLIF와 GREATEST를 조합하여 안전하게 처리
-- 잘못된 예: NULL을 0으로 대체 후 로그 계산
SELECT log(COALESCE(amount, 0)) FROM transactions; -- 에러 발생!
-- 올바른 예: NULL은 NULL로 유지하거나 양수 기본값 사용
SELECT log(NULLIF(COALESCE(amount, 1), 0)) FROM transactions;
-- GREATEST 함수를 이용해 최소값 보장
SELECT
id,
log(GREATEST(amount, 0.0001)) AS safe_log_amount
FROM transactions
WHERE amount IS NOT NULL;
-- 아예 NULL로 반환하는 가장 안전한 패턴
SELECT
id,
CASE WHEN amount > 0 THEN log(amount) ELSE NULL END AS log_amount
FROM transactions;
원인 3 해결: ETL 파이프라인에 사전 검증 추가
-- 로그 연산 전 데이터 품질 체크 쿼리
SELECT
COUNT(*) AS total_rows,
COUNT(*) FILTER (WHERE value <= 0) AS invalid_rows,
COUNT(*) FILTER (WHERE value IS NULL) AS null_rows,
COUNT(*) FILTER (WHERE value > 0) AS valid_rows
FROM source_data;
-- 유효하지 않은 데이터를 별도 테이블로 격리
CREATE TABLE invalid_log_data AS
SELECT *, NOW() AS detected_at
FROM source_data
WHERE value <= 0 OR value IS NULL;
-- 유효한 데이터에 대해서만 로그 연산 수행
INSERT INTO processed_data (id, log_value, processed_at)
SELECT
id,
log(value),
NOW()
FROM source_data
WHERE value > 0;
-- 뷰를 만들어 항상 안전하게 접근
CREATE OR REPLACE VIEW safe_log_view AS
SELECT
id,
value,
CASE WHEN value > 0 THEN log(value) ELSE NULL END AS log_value,
CASE WHEN value > 0 THEN ln(value) ELSE NULL END AS ln_value
FROM source_data;
에러 발생 시 즉각적인 원인 파악 쿼리
-- 문제가 되는 레코드 즉시 확인
SELECT id, column_name, value
FROM your_table
WHERE value <= 0
ORDER BY value ASC
LIMIT 100;
-- 통계 확인으로 데이터 분포 파악
SELECT
MIN(value) AS min_val,
MAX(value) AS max_val,
AVG(value) AS avg_val,
COUNT(*) FILTER (WHERE value <= 0) AS non_positive_count,
COUNT(*) AS total_count
FROM your_table;
예방 방법
- CHECK 제약 조건으로 데이터 입력 단계에서 차단
테이블 생성 시 또는 ALTER TABLE로 로그 연산에 사용될 컬럼에 양수 제약 조건을 추가하면, 데이터 입력 단계에서 유효하지 않은 값을 원천 차단할 수 있습니다. 이는 가장 강력하고 근본적인 예방책입니다.
“`sql
— 테이블 생성 시 CHECK 제약 조건 추가
CREATE TABLE measurements (
id SERIAL PRIMARY KEY,
sensor_value NUMERIC NOT NULL,
CONSTRAINT chk_positive_value CHECK (sensor_value > 0)
);
— 기존 테이블에 제약 조건 추가
ALTER TABLE sales
ADD CONSTRAINT chk_positive_sales CHECK (sales_amount > 0);
“`
- 함수 또는 뷰로 안전한 로그 계산 로직을 캡슐화
반복적으로 사용되는 로그 계산 로직은 안전 처리 로직이 내장된 사용자 정의 함수나 뷰로 만들어 두면, 모든 호출 지점에서 일관되게 에러를 방지할 수 있습니다.
“`sql
— 안전한 로그 계산 함수 생성
CREATE OR REPLACE FUNCTION safe_log(p_value NUMERIC, p_base NUMERIC DEFAULT 10)
RETURNS NUMERIC AS $$
BEGIN
IF p_value IS NULL OR p_value <= 0 THEN
RETURN NULL;
END IF;
IF p_base IS NULL OR p_base <= 0 OR p_base = 1 THEN
RAISE EXCEPTION ‘로그의 밑은 양수이고 1이 아니어야 합니다.’;
END IF;
RETURN log(p_base, p_value);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
— 사용 예시
SELECT safe_log(sales_amount) FROM sales;
SELECT safe_log(100, 10); — 결과: 2
SELECT safe_log(-5); — 결과: NULL (에러 없음)
SELECT safe_log(0); — 결과: NULL (에러 없음)
“`
관련 에러
- 2201F (invalid_argument_for_power_function):
power()함수에 유효하지 않은 인수가 전달될 때 발생하며, 음수를 밑으로 하고 정수가 아닌 지수를 사용할 때 나타납니다. - 2201G (invalid_argument_for_width_bucket_function):
width_bucket()함수에 잘못된 인수가 전달될 때 발생합니다. - 22012 (division_by_zero): 0으로 나누기 시 발생하는 에러로, 수학 함수의 도메인 제약 위반이라는 맥락에서 2201E와 유사한 성격을 가집니다.
- 22003 (numeric_value_out_of_range): 연산 결과가 데이터 타입의 허용 범위를 초과할 때 발생하며, 로그 계산 결과 처리 시 함께 고려해야 합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.