22. SQL - 반복해서 틀리는 것들 (#3) consecutive days (grp, streak_days)

Jason·2026년 1월 15일

SQL

목록 보기
21/47

[SQL 코테] 연속 날짜 그룹핑 내가 틀린 것들 정리 🔥

🚨 핵심 실수 포인트 (시험 전 필독!)

1. DATE_SUB는 윈도우 함수 아님! OVER() 안 붙어!
2. DATE_SUB(날짜, INTERVAL rn DAY) ← 문법 외우기
3. grp는 그룹 키일 뿐! 연속 일수 = COUNT(*)
4. GROUP BY는 grp로! (streak_days는 결과값이라 안 됨)

📝 문제: 유저별 연속 로그인 구간 찾기

테이블 구조

logins 테이블
id  | user_id | login_date
----|---------|------------
1   | 301     | 2024-03-01
2   | 301     | 2024-03-02
3   | 301     | 2024-03-03
4   | 301     | 2024-03-07
5   | 301     | 2024-03-08
6   | 302     | 2024-03-01
7   | 302     | 2024-03-03

✅ 정답 쿼리

WITH cte_rn AS ( 
  SELECT 
    user_id, login_date, 
    ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY login_date) AS rn 
  FROM logins 
), 
cte_grp AS ( 
  SELECT 
    user_id, login_date, rn, 
    DATE_SUB(login_date, INTERVAL rn DAY) AS grp 
  FROM cte_rn 
) 
SELECT 
  user_id, 
  MIN(login_date) AS start_date, 
  MAX(login_date) AS end_date, 
  COUNT(*) AS streak_days
FROM cte_grp 
GROUP BY user_id, grp
ORDER BY user_id, start_date;

❌ 내가 틀린 것들

1. DATE_SUB는 윈도우 함수가 아니야!

-- ❌ OVER() 붙이면 안 돼!
DATE_SUB((login_date, rn) OVER(PARTITION BY user_id ORDER BY login_date))

-- ✅ 그냥 일반 함수
DATE_SUB(login_date, INTERVAL rn DAY)

기억: DATE_SUB, DATEDIFF는 일반 함수! OVER() 안 붙어!


2. DATE_SUB 문법 구조

DATE_SUB(날짜, INTERVAL 숫자 단위)
부분의미
DATE_SUB(A, B)A에서 B를 빼라
login_date기준 날짜
INTERVAL rn DAYrn일 만큼

예시:

DATE_SUB('2024-03-03', INTERVAL 3 DAY) = '2024-02-29'

3. grp vs COUNT(*) 구분!

-- ❌ grp는 그룹 키일 뿐, 연속 일수 아님
grp AS streak_days

-- ✅ 행 갯수 = 연속 일수
COUNT(*) AS streak_days

grp 값 확인 (rn 포함 전체 과정):

user_id | login_date | rn | grp (login_date - rn일)
--------|------------|----|--------------------------
301     | 2024-03-01 | 1  | 2024-03-01 - 1일 = 2024-02-29  ←┐
301     | 2024-03-02 | 2  | 2024-03-02 - 2일 = 2024-02-29  ←┼ 같은 grp!
301     | 2024-03-03 | 3  | 2024-03-03 - 3일 = 2024-02-29  ←┘
301     | 2024-03-07 | 4  | 2024-03-07 - 4일 = 2024-03-03  ←┐
301     | 2024-03-08 | 5  | 2024-03-08 - 5일 = 2024-03-03  ←┘

왜 연속이면 grp가 같아지냐?

  • 연속된 날짜: 날짜 +1, rn도 +1 → 빼면 같은 값!
  • 끊긴 날짜: 날짜 +4 (03-03 → 03-07), rn은 +1 → 빼면 다른 값!

grp = '02-29'는 "이 행들이 같은 그룹이다"라는 표식일 뿐! 날짜 자체는 의미 없어!


5. grp vs streak_days 구분!

구분grpstreak_days
뭐야?그룹 키 (표식)연속 일수 (결과)
어떻게?DATE_SUB(date, INTERVAL rn DAY)COUNT(*)
역할연속인 행들 묶기용실제 며칠인지
의미값 자체는 의미 없음우리가 원하는 답!

비유:

  • grp = 같은 반 학생들한테 붙이는 반 번호 (1반, 2반...)
  • streak_days = 그 반에 학생이 몇 명인지

4. GROUP BY는 grp로!

-- ❌ streak_days는 SELECT에서 만든 결과값
GROUP BY user_id, streak_days

-- ✅ grp로 묶어야 연속 구간끼리 그룹됨
GROUP BY user_id, grp

흐름:

1. grp로 GROUP BY → 연속 구간끼리 묶임
2. 묶인 그룹 안에서 COUNT(*) → streak_days 계산됨

💡 DATE_SUB vs DATEDIFF 비교

함수하는 일결과 타입
DATE_SUB(날짜, INTERVAL n DAY)날짜 - n일DATE
DATEDIFF(날짜1, 날짜2)날짜 차이 계산INT (정수)
DATE_SUB('2024-03-03', INTERVAL 3 DAY)'2024-02-29' (날짜)
DATEDIFF('2024-03-03', '2024-03-01')2 (숫자)

🎯 체크리스트

  • DATE_SUB에 OVER() 붙이지 않기
  • DATE_SUB(날짜, INTERVAL rn DAY) 문법
  • 연속 일수 = COUNT(*) (grp 아님!)
  • GROUP BY는 grp로

채널톡 DA 인턴 코테 준비 중 정리한 내용입니다 🚀

profile
Data Analyst | Thoughts Become Things. 할 수 있다고 생각하면 할 수 있다. 할 수 없다고 생각하면 할 수 없다. | www.linkedin.com/in/명수-제-7ab843200

0개의 댓글