MariaDB / 함수 / IF, IFNULL, NULLIF

MariaDB의 IF()는 조건에 따라 두 값 중 하나를 선택하고, IFNULL()은 NULL을 대체하며, NULLIF()는 두 값이 같을 때 NULL을 만듭니다. 이름은 비슷하지만 “조건 분기”, “누락 값 대체”, “특정 값을 누락 값으로 변환”이라는 목적이 서로 다릅니다.

함수 반환 규칙 예시 용도
IF(조건, 참 값, 그 외 값) 조건이 참일 때 둘째 값, 아니면 셋째 값 수량에 따른 표시 문구
IFNULL(값, 대체 값) 첫 값이 NULL이면 대체 값 누락 이름의 표시
NULLIF(값, 비교 값) 비교가 참이면 NULL, 아니면 첫 값 분모 0을 NULL로 처리

IF: 조건이 참인지 판단

다음 SELECT는 별도 테이블 없이 실행합니다. IF() 함수의 조건은 숫자 0과 NULL일 때 참으로 취급하지 않으며, 0이 아닌 숫자는 참으로 취급합니다.

SELECT IF(3 > 2, 'T', 'F') AS true_condition,
       IF(3 < 2, 'T', 'F') AS false_condition,
       IF(NULL, 'T', 'F') AS unknown_condition,
       IF(0, 'T', 'F') AS zero_condition,
       IF(-2, 'T', 'F') AS nonzero_condition;

결과는 T·F·F·F·T입니다. NULL 조건이 참이 아니라는 것과 데이터 자체가 거짓이라는 것은 구분해야 합니다. 미입력 수량과 실제 수량 0을 다른 상태로 표시하려면 IS NULL을 먼저 검사하는 CASE 등으로 상태를 명확히 나눕니다. 숫자로 변환될 문자열을 조건에 그대로 쓰기보다 quantity > 0처럼 비교식을 작성하면 의도가 잘 드러납니다.

SELECT 안에서 쓰는 IF()는 값을 반환하는 함수입니다. 저장 프로시저의 여러 문장을 분기하는 IF ... THEN ... END IF 문과 구문이 다르므로 서로 바꿔 적지 않습니다. 반환값의 숫자·문자열 타입도 사용 문맥에 영향을 받으므로, 금액 계산 결과와 설명 문구를 하나의 열에 섞기보다 계산용 열과 표시용 열을 분리하는 편이 명확합니다.

IFNULL: NULL만 대체

SELECT IFNULL(NULL, '미등록') AS missing_value,
       IFNULL('이름', '미등록') AS present_value,
       CONCAT('[', IFNULL('', '미등록'), ']') AS empty_value,
       IFNULL(0, 99) AS zero_value,
       IFNULL(NULL, NULL) AS both_null;

일반 모드의 결과는 미등록·이름·[]·0·NULL입니다. IFNULL()은 빈 문자열이나 숫자 0을 자동으로 바꾸지 않습니다. NULL 자체를 검사하려면 value IS NULL 또는 ISNULL(value)을 사용하며 value = NULL로 비교하지 않습니다. Oracle 호환 모드처럼 빈 문자열 해석이 다른 환경은 SQL 모드도 함께 확인합니다.

NULL을 0으로 바꾸면 숫자 합계나 평균의 의미가 달라질 수 있습니다. 값이 아직 모르는 상태인지 실제로 없는 수량인지 먼저 정해야 합니다. 화면 표시를 편하게 하려고 바꾼 값을 그대로 통계의 원자료로 사용하지 마세요. IFNULL은 조회 결과를 대체할 뿐 원래 열의 NULL을 UPDATE하지 않습니다.

NULLIF: 같은 값을 NULL로 변환

SELECT NULLIF(5, 5) AS equal_values,
       NULLIF(5, 2) AS different_values,
       NULLIF(NULL, 5) AS null_first,
       NULLIF(5, NULL) AS null_second,
       NULLIF(NULL, NULL) AS two_nulls;
SELECT 12 / NULLIF(0, 0) AS zero_denominator,
       12 / NULLIF(3, 0) AS valid_denominator;

첫 조회는 NULL·5·NULL·5·NULL입니다. NULLIF()는 첫 값과 둘째 값의 = 비교가 참일 때 NULL을 반환하고, 나머지 경우 첫 값을 반환합니다. 따라서 NULLIF(5,NULL)은 5이며 NULLIF(NULL,NULL)의 결과가 NULL인 것은 첫 값 자체가 NULL이기 때문입니다.

둘째 조회의 결과는 NULL·4.0000입니다. 분모를 NULLIF(분모,0)으로 감싸면 0인 분모를 NULL로 바꿉니다. 이는 “계산할 수 없음”을 남기는 방법이며 결과를 0으로 보장하는 방법은 아닙니다. 그 뒤 IFNULL로 0을 넣을지는 0점과 계산 불가가 업무에서 같은 뜻인지 판단한 다음 결정합니다. 소수 자릿수는 계산 타입과 설정에 따라 달라질 수 있습니다.

열을 조합하는 전체 조회 예제

실습용 learning 데이터베이스에서 CREATE·INSERT·SELECT 권한으로 실행합니다. null_choice_demo가 이미 있으면 이름을 바꿉니다. 아래는 일반 SQL 모드와 UTF-8 입력을 전제로 하며, 조회 전후에 원본 값은 그대로 유지됩니다.

USE learning;
CREATE TABLE null_choice_demo (
    id INT PRIMARY KEY,
    nickname VARCHAR(30) NULL,
    completed INT NULL,
    total INT NOT NULL
);
INSERT INTO null_choice_demo VALUES
    (1, 'Alpha', 8, 10), (2, '', 0, 0), (3, NULL, NULL, 5);
SELECT id,
       IFNULL(NULLIF(TRIM(nickname), ''), '미등록') AS display_name,
       IF(completed >= 5, '기준 충족', '재확인') AS progress_label,
       ROUND(100.0 * completed / NULLIF(total, 0), 1) AS percent_value
FROM null_choice_demo ORDER BY id;
SELECT COUNT(*) AS all_rows, COUNT(completed) AS known_rows,
       ROUND(AVG(completed), 2) AS known_average,
       ROUND(AVG(IFNULL(completed, 0)), 2) AS null_as_zero_average
FROM null_choice_demo;

첫 조회의 이름은 Alpha·미등록·미등록, 상태는 기준 충족·재확인·재확인, 비율은 80.0·NULL·NULL입니다. 이름의 공백 제거와 빈 문자열 대체는 이 예제의 표시 정책입니다. 보존해야 할 공백이 있으면 TRIM을 사용하지 않거나 원래 값과 표시 값을 분리하세요.

둘째 조회는 전체 행 3, 값이 있는 행 2, 알려진 값의 평균 4.00, NULL을 0으로 바꾼 평균 2.67입니다. AVG가 NULL을 제외하는 것과 NULL을 먼저 0으로 대체하는 것은 다른 계산입니다. 이처럼 함수 이름보다 먼저 “누락·0·빈 문자열을 각각 어떤 상태로 다룰 것인가”를 정하면 세 함수를 올바르게 조합할 수 있습니다.