3개월 이상 연속 결제한 유저

난이도 어려움 · 권장 20분 · 출력 컬럼 users_with_3plus_streak
이 문제 직접 풀어보기 →

문제

결제한 '월'이 3개월 이상 끊김 없이 이어진 적이 있는 유저가 몇 명인지 구하세요. · 한 유저가 여러 연속 구간을 가질 수 있으나 유저 수는 중복 없이 셉니다. · 결과는 한 행입니다.
정렬 (단일 행)

쉽게 설명하면

출석 도장. 1월·2월·3월 쭉 찍었으면 3연속. 1월·3월만 찍었으면 끊긴 것. 이 트릭은 외워 두면 평생 쓴다.

결제한 달달 번호줄 번호차이
1월110
2월220
3월330
6월642

차이가 같은 것끼리 한 덩어리다. 위에서는 0 이 세 개니까 3연속. 연속이면 달 번호와 줄 번호가 똑같이 1씩 늘어서 차이가 안 변한다. 끊기면 달 번호만 껑충 뛰어서 차이가 달라진다.

이렇게 푼다

  1. 사람별로 결제한 달 목록을 중복 없이 만든다.
  2. 달을 숫자로 바꾼다 (기준월부터 몇 개월째인가).
  3. 달 숫자 − 줄 번호를 계산한다.
  4. 그 값으로 묶어서 개수를 세고, 3 이상만 남긴다.

이것만 피하면 된다

자세히

묻는 것 · gaps and islands. 알면 1분, 모르면 못 푼다.

풀이 순서

  1. 유저별 결제한 월 목록을 중복 없이 만든다.
  2. 월을 일련번호로 바꾼다 (기준월로부터 몇 개월째인가).
  3. 일련번호 − ROW_NUMBER() → 연속 구간마다 같은 값이 나온다.
  4. 그 값으로 묶어 개수를 세고 3 이상만 남긴다.

정답 (MySQL)

WITH mu AS (
  SELECT DISTINCT user_id, DATE_FORMAT(paid_date, '%Y-%m-01') AS m FROM payments
),
g AS (
  SELECT user_id, m,
         TIMESTAMPDIFF(MONTH, '2026-01-01', m)
         - ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY m) AS grp
  FROM mu
),
runs AS (
  SELECT user_id, grp, COUNT(*) AS run_len FROM g GROUP BY user_id, grp
)
SELECT COUNT(DISTINCT user_id) AS users_with_3plus_streak
FROM runs WHERE run_len >= 3;

함정

이렇게 변형된다

“연속 출석 일수”, “N일 연속 접속” 전부 동일. 일 단위면 DATEDIFF 를 일련번호로.

← Q7. 월별 플랜 업그레이드 / 다운그레이드Q9. 채널별 결제 전환과 LTV →