Skip to main content

[SQL] 131116 식품분류별 가장 비싼 식품의 정보 조회하기

https://school.programmers.co.kr/learn/courses/30/lessons/131116

image.png

image.png

1. 문제

테이블

  • FOOD_PRODUCT(PRODUCT_ID, PRODUCT_NAME, PRODUCT_CD, CATEGORY, PRICE)

요구사항

  • CATEGORY 별로 가장 비싼 상품 찾기

출력 컬럼

  • CATEGORY, MAX_PRICE, PRODUCT_NAME
  • CATEGORY가 '과자', '국', '김치', '식용유'인 것만

정렬

  • MAX_PRICE 기준 내림차순

2. 오답쿼리

-- 코드를 입력하세요
SELECT CATEGORY, MAX(PRICE) AS MAX_PRICE, PRODUCT_NAME
FROM FOOD_PRODUCT
WHERE CATEGORY IN ('과자', '국', '김치', '식용유')
GROUP BY CATEGORY
HAVING MAX(PRICE)
ORDER BY MAX_PRICE DESC;

틀린이유

1. GROUP BY + MAX(PRICE) 문제

MAX(PRICE)는 그룹별 최댓값만 주는데, PRODUCT_NAME은 GROUP BY에 없으니까 어떤 이름을 보여줘야 할 지 DB가 모른다. 그래서 그룹의 최대 가격을 가진 상품의 이름을 제대로 뽑아오지 못한다.

2. HAVING MAX(PRICE)

HAVING은 조건절인데 MAX(PRICE)만 쓰면 조건이 의미 없다.
HAVING 뒤에는 반드시 TRUE/FALSE를 반환하는 조건이 있어야 한다.

-- ❌ 틀린 예
GROUP BY CATEGORY
HAVING MAX(PRICE)

→ MAX(PRICE)는 숫자, 조건이 아니어서 오류


HAVING 올바른 사용 예

-- 예: 각 카테고리에서 최대가격이 1000 이상인 그룹만
GROUP BY CATEGORY
HAVING MAX(PRICE) >= 1000

즉, HAVING은 '이 그룹이 조건을 만족하는가?'를 평가하는 용도로만 쓰임


여기서 PRODUCT_NAME이랑 같이 못 쓰는 이유는?

SELECT CATEGORY, MAX(PRICE), PRODUCT_NAME
FROM FOOD_PRODUCT
GROUP BY CATEGORY
  • MAX(PRICE)는 그룹 단위 숫자지만, PRODUCT_NAME은 여러 값 중 어떤 걸 써야 할 지 모름
  • 그래서 오류 발생 → DB는 '어느 PRODUCT_NAME 보여줘야 하지? 하고 막힘

결론

1. HAVING 뒤에는 조건식만 가능 (TRUE/FALSE)
2. 단순히 MAX(PRICE)만 쓰면 조건이 없어서 안 됨
3. GROUP BY에서 집계 외 컬럼을 바로 쓰려면 그룹 내에서 최대값 행을 찾는 서브쿼리나 윈도우 함수 사용하기

3. 정답쿼리

카테고리별 최고가 상품 가져올 때는 서브쿼리나 윈도우 함수를 써야 한다.

방법 1: 서브쿼리

SELECT CATEGORY, PRICE, PRODUCT_NAME
FROM FOOD_PRODUCT
WHERE CATEGORY IN ('과자', '국', '김치', '식용유')
  AND PRICE = (
      SELECT MAX(PRICE)
      FROM FOOD_PRODUCT f2
      WHERE f2.CATEGORY = FOOD_PRODUCT.CATEGORY
  )
ORDER BY PRICE DESC;

방법 2: 윈도우 함수

SELECT CATEGORY, PRICE, PRODUCT_NAME
FROM (
    SELECT CATEGORY, PRICE, PRODUCT_NAME,
           RANK() OVER (PARTITION BY CATEGORY ORDER BY PRICE DESC) AS rnk
    FROM FOOD_PRODUCT
    WHERE CATEGORY IN ('과자', '국', '김치', '식용유')
) t
WHERE rnk = 1
ORDER BY PRICE DESC;

4. 추가 정리

SQL의 실행순서와 ALIAS

처음에 아래와 같이 서브쿼리 작성해서 오답처리 됨

-- 코드를 입력하세요
SELECT CATEGORY, MAX_PRICE, PRODUCT_NAME
FROM FOOD_PRODUCT
WHERE CATEGORY IN ('과자', '국', '김치', '식용유')
    AND MAX_PRICE = (
        SELECT MAX(PRICE)
        FROM FOOD_PRODUCT f2
        WHERE f2.CATEGORY = FOOD_PRODUCT.CATEGORY
    )
ORDER BY MAX_PRICE DESC;

틀린 이유

AND PRICE = MAX_PRICE

MAX_PRICE는 별칭(ALIAS)이다. WHERE에서는 SELECT에서 정의한 별칭을 사용할 수 없다.

  • SQL 실행순서
    • FROM
    • WHERE
    • GROUP BY
    • HAVING
    • SELECT - 별칭
    • ORDER BY
  • 별칭은 SELECT 이후에 인식되므로, SELECT보다 먼저 실행되는 WHERE 절에서는 참조 불가하다.
  • 즉, WHERE 절은 SELECT에서 정의한 ALIAS를 아직 모르는 시점에 실행되기 때문에 DB는 MAX_PRICE가 뭔지 모른다.
  • 따라서 아래와 같이 서브 쿼리 안에서 MAX() 함수 처리 후 SELECT 절에서 PRICE를 MAX_PRICE로 별칭을 줘서 해결했다.
-- 코드를 입력하세요
SELECT CATEGORY, PRICE AS MAX_PRICE, PRODUCT_NAME
FROM FOOD_PRODUCT
WHERE CATEGORY IN ('과자', '국', '김치', '식용유')
    AND PRICE = (
        SELECT MAX(PRICE)
        FROM FOOD_PRODUCT f2
        WHERE f2.CATEGORY = FOOD_PRODUCT.CATEGORY
    )
ORDER BY MAX_PRICE DESC;