🤔 문제
다음은 식당의 정보를 담은 `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;
결과
🖍 오답노트
틀린 이유
`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
[IN 개념 참고]
https://jaehwaseo.tistory.com/24
'취업준비 > 코딩테스트 문제 풀이' 카테고리의 다른 글
[프로그래머스 SQL 코딩테스트 연습] Lv3. 조건별로 분류하여 주문상태 출력하기(MySQL) (2) | 2024.07.20 |
---|---|
[프로그래머스 SQL 코딩테스트 연습] Lv3. 특정 조건을 만족하는 물고기별 수와 최대 길이 구하기 (MySQL) (0) | 2024.07.18 |
[프로그래머스 SQL 코딩테스트 연습] Lv5. 상품을 구매한 회원 비율 구하기 (MySQL) (4) | 2024.07.16 |
[프로그래머스 SQL 코딩테스트 연습] Lv4. 5월 식품들의 총매출 조회하기 (MySQL) (0) | 2024.07.10 |
[프로그래머스 SQL 코딩테스트 연습] Lv3. 대장균들의 자식의 수 구하기 (MySQL) (0) | 2024.07.08 |