[SQL문제풀기] 미세먼지 수치의 계절간 차이

silver's avatar
Mar 17, 2025
[SQL문제풀기] 미세먼지 수치의 계절간 차이

문제

SQLite

내가 작성한 정답 1 - row_number()

: row_number로 순번을 구한 후 중간순번에 해당하는 중간값을 가져왔다.
with a as ( select case when strftime ('%m', measured_at) in ('03', '04', '05') then 'spring' when strftime ('%m', measured_at) in ('06', '07', '08') then 'summer' when strftime ('%m', measured_at) in ('09', '10', '11') then 'autumn' else 'winter' end season, pm10 from measurements ), b as ( select season, count(*) cnt, round(avg(pm10),2) pm10_average from a group by season order by pm10 ) select b.season, c.pm10 pm10_median, b.pm10_average from b b join (select row_number() over(partition by a.season order by a.pm10) ranking,a.season,a.pm10 from b b join a a on b.season = a.season) c on b.season = c.season and (cnt+1)/2 = ranking
💡
ROW_NUMBER() OVER
: 결과 집합의 각 행에 대해 고유한 순번을 부여한다. 이 함수는 주로 데이터의 순서를 매기거나 특정 조건에 따라 그룹화된 데이터 내에서 행 번호를 생성하는 데 사용된다.
  • PARTITION BY: 이 절은 결과 집합을 특정 열의 값에 따라 그룹화한다. 각 그룹 내에서 ROW_NUMBER()가 다시 1부터 시작한다. 이 절은 선택 사항!
  • ORDER BY: 이 절은 각 그룹 내에서 행 번호를 매길 순서를 지정합니다. 이 절은 필수!
ROW_NUMBER() OVER (PARTITION BY column_name ORDER BY column_name) // 아래의 쿼리는 각 부서(department_id) 내에서 직원(employee_id)에 대해 순번을 매긴다. // 각 부서의 첫 번째 직원은 row_num이 1이 되고, 두 번째 직원은 2가 된다. SELECT employee_id, department_id, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY employee_id) AS row_num FROM employees;
  • ORDER BY 절에서 지정한 열의 값이 동일한 여러 행이 존재한다면, ROW_NUMBER()는 이들 행에 대해 각각 다른 번호를 부여한다. 즉, 동일한 값이 있는 행이라도 순서에 따라 번호가 다르게 매겨진다.

내가 작성한 정답 2 - PERCENT_RANK()

: percent_rank()로 퍼센트 비율을 구한 후 중간퍼센트인 0.5에 해당하는 중간값을 가져왔다. 이 때 계절별로 데이터가 홀수개라면 0.5가 정확히 나올 수 없으므로 ceiling으로 올림을 해서 가져온다. 올림을 할 때 소수점 첫째자리까지 나오면 0.55같은 경우는 올림이 제대로 되지 않고 소수점 둘째짜리까지 나오면 데이터가 홀수인 것들은 정확히 0.5가 될 수 없으므로 or 조건으로 두가지 경우를 가져와 max로 최대값을 출력한다.
with a as ( select case when strftime ('%m', measured_at) in ('03', '04', '05') then 'spring' when strftime ('%m', measured_at) in ('06', '07', '08') then 'summer' when strftime ('%m', measured_at) in ('09', '10', '11') then 'autumn' else 'winter' end season, pm10 from measurements ), b as ( select season, round(avg(pm10),2) pm10_average from a group by season order by pm10 ) select b.season, max(c.pm10) pm10_median, b.pm10_average from b b join (select percent_rank() over(partition by a.season order by a.pm10) ranking,a.season,a.pm10 from b b join a a on b.season = a.season) c on b.season = c.season where (ceiling(c.ranking*100))*0.01 = 0.5 or (ceiling(c.ranking*10))*0.1 = 0.5 group by b.season
💡
PERCENT_RANK() : 함수는 SQL에서 사용되는 윈도우 함수 중 하나로, 특정 행의 순위를 백분율로 계산한다. 이 함수는 주어진 집합 내에서 각 행의 상대적 위치를 나타내며, 0에서 1 사이의 값을 반환한다.
PERCENT_RANK() OVER (PARTITION BY partition_expression ORDER BY order_expression)

다른 사람들이 작성한 정답

SELECT CASE WHEN substr(measured_at, 6, 2) IN ('03', '04', '05') THEN 'spring' WHEN substr(measured_at, 6, 2) IN ('06', '07', '08') THEN 'summer' WHEN substr(measured_at, 6, 2) IN ('09', '10', '11') THEN 'autumn' ELSE 'winter' END season, median(pm10) pm10_median, round(avg(pm10), 2) pm10_average FROM measurements GROUP BY 1;
💡
median()함수를 사용한다면 중간값을 쉽게 구할 수 있다.

Oracle

SELECT season, ROUND(AVG(pm10), 2) AS pm10_average, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY pm10) AS pm10_median FROM ( SELECT CASE WHEN TO_CHAR(TO_DATE(date, 'YYYY-MM-DD'), 'MM') BETWEEN '03' AND '05' THEN 'spring' WHEN TO_CHAR(TO_DATE(date, 'YYYY-MM-DD'), 'MM') BETWEEN '06' AND '08' THEN 'summer' WHEN TO_CHAR(TO_DATE(date, 'YYYY-MM-DD'), 'MM') BETWEEN '09' AND '11' THEN 'autumn' ELSE 'winter' END AS season, pm10 FROM measurements ) GROUP BY season;
💡
oracle에서는 PERCENTILE_CONT(0.5) WITHIN GROUP을 사용하여 중앙값을 쉽게 구할 수 있다.
median()함수도 바로 사용가능하다
 
Share article

silver