코딩테스트/SQL

[프로그래머스][MySQL] Lv. 4 그룹별 조건에 맞는 식당 목록 출력하기

_알파카 2024. 7. 19. 17:42
728x90

문제 설명

https://school.programmers.co.kr/learn/courses/30/lessons/131124

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제의 조건은 다음과 같다. 

- 리뷰를 가장 많이 작성한 회원의 리뷰 조회
- 회원 이름, 리뷰 텍스트, 리뷰 작성일이 출력
- 리뷰 작성일을 기준으로 오름차순, 리뷰 텍스트를 기준으로 오름차순

 

회원의 정보가 담긴 테이블과 리뷰 정보가 담긴 테이블이 나누어져 있으므로, 

풀이 과정은 다음과 같이 이루어진다. 

1. 리뷰를 가장 많이 작성한 회원 찾기

2. 그 회원의 이름, 텍스트, 작성일 출력하기

 

내 풀이

처음 풀이

-- 회원별 리뷰의 개수를 찾는 쿼리
WITH find_reviews AS (
    SELECT MEMBER_ID, REVIEW_TEXT, REVIEW_DATE, count(*) as cnt
    FROM REST_REVIEW
    GROUP BY MEMBER_ID
), 
-- 리뷰를 가장 많이 작성한 회원을 찾는 쿼리
find_member AS (
    SELECT MEMBER_ID, REVIEW_TEXT, REVIEW_DATE
    FROM find_reviews
    WHERE cnt IN (SELECT max(cnt) FROM find_reviews)
), 
-- 리뷰를 가장 많이 작성한 회원의 정보를 찾는 쿼리
find_member_info AS (
    SELECT MEMBER_ID, REVIEW_TEXT, REVIEW_DATE
    FROM REST_REVIEW
    WHERE MEMBER_ID IN (SELECT MEMBER_ID FROM find_member)
)
-- 회원 이름, 리뷰, 작성 날짜를 찾는 쿼리
SELECT p.MEMBER_NAME
        , f.REVIEW_TEXT
        , DATE_FORMAT(f.REVIEW_DATE, '%Y-%m-%d') AS REVIEW_DATE
FROM find_member_info f 
INNER JOIN MEMBER_PROFILE p
ON f.MEMBER_ID = p.MEMBER_ID
ORDER BY f.REVIEW_DATE, f.REVIEW_TEXT

 

이 풀이도 정답은 맞긴 하지만, 

좀 더 최적화할 수 있을 것 같아 아래와 같이 수정해보았다. 

 

불필요한 정보를 뺀 최적화 쿼리

-- 회원별 리뷰의 개수를 찾는 쿼리
WITH find_reviews AS (
    SELECT MEMBER_ID, count(*) as cnt
    FROM REST_REVIEW
    GROUP BY MEMBER_ID
), 
-- 리뷰를 가장 많이 작성한 회원의 정보를 찾는 쿼리
find_member AS (
    SELECT MEMBER_ID
    FROM find_reviews
    WHERE cnt IN (SELECT max(cnt) FROM find_reviews)
)
SELECT p.MEMBER_NAME
        , r.REVIEW_TEXT
        , DATE_FORMAT(r.REVIEW_DATE, '%Y-%m-%d') AS REVIEW_DATE
FROM REST_REVIEW r
INNER JOIN find_member f
ON r.MEMBER_ID = f.MEMBER_ID
INNER JOIN MEMBER_PROFILE p
ON r.MEMBER_ID = p.MEMBER_ID
ORDER BY r.REVIEW_DATE, r.REVIEW_TEXT

 

해당 쿼리는 다음과 같이 이루어진다. 

1. 고객별 리뷰의 개수 찾기

: 먼저 리뷰 테이블에서 group by를 통해 회원별 리뷰의 개수를 찾고, 이를 CTE로 정의한다. 

이 과정에서 바로 max(count(*))를 통해 최대값을 찾고 싶었는데, 이는 불가능하였다. 

(이 부분에서 시간이 다소 걸렸다!)

따라서, 회원별 작성한 리뷰의 개수만 cnt 컬럼에 따로 저장한다. 

 

2. 리뷰를 가장 많이 작성한 회원의 정보를 찾는다. 

: 앞서 고객별 리뷰의 개수를 찾는 쿼리에서, 최댓값을 찾아 그 회원의 정보를 찾는다. 

이 역시 CTE로 정의한다. 

 

3. 해당 회원의 이름, 리뷰, 작성일을 찾는다. 

: 이제 리뷰를 가장 많이 작성한 회원의 정보를 찾았기 때문에, 

이를 본래 테이블과 join하여 회원의 이름, 리뷰, 작성일을 찾는다. 

이 때, 본래 테이블인 member_profile 테이블과 join을 통해 회원의 이름을 찾아야하며, 

rest_review 테이블과 join을 통해 review_text, review_date를 찾아야한다. 

 

 

이상한 점

다소 이상한 점이 있다.

회원별 리뷰의 개수를 찾아보면, 리뷰를 가장 많이 작성한 회원은 중복이 된다. 

 

아래와 같이 member_id별 리뷰의 개수를 찾아보면, 

가장 많이 작성한 리뷰의 개수는 3이며, 

총 3명의 회원이 3개의 리뷰를 작성하였다. 

 

이를 바탕으로 내가 제출한 결과는 다음과 같다. 

총 3명의 회원에 대한 리뷰를 모두 찾아내었다. 

이는 분명 정답으로 뜬다! 

 

 

그러나.. 

다음과 같이 count(*)에서 LIMIT 1을 통해 간단하게 가장 최상위 회원만 찾아내어도

정답으로 뜬다!

SELECT A.MEMBER_NAME,
		B.REVIEW_TEXT,
        DATE_FORMAT(B.REVIEW_DATE, "%Y-%m-%d") AS REVIEW_DATE
FROM MEMBER_PROFILE A join REST_REVIEW B
ON A.MEMBER_ID = B.MEMBER_ID
WHERE A.MEMBER_ID = (SELECT MEMBER_ID FROM REST_REVIEW
						GROUP BY MEMBER_ID
						ORDER BY COUNT(*) DESC LIMIT 1)
ORDER BY REVIEW_DATE asc, REVIEW_TEXT

 

참 웃긴다:)

728x90