pro_ratio DESC, channel ASC결제한 사람 중에 비싼 요금제 쓴 비율. 결제한 사람이 0명인 채널은 계산이 불가능하니 빈칸이어야 한다.
| 채널 | 결제 유저 | pro 유저 | 비중 |
|---|---|---|---|
| organic | 371 | 130 | 35.04 |
| newsletter | 0 | 0 | NULL |
0 ÷ 0 은 '0%' 가 아니다. 계산할 수 없음 이다. 그래서 0 이 아니라 빈칸(NULL)이 맞다. 그리고 그 채널도 결과에 나와야 한다.
pro수 * 100.0 / NULLIF(결제수, 0).NULLIF(분모, 0) 이 이 문제의 전부다. '분모가 0 이면 NULL 로 바꿔라' 는 뜻이고, NULL 로 나누면 결과가 NULL 이 된다. 이름이 헷갈리는데, NULLIF 는 NULL 을 만드는 함수다.IFNULL 과 반대다. IFNULL(분모, 0) 은 NULL 을 0 으로 바꿔서 0 나누기를 일부러 만든다. 정반대다.WHERE 로 걸러내면 안 된다. 그 줄도 나와야 한다.묻는 것 · 분모가 0 이 될 수 있는 상황을 아는가.
NULLIF(분모, 0) 로 감싼다.SELECT u.channel,
COUNT(DISTINCT p.user_id) AS paying_users,
COUNT(DISTINCT CASE WHEN p.plan='pro' THEN p.user_id END) AS pro_users,
ROUND(100.0 * COUNT(DISTINCT CASE WHEN p.plan='pro' THEN p.user_id END)
/ NULLIF(COUNT(DISTINCT p.user_id), 0), 2) AS pro_ratio
FROM users u
LEFT JOIN payments p ON p.user_id = u.user_id
GROUP BY u.channel
ORDER BY pro_ratio DESC, u.channel;IFNULL(분모, 0) 은 정반대다. 0 나누기를 막는 게 아니라 만든다. 방어는 NULLIF(분모, 0).CASE WHEN ... THEN user_id END 에 ELSE 를 쓰지 않는다. ELSE 0 을 넣으면 0 도 값이라 DISTINCT 집계에 섞인다.“환불률”, “쿠폰 사용률” 처럼 모집단이 비어 있을 수 있는 비율 전부.