3일 이상 연속 상승 구간 모두 찾기

난이도 어려움 · 권장 22분 · 출력 컬럼 stock_code, streak_start_date, streak_end_date, streak_days
이 문제 직접 풀어보기 →

문제

stock_daily_prices 에서 종목별로 '3일 이상 연속 상승한 구간' 을 모두 찾으세요. stock_code streak_start_date 그 구간의 첫 상승일 streak_end_date 그 구간의 마지막 상승일 streak_days 그 구간의 연속 상승 일수 · 상승일 = 전 거래일 종가보다 당일 종가가 '더 높은' 날 (같으면 상승이 아닙니다). · 전 거래일은 하루 전이 아니라 그 종목의 데이터상 바로 앞 행입니다. · streak_days 는 상승일의 개수입니다. 상승이 시작되기 전 날은 세지 않습니다. · 구간이 3일 미만이면 출력하지 않습니다. · stock_code 오름차순, 같으면 streak_start_date 오름차순으로 정렬하세요.
정렬 stock_code ASC, streak_start_date ASC

쉽게 설명하면

Q8 출석 도장 트릭 + 어제와 비교. 두 개를 겹쳐 쓰는 문제다. 이게 풀리면 시계열 문제는 거의 다 풀린다.

줄번호날종가어제올랐나오른날 줄번호차이
11일100--
22일110100O11
33일120110O21
44일130120O31
55일125130X
66일130125O42

차이 1 이 세 개 → 2일~4일이 한 덩어리(3일 연속). 6일은 차이가 2 라서 다른 덩어리.

이렇게 푼다

  1. 전체 줄에 먼저 번호를 매기고, 어제 종가도 같이 끌어온다.
  2. 오른 날만 남긴다 (오늘 > 어제).
  3. 남은 것에 번호를 새로 매기고, (전체 줄번호 − 새 번호).
  4. 그 값으로 묶어서 시작일·끝일·개수, 3 이상만.

이것만 피하면 된다

자세히

묻는 것 · LAG 로 상승일을 가리고, 그 위에 gaps and islands 를 한 번 더 얹는다. 두 패턴을 포개는 문제. 이게 풀리면 시계열 문제는 거의 다 풀린다.

풀이 순서

  1. 먼저 모든 행에 행 번호를 매긴다: ROW_NUMBER() OVER (PARTITION BY stock_code ORDER BY trade_date) AS rn. 이게 '몇 번째 거래일인가' 다. 날짜가 아니라 이 번호가 기준이 된다.
  2. 같은 단에서 LAG(close_price) OVER (PARTITION BY stock_code ORDER BY trade_date) 로 전 거래일 종가를 끌어온다.
  3. WHERE prev IS NOT NULL AND close_price > prev 로 상승일만 남긴다.
  4. 남은 상승일에 새로 행 번호를 매기고 rn − 새 행번호 → 연속 상승 구간마다 같은 값.
  5. 그 값으로 묶어 MIN/MAX/COUNT, HAVING COUNT(*) >= 3.

정답 (MySQL)

WITH p AS (
  SELECT stock_code, trade_date, close_price,
         ROW_NUMBER() OVER (PARTITION BY stock_code ORDER BY trade_date) AS rn,
         LAG(close_price) OVER (PARTITION BY stock_code ORDER BY trade_date) AS prev
  FROM stock_daily_prices
),
u AS (
  SELECT stock_code, trade_date,
         rn - ROW_NUMBER() OVER (PARTITION BY stock_code ORDER BY trade_date) AS grp
  FROM p
  WHERE prev IS NOT NULL AND close_price > prev
)
SELECT stock_code,
       MIN(trade_date) AS streak_start_date,
       MAX(trade_date) AS streak_end_date,
       COUNT(*) AS streak_days
FROM u
GROUP BY stock_code, grp
HAVING COUNT(*) >= 3
ORDER BY stock_code, streak_start_date;

함정

이렇게 변형된다

“N일 연속 하락”이면 부등호만 뒤집는다. “최장 구간 하나만”이면 마지막에 ROW_NUMBER() OVER (PARTITION BY stock_code ORDER BY COUNT(*) DESC) 로 1등만. “연속 상승률”이면 구간 양 끝 종가가 필요하므로 FIRST_VALUE/LAST_VALUE 를 쓰거나 시작일 하루 전 종가를 따로 끌어온다.

← Q16. A/B 테스트 그룹 집계 (상위 1% 제외)Q18. 채널별 ARPU 와 ARPPU →