숏컷 코드
SELECT
name,
COALESCE(nickname, name) AS display_name
FROM users
WHERE deleted_at IS NULL;문법
NULL은 세 값 논리를 만들어 일반 비교 연산자를 무력화한다
SQL의 논리는 참/거짓/알 수 없음(UNKNOWN) 세 가지 상태로 동작합니다. NULL = NULL 은 TRUE 가 아니라 UNKNOWN 이고, WHERE 절은 UNKNOWN 을 거짓으로 처리해 행을 제거합니다. 따라서 WHERE column = NULL 은 항상 결과가 없고, WHERE column != NULL 도 마찬가지입니다. NULL 여부를 비교하려면 반드시 IS NULL / IS NOT NULL 을 써야 합니다.
-- 절대 행을 반환하지 않음 (NULL과 = 비교는 UNKNOWN)
SELECT * FROM users WHERE nickname = NULL;
-- 올바른 NULL 확인
SELECT * FROM users WHERE nickname IS NULL;
SELECT * FROM users WHERE nickname IS NOT NULL;NULL은 빈 문자열이나 0과 다른 별도 상태다
NULL은 "값이 없다"는 상태이지 빈 문자열 ''이나 숫자 0이 아닙니다. 그래서 비교, 집계, JOIN에서 따로 취급됩니다. 이 차이를 먼저 잡아야 COALESCE, IS NULL, COUNT(column) 동작이 자연스럽게 읽힙니다.
SELECT
nickname,
nickname IS NULL AS is_null,
nickname = '' AS is_empty_string
FROM users;COALESCE 는 NULL을 대체값으로 교체하지만 쇼트서킷 평가가 적용된다
COALESCE(a, b, c) 는 왼쪽부터 순서대로 평가해 처음 나오는 non-NULL 값을 반환합니다. 쇼트서킷 평가가 적용되므로 앞 인자가 non-NULL 이면 뒤 인자는 평가하지 않습니다. 이 특성을 이용해 비용이 높은 함수 호출을 뒤에 배치해 불필요한 실행을 피할 수 있습니다. 단, COALESCE 는 표현식 인덱스와 결합할 때 인덱스를 타지 않을 수 있으므로 필터 조건보다는 SELECT 목록에 사용하는 것이 성능상 안전합니다.
-- 닉네임 없으면 이름, 이름도 없으면 '익명'
SELECT COALESCE(nickname, name, '익명') AS display_name
FROM users;
-- NULLIF: 두 값이 같으면 NULL 반환 (0으로 나누기 방지 등)
SELECT total_amount / NULLIF(item_count, 0) AS unit_price
FROM orders;NULL은 집계 함수와 GROUP BY에서 조용히 행을 누락시킨다
COUNT(*) 는 NULL 포함 전체 행을 셉니다. 그러나 COUNT(column) 은 해당 컬럼이 NULL 인 행을 제외합니다. SUM, AVG, MAX, MIN 도 NULL 을 무시합니다. GROUP BY 는 NULL 을 하나의 그룹 키로 취급하므로 NULL 값을 가진 행은 별도 그룹으로 묶입니다. 집계 결과가 예상보다 작다면 NULL 누락 여부를 먼저 확인해야 합니다.
-- COUNT(*) vs COUNT(column) 차이 확인
SELECT
COUNT(*) AS total_rows,
COUNT(nickname) AS with_nickname,
COUNT(*) - COUNT(nickname) AS null_nickname_count
FROM users;
-- NULL을 포함한 합계 (COALESCE로 0 대체)
SELECT SUM(COALESCE(score, 0)) AS total_score
FROM quiz_results;LEFT JOIN 결과의 NULL과 진짜 NULL 컬럼을 구분해야 한다
LEFT JOIN 에서 매칭 행이 없을 때 오른쪽 컬럼이 모두 NULL 이 되는데, 이 NULL 은 "데이터 없음"을 뜻하는 구조적 NULL 입니다. 하지만 매칭 행이 존재하더라도 그 행의 컬럼 값 자체가 NULL 일 수 있습니다. 두 경우를 구분하려면 오른쪽 테이블의 기본 키(NOT NULL 이 보장된 컬럼)를 기준으로 IS NULL 을 판단하는 것이 안전합니다.
-- 올바른 안티조인: 기본 키로 관계 부재 판단
SELECT u.id, u.name
FROM users AS u
LEFT JOIN posts AS p ON p.user_id = u.id
WHERE p.id IS NULL; -- p.title IS NULL 은 실제 NULL 값과 혼동 가능체크포인트
| 상황 | 적합한 선택 |
|---|---|
| NULL 여부 확인 | IS NULL / IS NOT NULL |
| NULL 을 대체값으로 교체할 때 | COALESCE(a, b, ...) |
| 두 값이 같으면 NULL 반환이 필요할 때 | NULLIF(a, b) |
| NULL 포함 전체 행 집계 | COUNT(*) |
| NULL 제외 집계 | COUNT(column), SUM(column) 등 |
| LEFT JOIN 에서 관계 부재 판단 | 오른쪽 PK 컬럼으로 IS NULL 확인 |
주의할 점
WHERE column = NULL 은 항상 빈 결과를 반환합니다. NULL 은 =, !=, <> 같은 일반 비교 연산자로 비교할 수 없으며,
비교 결과는 항상 UNKNOWN 이 됩니다. 집계 함수(COUNT, SUM, AVG)는 NULL 을 조용히 무시하므로
집계 결과가 예상보다 작다면 NULL 누락을 먼저 의심해야 합니다.
SELECT * FROM users WHERE COALESCE(nickname, '') = '';이 패턴은 NULL과 빈 문자열을 같은 의미로 취급합니다. 둘을 실제로 같은 뜻으로 써도 되는지 먼저 확인하지 않으면, 데이터 의미가 섞여 버릴 수 있습니다.
참고 링크
2 sources