[프로그래머스 SQL 코딩테스트 연습] Lv3. 즐겨찾기가 가장 많은 식당 정보 출력 (MySQL)
🤔 문제
다음은 식당의 정보를 담은 `REST_INFO` 테이블입니다. `REST_INFO` 테이블은 다음과 같으며 `REST_ID`, `REST_NAME`, `FOOD_TYPE`, `VIEWS`, `FAVORITES`, `PARKING_LOT`, `ADDRESS`, `TEL`은 식당 ID, 식당 이름, 음식 종류, 조회수, 즐겨찾기수, 주차장 유무, 주소, 전화번호를 의미합니다.
`REST_INFO` 테이블에서 음식종류별로 즐겨찾기수가 가장 많은 식당의 음식 종류, ID, 식당 이름, 즐겨찾기수를 조회하는 SQL문을 작성해주세요. 이때 결과는 음식 종류를 기준으로 내림차순 정렬해주세요.
예시
`REST_INFO` 테이블이 다음과 같을 때
SQL을 실행하면 다음과 같이 출력되어야 합니다.
💻 나의 풀이
WITH MOSTFAV AS(
SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
FROM REST_INFO
GROUP BY FOOD_TYPE
ORDER BY FAVORITES DESC
)
SELECT *
FROM MOSTFAV
ORDER BY FOOD_TYPE DESC;
결과
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/040.gif)
🖍 오답노트
틀린 이유
`GROUP BY`는 그룹화된 각 그룹에서 하나의 행을 반환하는 데,
`FAVORITES`를 기준으로 정렬하여 가장 많은 즐겨찾기를 가진 식당을 얻으려면 서브쿼리와 윈도우 함수를 사용해야 한다.
정답 풀이
1. 서브쿼리 내에서 MAX()로 최댓값을 찾는 풀이
SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
FROM REST_INFO
WHERE (FOOD_TYPE, FAVORITES) IN (SELECT FOOD_TYPE, MAX(FAVORITES)
FROM REST_INFO
GROUP BY FOOD_TYPE)
ORDER BY 1 DESC;
- `WHERE (FOOD_TYPE, FAVORITES) IN ()`
괄호 안을 만족하는 테이블을 돌면서 음식 종류와 즐겨찾기수를 비교하여 최다 즐겨찾기수와 해당하는 식당의 음식 종류를 필터링한다. 이때, 음식 종류와 즐겨찾기수가 (가리키는 식당이)같아야 하기 때문에 `(FOOD_TYPE, FAVORITES)`로 묶어준다. - 서브쿼리
음식 종류별로 최다 즐겨찾기수를 구하기 위해 `GROUP BY FOOD_TYPE`로 그룹핑한 후, `MAX(FAVORITES)`로 최댓값을 따로 찾아준다.
2. 윈도우 함수를 사용해서 음식 종류별 순위를 매기는 풀이
-- 음식 종류별 즐겨찾기수 기준으로 내림차순 정렬하여 순위를 매긴 테이블 생성
WITH RANKED_RESTS AS (
SELECT
REST_ID,
REST_NAME,
FOOD_TYPE,
FAVORITES,
ROW_NUMBER() OVER (PARTITION BY FOOD_TYPE ORDER BY FAVORITES DESC) AS RNK
FROM REST_INFO
)
SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
FROM RANKED_RESTS
WHERE RNK = 1
ORDER BY 1 DESC;
- CTE `RANKED_RESTS`
음식 종류별 즐겨찾기수 기준으로 내림차순 정렬하여 각 식당에 대한 순위를 매긴 테이블을 생성한다.- 윈도우 함수`ROW_NUMBER()` : `FOOD_TYPE`별로 즐겨찾기 수가 많은 순서대로 각 행에 번호를 매기는데,
- `PARTITION BY FOOD_TYPE` : 음식 종류별로 파티션을 나누고,
- `ORDER BY FAVORITES DESC` : 각 파티션 내에서 즐겨찾기수가 많은 순서대로 내림차순 정렬한다.
- 메인쿼리
- `RNK = 1` : 각 음식 종류별로 즐겨찾기 수가 가장 많은 식당(순위가 1번째인)을 선택한다.
✅ 핵심 정리
1. GROUP BY
`GROUP BY`로 그룹핑하면, 그룹 내에서 가장 상단에 있는 데이터들을 임의로 가져온다.
그래서 위의 문제에서 `GROUP BY FOOD_TYPE`후 그냥 `MAX(FAVORITES)`를 하게 되면, 음식 종류별 즐겨찾기수 최댓값이 아니라, 음식 종류별로 묶은 그룹 테이블 내 임의의 최상단 값을 조회하기 때문에 오답처리된다.
► 따라서 서브 쿼리를 생성하여 그 안에서 그룹핑하고 즐겨찾기수에 대한 최댓값을 따로 찾아줘야한다.
2. IN
: 값 리스트에 포함된 값을 검사하기 때문에 여러 행과 컬럼을 동시에 비교할 수 있다.
서브 쿼리를 생성했을 때, 다중 조건을 동시에 만족하기 위해서는 아래와 같이 쿼리를 작성해야 한다.
SELECT 컬럼명
FROM 테이블명
WHERE (컬럼명1, 컬럼명2, ..) IN (SELECT 서브쿼리_컬럼명1, 서브쿼리_컬럼명2, ..
FROM 서브쿼리_테이블명);
※ `=` 연산자
단일 값과의 비교에 사용되기 때문에 위와 같은 여러 컬럼을 동시에 비교하고자 할 때에는 `IN`을 사용해야 한다.
🔗 References
[풀이1 참고]
https://school.programmers.co.kr/questions/38854
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
[IN 개념 참고]
https://jaehwaseo.tistory.com/24
프로그래머스 즐겨찾기가 가장 많은 식당 정보 출력하기 SQL(MySQL)
문제 다음은 식당의 정보를 담은 REST_INFO 테이블입니다. REST_INFO 테이블은 다음과 같으며 REST_ID, REST_NAME, FOOD_TYPE, VIEWS, FAVORITES, PARKING_LOT, ADDRESS, TEL은 식당 ID, 식당 이름, 음식 종류, 조회수, 즐겨찾
jaehwaseo.tistory.com