2024-04-18 [SQL PROGRAMMER 문제 풀이]
CASE (그룹별 조건에 맞는 식당 목록 출력하기)
고객의 정보를 담은 [MEMBER_PROFILE] 테이블과
식당의 리뷰 정보를 담은 [REST_REVIEW] 테이블입니다.
[MEMBER_PROFILE] 테이블은 다음과 같고,
(MEMBER_ID), (MEMBER_NAME), (TLNO), (GENDER), (DATE_OF_BIRTH)는
회원 ID, 회원 이름, 회원 연락처, 성별, 생년월일을 의미합니다.

REST_REVIEW 테이블은 다음과 같으며,
(REVIEW_ID), (REST_ID), (MEMBER_ID), (REVIEW_SCORE), (REVIEW_TEXT), (REVIEW_DATE)는 각각
리뷰 ID, 식당 ID, 회원 ID, 점수, 리뷰 텍스트, 리뷰 작성일을 의미합니다.

문제
리뷰를 가장 많이 작성한 회원의 리뷰들을 조회
(회원 이름), (리뷰 텍스트), (리뷰 작성일) 출력
결과는 리뷰 작성일을 기준으로 오름차순, 리뷰 작성일이 같다면 리뷰 텍스트를 기준으로 오름차순 정렬
1. 풀이 및 해설 (SubQuery / LIMIT)
처음 아래와 같이 쿼리를 작성해보았다.
SELECT MEMBER_NAME,
REVIEW_TEXT,
DATE_FORMAT (REVIEW_DATE,'%Y-%m-%d') DATE_FORMAT
FROM MEMBER_PROFILE M JOIN REST_REVIEW R USING (MEMBER_ID)
WHERE R.MEMBER_ID = (SELECT MEMBER_ID
FROM REST_REVIEW
GROUP BY MEMBER_ID
ORDER BY COUNT(*) DESC
LIMIT 1)
ORDER BY 3, 2
풀이 과정을 순서대로 살펴보면,
1. MEMBER_PROFILE과 REST_REVIEW TABLE을 MEMBER_ID 공통 컬럼 활용 JOIN을 하여 모든 컬럼을 조회해 보았고, 잘 JOIN되어 정상적으로 출력되는 모습 확인
2. WHERE 절 내 추가적인 서브 쿼리를 활용 가장 리뷰를 많이 작성한 한 명의 회원 아이디를 조회
- R TABLE 내 리뷰 정보가 있기에, 해당 테이블을 서브 쿼리 내 활용
- 가장 리뷰를 많이 쓴 MEMEBER_ID 정보가 필요하기에, 해당 컬럼을 조회
- MEMBER_ID 별로 그룹을 분류하여, COUNT()함수 활용 가장 많은 로우를 가지고 있는 MEMBER_ID를 순서로 출력
- LIMIT절을 통해 한 명만 출력되도록 설정 (가장 많이 리뷰를 쓴 회원을 조회하는 것이 때문)
3. 필요한 컬럼들을 조회
4. 리뷰 작성일을 기준으로 오름차순, 리뷰 작성일이 같다면 리뷰 텍스트를 기준으로 오름차순 정렬
결과적으로 정답 처리가 되었으나, 추가적으로 의문이 생기는 부분이 발생하였다.
만약 리뷰를 가장 많이 쓴 회원이 한 명이 아니라 여러명이라면, LIMIT만을 활용하여 쿼리를 작성하는 것은 한계가 있다는 것이다. (실제로 가장 많은 리뷰를 쓴 회원은 한명이 아니었다!)
맞다, 이전에 TIL에서 특정 항목 내 순위를 구하는 함수를 분명 다루었기에 .. 이전에 작성한 TIL을 기반으로 다시 한번 쿼리를 작성해보았다!
2024.03.29 - [SQL/PROGRAMMERS] - 2024-03-29 [SQL ROW_NUMBER() OVER (PARTITION BY ORDER BY)]
2024-03-29 [SQL ROW_NUMBER() OVER (PARTITION BY ORDER BY)]
CASE 식당의 정보를 담은 [REST_INFO] 테이블입니다. REST_ID, REST_NAME, FOOD_TYPE, VIEWS, FAVORITES, PARKING_LOT, ADDRESS, TEL은 식당 ID, 식당 이름, 음식 종류, 조회수, 즐겨찾기수, 주차장 유무, 주소, 전화번호를 의
hongjinkwon.tistory.com
1. 풀이 및 해설 (SubQuery / LIMIT)
최종적으로 작성한 쿼리는 아래와 같다.
SELECT MEMBER_NAME,
REVIEW_TEXT,
DATE_FORMAT(REVIEW_DATE, '%Y-%m-%d') REVIEW_DATE
FROM
MEMBER_PROFILE M JOIN REST_REVIEW R ON M.MEMBER_ID = R.MEMBER_ID
WHERE R.MEMBER_ID IN (
SELECT MEMBER_ID
FROM (
SELECT MEMBER_ID, RANK() OVER(ORDER BY COUNT(*) DESC) RNK
FROM REST_REVIEW
GROUP BY MEMBER_ID
) S
WHERE RNK = 1
)
ORDER BY
REVIEW_DATE ASC, REVIEW_TEXT ASC;
작성 중 여러 번의 수정 과정을 거쳐서, 순서대로 자세히 풀어가려 한다.
1. 앞 풀이 방법과 동일
2. 이 풀이 방법에서 핵심은 가장 많은 리뷰를 작성한 사람이 한 사람이 아니더라도 문제없이 모두 출력할 수 있어야 한다는 점으로
즉, 리뷰를 가장 많이 작성한 사람이 여러명이더라도 동일한 순위를 줘야한다는 점이다.
위 플러그인한 이전 작성 글을 보면 RANK 함수 관련 내용이 나오는데,
- RANK 함수
- RANK 함수는 ORDER BY를 포함한 쿼리문에서 특정 항목에 대한 순위를 구하는 함수로, 이 때 특정범위 (PARTITION BY) 내에서 순위를 구할 수도 있고, 전체 데이터에 대한 순위를 구할 수도 있다.
- 동일한 값에 대해서는 동일한 순서를 부여하게 된다.
EX) 동일한 값을 가진 ROW가 1,1로 순서를 부여 받았다면, 다음 ROW는 3으로 순서를 부여
위 풀이와 동일하게 GROUP BY절 활용 MEMBER_ID 를 기준으로 그룹을 분류하고,
RANK() OVER() 함수를 활용하여 가장 많은 로우를 가진 회원들을 랭킹 1위 부여했다.
여기서 좀 헤맨 부분이 있는데,
"WHERE RNK=1"을 S 서브쿼리 내 작성하여 지속적으로 오류가 출력되었다는 점이다.
여기서 WHERE절을 서브쿼리에 벗어나서 적어야 하는 이유는 문제 풀이가 진행되는 순서를 생각하면 되는데,
SELECT 절보다 WHERE 조건문이 우선적으로 풀이가 진행되기 때문이다.
그래서 S 서브쿼리를 벗어나 조건을 걸어두고, 리뷰가 가장 많은 랭킹 1위 회원만으로 좁힐 수 있었다.
3. 나머지 위 풀이와 동일
문제를 푸는 과정에서 다소 어려움을 겪었던 문제들은 최대한 자세하게 TIL내 풀어보려한다.
추가로 다루고 싶은 문제가 있으나, 글이 길어져 다른 글에서 추가로 기재해야겠다!