[프로그래머스 SQL/131116] 식품분류별 가장 비싼 식품의 정보 조회하기

☑️ 문제

프로그래머스 131116

  • 카테고리 별 가장 비싼 상품을 가져오기

☑️ 풀이

첫 번째 풀이 (실패)

SELECT CATEGORY, PRICE AS 'MAX_PRICE', PRODUCT_NAME
FROM FOOD_PRODUCT
GROUP BY CATEGORY
HAVING CATEGORY IN ('과자', '국', '김치', '식용유')
ORDER BY PRICE DESC
  • GROUP BY 사용 시 집계 함수 없이 SELECT 절에 PRICE, PRODUCT_NAME이 쓰였기 때문에, GROUP BY 된 각 그룹에서 임의의 하나의 레코드를 가져오는 에러가 발생한다.
  • CATEGORY IN ('과자', '국', '김치', '식용유')HAVING 절이 아닌 WHERE 절에 쓰는 게 더 명확하다.
    • WHERE : 그룹화 전에 행 필터링
    • HAVING : GROUP BY 이후 그룹 필터링

두 번째 풀이 (성공)

SELECT CATEGORY, PRICE AS 'MAX_PRICE', PRODUCT_NAME
FROM FOOD_PRODUCT
WHERE (CATEGORY, PRICE) IN (
    SELECT CATEGORY, MAX(PRICE)
    FROM FOOD_PRODUCT
    WHERE CATEGORY IN ('과자', '국', '김치', '식용유')
    GROUP BY CATEGORY
    )
ORDER BY PRICE DESC
  1. 서브쿼리를 이용하여 카테고리별 최고 가격을 구한다.
  2. 메인쿼리에서는 서브 쿼리에서 구한 (CATEGORY, MAX_PRICE) 쌍을 기준으로, 원래 테이블에서 해당 상품을 찾는다.

세 번째 풀이 (성공)

SELECT CATEGORY, PRICE AS 'MAX_PRICE', PRODUCT_NAME
FROM (
    SELECT *,
    ROW_NUMBER() OVER (PARTITION BY CATEGORY ORDER BY PRICE DESC) AS RN
    FROM FOOD_PRODUCT
    WHERE CATEGORY IN ('과자', '국', '김치', '식용유')
    ) T
WHERE RN = 1
ORDER BY PRICE DESC
  1. PARTITION BY CATEGORY : 카테고리별로 데이터를 묶는다.
  2. ORDER BY PRICE DESC : 각 카테고리 안에서 가격 기준으로 내림차순 정렬을 한다.
  3. ROW_NUMBER() : 정렬된 각 그룹 내에서 순번을 매긴다. (가장 비싼 상품은 rn = 1)
  4. 외부 SELECT에서 WHERE RN = 1 : 각 카테고리에서 가장 비싼 상품 하나만 뽑는다.

☑️ 문법 정리

윈도우 함수

  • 형식

      <윈도우 함수> OVER (
          [PARTITION BY ...] 
          [ORDER BY ...] 
          [ROWS BETWEEN ...]
      )
    
    • 그룹 집계 없이도 행마다 통계 정보를 계산할 수 있는 함수
    • OVER() 절과 함께 사용하며, GROUP BY와 달리 모든 행에 결과가 유지된다.
  • 윈도우 함수 종류

    함수 이름설명
    ROW_NUMBER()정렬 기준에 따라 순번을 매김 (무조건 1,2,3…)
    RANK()동순위 허용, 다음 순위 건너뜀 (예: 1,1,3)
    DENSE_RANK()동순위 허용, 다음 순위 안 건너뜀 (예: 1,1,2)
    NTILE(N)N개의 그룹으로 나눔 (백분위 등 만들 때 사용)
    SUM()누적 합 계산 가능
    AVG()누적 평균
    MAX(), MIN()누적 최대/최소값
    LAG(), LEAD()이전/다음 행 값 참조
  • PARTITION BY
    • 데이터를 그룹으로 나누는 기준이다.
    • GROUP BY처럼 동작하지만 결과는 원래 행 개수만큼 유지된다.
    • 예시

        ROW_NUMBER() OVER (PARTITION BY CATEGORY ORDER BY PRICE DESC)
      
  • ROWS BETWEEN …
    • 누적 계산 시 사용하는 범위를 지정한다. (누적합 등에서 사용)
    • 예시

        SUM(SALES) OVER (
        	PARTITION BY YEAR
        	ORDER BY MONTH
        	ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        )
      
      • 올해 1월부터 현재 월까지의 누적 매출을 계산한다.

© 2021. All rights reserved.

yaejinkong의 블로그