전 유저 결제 요약 (NULL 처리)

난이도 보통 · 권장 10분 · 출력 컬럼 user_id, channel, pay_count, total_amount, last_paid
이 문제 직접 풀어보기 →

문제

모든 유저에 대해 결제 요약을 만드세요. 결제 이력이 없는 유저도 빠짐없이 포함해야 합니다. user_id 유저 ID channel 유입 채널 pay_count 결제 건수 (없으면 0) total_amount 결제 금액 합계 (없으면 0) last_paid 마지막 결제일 (없으면 NULL 그대로 둘 것) · total_amount 는 숫자여야 합니다. 문자로 바꾸지 마세요. · 결제가 있는 유저를 먼저, 없는 유저를 뒤로 보내세요. · 그 안에서는 total_amount 내림차순, 같으면 user_id 오름차순입니다. · 상위 20행만 출력하세요.
정렬 결제없음 뒤로, total_amount DESC, user_id ASC / LIMIT 20

쉽게 설명하면

전교생 명단에 성적을 붙이는데, 시험 안 본 애도 명단에 남아야 한다. 점수 칸은 0 으로, 시험 날짜 칸은 빈칸으로.

더할 게 하나도 없을 때 뭐가 나오나 — 이걸 알아야 풀린다.

함수아무것도 없을 때
COUNT(*) · COUNT(칸)0
SUM · AVG · MAX · MINNULL (0 이 아니다!)

이렇게 푼다

  1. 유저 명단을 왼쪽에 두고 결제를 붙인다 (LEFT JOIN).
  2. 건수는 COUNT — 결제가 없으면 자동으로 0 이 된다.
  3. 금액은 COALESCE(SUM(금액), 0) — SUM 밖에 씌운다.
  4. 마지막 결제일은 NULL 그대로 둔다.
  5. 결제 없는 사람을 뒤로 보내고, 금액 많은 순, 상위 20명만.

이것만 피하면 된다

자세히

묻는 것 · LEFT JOIN 후 NULL 을 어떻게 다루는가. 그리고 NULL 정렬.

풀이 순서

  1. users 기준 LEFT JOIN.
  2. 건수는 COUNT(p.user_id) — NULL 을 안 세므로 0 이 된다.
  3. 합계는 COALESCE(SUM(...), 0) — SUM 은 대상이 없으면 NULL 을 반환한다.
  4. 마지막 결제일은 NULL 그대로 두되, 정렬에서 뒤로 보낸다.

정답 (MySQL)

SELECT u.user_id, u.channel,
       COUNT(p.user_id)           AS pay_count,
       COALESCE(SUM(p.amount), 0) AS total_amount,
       MAX(p.paid_date)           AS last_paid
FROM users u
LEFT JOIN payments p ON p.user_id = u.user_id
GROUP BY u.user_id, u.channel
ORDER BY (MAX(p.paid_date) IS NULL), COALESCE(SUM(p.amount),0) DESC, u.user_id
LIMIT 20;

함정

이렇게 변형된다

“주문 없는 고객 포함 요약”, “미거래 종목 포함” 전부 동일.

← Q10. 채널별 ARPPU와 순위 변동Q12. 채널별 pro 비중 (0 나누기) →