본문으로 바로가기
TaeyoungKim.dev

SQL COUNT(*)와 COUNT(컬럼) 차이: NULL은 왜 건수에서 빠질까?

DB/SQL작성 약 2분 읽기TaeyoungKim
LinkedInX

작업은 네 건인데 ‘재시도 횟수가 기록된 작업’은 세 건이라고 나온다. 한 건이 사라졌나? 두 숫자가 서로 다른 대상을 세었을 가능성이 크다. COUNT(*)는 결과의 행을, COUNT(컬럼)은 그 컬럼에서 NULL이 아닌 값을 센다.

COUNT 함수의 별표와 컬럼은 무엇을 셀까?

다음 네 작업에서 retry_count가 NULL인 것은 3번 한 건이다. 1번의 0은 ‘재시도하지 않았다’는 기록된 값이지, 값이 없는 상태가 아니다.

도식에서 0은 값이므로 세지만 NULL은 COUNT(retry_count)에서 빠진다. 네 행을 만든 뒤 두 집계 결과를 같은 쿼리에서 비교해 보자.

sql
CREATE TABLE jobs (
  id INTEGER PRIMARY KEY,
  retry_count INTEGER
);

INSERT INTO jobs (id, retry_count) VALUES
  (1, 0), (2, 2), (3, NULL), (4, 1);

SELECT COUNT(*) AS total_jobs,
       COUNT(retry_count) AS recorded_jobs
FROM jobs;
total_jobsrecorded_jobs
43

COUNT(*)의 별표는 각 행을 세라는 뜻이다. 반면 COUNT(retry_count)는 그 열의 값이 있는 행만 센다. 그래서 0, 2, 1은 포함되고 NULL 한 건만 빠진다.

NULL인 작업은 어떻게 찾을까?

두 건수의 차이는 같은 입력 행 집합에서 그 컬럼이 NULL인 행의 수다.

sql
SELECT COUNT(*) - COUNT(retry_count) AS missing_retry_count
FROM jobs;
-- 1

SELECT id FROM jobs WHERE retry_count IS NULL;
-- 3

missing_retry_count = 1은 누락된 값의 개수, id = 3은 그 값이 없는 작업을 보여 준다. 숫자 0을 누락으로 취급해 세면 답이 틀어진다.

WHERE를 붙이면 왜 두 COUNT가 같아질까?

WHERE가 먼저 NULL 행을 제외하면, 그 뒤에 세는 행에는 빠진 값이 없다.

sql
SELECT COUNT(*) AS rows_after_filter,
       COUNT(retry_count) AS recorded_after_filter
FROM jobs
WHERE retry_count IS NOT NULL;
-- 3 | 3

따라서 건수가 예상과 다를 때는 괄호 안만 보지 말고 같은 FROM·WHERE 결과를 세고 있는지 확인하자. 조인으로 행이 늘어난 쿼리라면 COUNT(*)도 원본 작업 수가 아니라 늘어난 결과 행을 센다.

핵심 요약

COUNT(*)는 결과 행 전체를 세고, COUNT(컬럼)은 그 열의 NULL을 제외한다. 0은 빠지지 않는다. 차이를 조사할 때는 COUNT(*) - COUNT(컬럼)으로 누락된 값의 수를 보고, IS NULL로 해당 행을 확인하면 된다.

작성자

TaeyoungKim

기초 개념을 구현과 검증, 실제 운영 판단까지 연결해 기록합니다.

#SQL COUNT#COUNT(*)#COUNT(컬럼)#SQL NULL#집계 함수

함께 읽으면 좋은 글