데일리
[23.11.04] LEFT JOIN과 WHERE IS NULL을 활용한 그룹 별 최상단행 뽑기
paikpaik
2023. 11. 4. 18:33
글의 목적
- 서브쿼리를 사용하면 성능상으로 문제가 있어서 JOIN으로 해결해야할 경우
- 문제가 그룹별 최상단 1개의 행만 뽑으면 되는 경우
- LEFT JOIN과 WHERE IS NULL을 활용하여 해결하는 방법은 기록해두면 좋을 것 같아서
- 단 그룹당 2개의 행을 뽑으려면 이 방법으로는 안됨.
본론
Column name | Type | Nullable |
REST_ID | VARCHAR(5) | FALSE |
REST_NAME | VARCHAR(50) | FALSE |
FOOD_TYPE | VARCHAR(20) | TRUE |
VIEWS | NUMBER | TRUE |
FAVORITES | NUMBER | TRUE |
PARKING_LOT | VARCHAR(1) | TRUE |
ADDRESS | VARCHAR(100) | TRUE |
TEL | VARCHAR(100) | TRUE |
- 대충 위와 같은 식당정보를 담은 REST_INFO 테이블이 있다고 하자
- REST_INFO 테이블에서 음식 종류별 내림차순으로 FAVORITES 수가 가장 많은 식당의 종류, ID, 이름과 FAVORITES의 수를 출력하라고 할 때
- SUBQUERY가 아닌 LEFT JOIN과 WHERE IS NULL로 해결하는 방법을 알아보려고 한다.
- 우선 LEFT JOIN을 이해해야 한다. 모르면 이해하고 이 글을 다시 보자.
SELECT R1.FOOD_TYPE, R1.REST_ID, R1.REST_NAME, R1.FAVORITES
FROM REST_INFO R1
LEFT JOIN REST_INFO R2
ON R1.FAVORITES < R2.FAVORITES AND
R1.FOOD_TYPE = R2.FOOD_TYPE
WHERE R2.REST_ID IS NULL
ORDER BY FOOD_TYPE DESC
- 여기서 핵심은 하나의 테이블로 LEFT JOIN을 진행했고 ON으로 최상단 값을 제거한 다음
- 그렇게 제거된 부분을 WHRER IS NULL로 가져오는 방법이다.
- 단점은 목적에서도 말했듯이 그룹별 2개는 못가져 온다.
- 아래는 응용 ( 프로그래머스 - 식품분류별 가장 비싼 식품의 정보 조회하기 - lv4 문제)
SELECT F1.CATEGORY, F1.PRICE AS MAX_PRICE, F1.PRODUCT_NAME
FROM FOOD_PRODUCT F1 LEFT JOIN FOOD_PRODUCT F2
ON F1.PRICE < F2.PRICE AND
F1.CATEGORY = F2.CATEGORY
WHERE F2.PRODUCT_ID IS NULL AND
F1.CATEGORY IN ('과자', '국', '김치', '식용유')
ORDER BY MAX_PRICE DESC
결론
- 그룹별 1등만 뽑아야 할 경우 사용하면 성능적으로 약간 좋아진다.
- 되도록이면 서브쿼리보단 JOIN을 활용하려고 한다면 알아두자!