
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;
-- ❌ 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() 안 붙어!
DATE_SUB(날짜, INTERVAL 숫자 단위)
| 부분 | 의미 |
|---|---|
DATE_SUB(A, B) | A에서 B를 빼라 |
login_date | 기준 날짜 |
INTERVAL rn DAY | rn일 만큼 |
예시:
DATE_SUB('2024-03-03', INTERVAL 3 DAY) = '2024-02-29'
-- ❌ grp는 그룹 키일 뿐, 연속 일수 아님
grp AS streak_days
-- ✅ 행 갯수 = 연속 일수
COUNT(*) AS streak_days
grp 값 확인:
user_id | login_date | rn | grp
--------|------------|----|-----------
301 | 03-01 | 1 | 02-29 ←┐
301 | 03-02 | 2 | 02-29 ←┼ 같은 값 = 연속!
301 | 03-03 | 3 | 02-29 ←┘
301 | 03-07 | 4 | 03-03 ←┐
301 | 03-08 | 5 | 03-03 ←┘
grp = '02-29'는 "이 행들이 같은 그룹이다"라는 표식일 뿐! 날짜 자체는 의미 없어!
-- ❌ 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(날짜, 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 (숫자)
채널톡 DA 인턴 코테 준비 중 정리한 내용입니다 🚀
