[solvesql_Lv3] 미세먼지 수치의 계절간 차이(중앙값구하기)

2025. 10. 14. 12:02·코딩 테스트/02. SQL

1. 문제 설명

데이터를 활용해 봄, 여름, 가을, 겨울 계절 별로 미세먼지의 농도에 차이가 있는지 알아보고싶다

 

조건 1)  제시된 시기별로 계절의 명칭을 붙이기

조건 2)  계절별 미세먼지 농도의 중앙값과 평균을 구하기

조건 3)  PM10 농도의 평균값은 소숫점 셋째 자리에서 반올림 해 소수점 둘째자리까지 표시

2. 풀이

WITH base AS (
  SELECT
    pm10,
    CASE
      WHEN DATE(measured_at) BETWEEN '2022-03-01' AND '2022-05-31' THEN 'spring'
      WHEN DATE(measured_at) BETWEEN '2022-06-01' AND '2022-08-31' THEN 'summer'
      WHEN DATE(measured_at) BETWEEN '2022-09-01' AND '2022-11-30' THEN 'autumn'
      ELSE 'winter'
    END AS season
  FROM measurements
),
ranked AS (
  SELECT
    season, pm10,
    ROW_NUMBER() OVER (PARTITION BY season ORDER BY pm10) AS rn,
    COUNT(*)    OVER (PARTITION BY season)                AS cnt
  FROM base
)
SELECT
  season,
  ROUND(AVG(pm10),2) AS pm10_average,
  AVG(CASE WHEN rn IN (FLOOR((cnt+1)/2), CEIL((cnt+1)/2)) THEN pm10 END) AS pm10_median
FROM ranked
GROUP BY season
ORDER BY season;

3. 중앙값 구하기

이 문제는 전체 구조는 단순한데 중앙값을 구하는 로직이 핵심 포인트였습니다.

MySQL에 내장 함수가 없어서 직접 구현해야하기때문이죠!

 

1) BASE 테이블에 계절 컬럼 붙이기 : 분류 라벨링 완료

2) ROW_NUMBER() 함수로 계절별 정렬 순번 부여

3)  COUNT(*)    OVER (PARTITION BY season) : 같은 계정 그룹의 총개수를 모든 행에 붙임.

4) 본격 중앙값 구하기

 AVG(CASE WHEN rn IN (FLOOR((cnt+1)/2), CEIL((cnt+1)/2)) THEN pm10 END)
  • rn = 정렬된 순서 번호
  • cnt = 그 계절에 속한 전체 데이터 개수
상황 선택되는 rn 이유 평균 결과
홀수 개수 딱 1개 (가운데 값) (cnt+1)/2의 floor와 ceil이 같아서 그 값 자체가 중앙값
짝수 개수 2개 (가운데 두 값) floor와 ceil이 서로 달라서 두 값의 평균이 중앙값

예시로 확실하게 이해하기 

+ ) rn IN (...)을 쓴 이유 
-> 짝수 개수일 때 가운데 두 값(rn 두 개) 을 둘 다 포함하기 위해서!
상황 FLOOR((cnt+1)/2) CEIL((cnt+1)/2) rn IN (...) 결과
홀수 (cnt=5) 3 3 rn IN (3,3) → 결국 rn=3 하나만 선택
짝수 (cnt=6) 3 4 rn IN (3,4) → rn=3과 rn=4 두 행 선택

즉,

  • IN은 다중 값을 비교하는 연산자라
    • 홀수일 때는 하나만 선택
    • 짝수일 때는 두 개를 모두 선택
  • AVG()가 그 두 값을 자동으로 평균 내니까 중앙값이 완성

4.  집계 함수도 윈도우 함수로 사용 가능

MySQL 8.0 이후부터는 집계 함수 대부분이 윈도우 함수로도 사용 가능합니다.

SUM(), AVG(), COUNT(), MIN(), MAX() 같은 집계 함수를

OVER() 구문과 함께 쓰면 → 윈도우 함수로 변신합니다.

 

즉 👇

  • COUNT() → 전체나 파티션 내 행 개수 세기
  • SUM() → 누적합
  • AVG() → 누적평균
  • MIN() / MAX() → 구간별 최솟값·최댓값

예시

더보기
SELECT
  department,
  employee,
  salary,
  COUNT(*) OVER (PARTITION BY department) AS cnt_by_dept,
  AVG(salary) OVER (PARTITION BY department) AS avg_by_dept
FROM employees;

 


department employee salary cnt_by_dept avg_by_dept
HR Alice 4000 2 4500
HR Bob 5000 2 4500
IT Carol 7000 3 7333
IT Dan 8000 3 7333
IT Emma 7000 3 7333

➡️ 여기서 COUNT()는 GROUP BY처럼 한 줄로 요약하지 않고,
각 행마다 “해당 그룹 안의 개수”를 표시합니다. 이게 바로 윈도우 함수의 장점이죠.

 

'코딩 테스트 > 02. SQL' 카테고리의 다른 글

(solvesql) Advent of SQL 2025 6일차  (0) 2025.12.08
(solvesql) Advent of SQL 2025 5일차  (0) 2025.12.08
[solvesql_Lv3]멘토링 짝꿍 리스트(JOIN에서 ON의 특징)  (2) 2025.10.14
[solvesql_Lv3] 작품이 없는 작가 찾기  (0) 2025.10.13
[solvesql]MySQL_2(Lv2)  (1) 2025.10.12
'코딩 테스트/02. SQL' 카테고리의 다른 글
  • (solvesql) Advent of SQL 2025 6일차
  • (solvesql) Advent of SQL 2025 5일차
  • [solvesql_Lv3]멘토링 짝꿍 리스트(JOIN에서 ON의 특징)
  • [solvesql_Lv3] 작품이 없는 작가 찾기
Growth DA Log
Growth DA Log
Growth DA Log 님의 블로그 입니다.
  • Growth DA Log
    Growth DA Log님의 블로그
    Growth DA Log
  • 전체
    오늘
    어제
    • 분류 전체보기 (125)
      • TIS_COMPANY (6)
      • 코딩 테스트 (61)
        • 01. Python (3)
        • 02. SQL (58)
      • 데이터 분석 (53)
        • 01. BigQuery (9)
        • 02. GA4 (1)
        • 02-1. GA4를 더 잘 다루기 위한 마케팅 개.. (5)
        • 03. streamlit (5)
        • 04. Git (12)
        • 05. 데이터 엔지니어링 (3)
        • 06. 데이터 모델링 (11)
        • 07. Excel (0)
        • 08. Tableau (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    rank
    cross_join
    streamlit
    프로그래머스
    윈도우함수
    SQL
    solvesql
    revert
    git
    코드잇스프린트후기
    tableaubootcamp
    이행성
    tableau
    ROW_NUMBER
    DENSE_RANK
    Reset
    AARRR
    코테
    쿼리테스트
    코딩테스트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
Growth DA Log
[solvesql_Lv3] 미세먼지 수치의 계절간 차이(중앙값구하기)
상단으로

티스토리툴바