데일리

[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을 활용하려고 한다면 알아두자!