SQL 예제 정리('그룹별 조건에 맞는 식당 목록 출력하기')(24.05.05)
https://school.programmers.co.kr/learn/courses/30/lessons/131124
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
리뷰를 가장 많이 작성한 회원의 이름, 리뷰 텍스트, 리뷰 작성일을 출력하는 것이 이번 문제의 요구사항입니다.
우선 제가 작성한 쿼리 먼저 보여드리겠습니다.
SELECT MP.MEMBER_NAME,
RR.REVIEW_TEXT,
DATE_FORMAT(RR.REVIEW_DATE, '%Y-%m-%d') REVIEW_DATE
FROM MEMBER_PROFILE MP RIGHT JOIN REST_REVIEW RR ON MP.MEMBER_ID=RR.MEMBER_ID
WHERE MP.MEMBER_ID IN (
SELECT B.MEMBER_ID
FROM
(
SELECT A.MEMBER_ID, RANK() OVER(ORDER BY A.CNT_REVIEW DESC) RANKING
FROM
(
SELECT MP.MEMBER_ID,
COUNT(*) CNT_REVIEW
FROM MEMBER_PROFILE MP RIGHT JOIN REST_REVIEW RR ON MP.MEMBER_ID=RR.MEMBER_ID
GROUP BY MP.MEMBER_ID
) A
) B
WHERE B.RANKING = 1
)
ORDER BY REVIEW_DATE, RR.REVIEW_TEXT;
뭐가 좀 많이 복잡하긴한데
- 총 두 개의 서브 쿼리를 활용하여 리슈 수가 가장 많은 멤버를 필터링해서
- 해당 멤버들의 정보들을 본 쿼리에서 출력하게끔 작성된 쿼리입니다.
하나씩 뜯어보겠습니다.
SELECT A.MEMBER_ID, RANK() OVER(ORDER BY A.CNT_REVIEW DESC) RANKING
FROM
(
SELECT MP.MEMBER_ID,
COUNT(*) CNT_REVIEW
FROM MEMBER_PROFILE MP RIGHT JOIN REST_REVIEW RR ON MP.MEMBER_ID=RR.MEMBER_ID
GROUP BY MP.MEMBER_ID
) A
가장 안쪽에 있는 서브쿼리입니다.
여기서는 MEMBER_ID별 리뷰 수를 COUNTING한 후
바깥 쿼리에서 리뷰 수 기준 RANK를 매깁니다.
SELECT B.MEMBER_ID
FROM
(
SELECT A.MEMBER_ID, RANK() OVER(ORDER BY A.CNT_REVIEW DESC) RANKING
FROM
(
SELECT MP.MEMBER_ID,
COUNT(*) CNT_REVIEW
FROM MEMBER_PROFILE MP RIGHT JOIN REST_REVIEW RR ON MP.MEMBER_ID=RR.MEMBER_ID
GROUP BY MP.MEMBER_ID
) A
) B
WHERE B.RANKING = 1
RANK를 매기는 서브쿼리를 다시 한 번 더 서브쿼리로 하는
쿼리문을 작성합니다.
여기서는 단순하게 RANK가 1인 MEMEBER_ID만 뽑아냅니다.
SELECT MP.MEMBER_NAME,
RR.REVIEW_TEXT,
DATE_FORMAT(RR.REVIEW_DATE, '%Y-%m-%d') REVIEW_DATE
FROM MEMBER_PROFILE MP RIGHT JOIN REST_REVIEW RR ON MP.MEMBER_ID=RR.MEMBER_ID
WHERE MP.MEMBER_ID IN (
SELECT B.MEMBER_ID
FROM
(
SELECT A.MEMBER_ID, RANK() OVER(ORDER BY A.CNT_REVIEW DESC) RANKING
FROM
(
SELECT MP.MEMBER_ID,
COUNT(*) CNT_REVIEW
FROM MEMBER_PROFILE MP RIGHT JOIN REST_REVIEW RR ON MP.MEMBER_ID=RR.MEMBER_ID
GROUP BY MP.MEMBER_ID
) A
) B
WHERE B.RANKING = 1
)
ORDER BY REVIEW_DATE, RR.REVIEW_TEXT;
RANK가 1인 MEMBER_ID만 뽑아내는 쿼리문을
본 쿼리의 WHERE 절에 넣어준 후
SELECT 절에 문제에서 요구한 MEMBER_NAME, REVIEW_TEXT, REVIEW_DATE를 적어준 후,
마지막으로 REVIEW_DATE와 REVIEW_TEXT를 기준으로 정렬해줍니다.
이 쿼리의 경우 이전에 작성한 쿼리문을 보지 않고 새롭게 작성한 쿼리문인데요,
예전에 작성한 쿼리문을 확인해보니 훨씬 간단했습니다.
SELECT MP.MEMBER_NAME,
RR.REVIEW_TEXT,
DATE_FORMAT(RR.REVIEW_DATE, '%Y-%m-%d') REVIEW_DATE
FROM MEMBER_PROFILE MP JOIN REST_REVIEW RR ON MP.MEMBER_ID = RR.MEMBER_ID
WHERE MP.MEMBER_ID =
(
SELECT MEMBER_ID
FROM REST_REVIEW
GROUP BY MEMBER_ID
ORDER BY COUNT(*) DESC
LIMIT 1
)
ORDER BY REVIEW_DATE, RR.REVIEW_TEXT
첫 번째 쿼리와 이 쿼리의 차이점은 뭘까요?
두 번째 쿼리는 조건에 해당하는 MEMBER들 중 한 명의 리뷰들만을 출력하는 쿼리입니다.
SELECT MEMBER_ID
FROM REST_REVIEW
GROUP BY MEMBER_ID
ORDER BY COUNT(*) DESC
LIMIT 1
두 번째 쿼리의 서브쿼리를 보시면 '개수'를 기준으로 정렬 후 LIMIT 1을 걸어버립니다.
이렇게 되면 리뷰 수가 동일하더라도 가장 위에 출력되는 MEMBER_ID 하나만 WHERE절에 들어가게 되죠.
PROGRAMMERS에서 두 결과값 모두 정답 처리를 하니 어떤 쿼리를 사용해도 상관은 없을 것 같습니다.
어짜피 쿼리 작성 로직 자체는 동일하니까요.