[SQL] 131116 식품분류별 가장 비싼 식품의 정보 조회하기
https://school.programmers.co.kr/learn/courses/30/lessons/131116
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;