mysql 문제풀이/hard

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

gooreumsea 2023. 7. 6. 23:45

인터넷 상에  죄다 LIMIT 1 풀이 투성이라, 조금 헤멧다.

리팩토링은 나중에...해봐야겠다.

 

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

 

습득한 점:

WITH 구문을 사용 함과 동시에, 다른 2가지 이상의 테이블을 동시에 활용 할때,

FROM 절에 들어할 테이블이 2개 이상인 경우가 있어서

이를 어찌 처리해야 할지 난감했다.

 

결과적으로는 WITH 문 + SELECT 문 조합으로 계산을 끝낸 뒤,
이 전체를 새로운 테이블의 WHERE 값에 넣어버리는 식으로 쿼리를 작성했다.

 

이 과정에서, 아래 2가지의 차이를 알게되었다.

WHERE 컬럼 = (~~~~)

WHERE 컬럼 IN (~~~~)

 

서브쿼리에 해당하는 값이 1가지 이고, 이를 다른 테이블의 조건값으로서 매칭 시킬 때는 "=" 을 사용

서브쿼리에 해당하는 값이 2가지 이상이고, 이 때는 "IN" 을 활용해야

 

subquery returns more than 1 row 에러가 발생하지 않는다.

 

또한 내가 생각치 못한 경우의 수가 있는지 없는지, 테이블을 뜯어보는 습관은 좋은 것 같다.

(이러면 시간이 오래걸려서 실제 코테에선 맞는 방법일 지는 모르겠다)


 

문제:

MEMBER_PROFILE와 REST_REVIEW 테이블에서 리뷰를 가장 많이 작성한 회원의 리뷰들을 조회하는 쿼리 작성

결과값은 회원 이름, 리뷰 텍스트, 리뷰 작성일이 출력되도록 작성,

정렬기준은 리뷰 작성일을 기준으로 오름차순,

                 리뷰 작성일이 같다면 리뷰 텍스트를 기준으로 오름차순 정렬.

 

 

문제파악:

문제가 좀 이상하다.

문제 타이틀은 식당 목록을 출력하는 것인데,

정답의 결과는 아래와 같다.

 

또 하나, 문제를 처음 접근할 때 조인을 어떻게하면 좋을 지 처음엔 테이블을 하나하나 다 뜯어보다가,

고객을 정보를 담은 MEMBER_PROFILE 테이블의 member_id(이메일)는 14개인데,

리뷰정보를 담은 REST_REVIEW 테이블에서의 중복을 제거한 member_id(이메일)은 모두 15개 였다...

???

일단 테이블끼리 조인했다.

 

또한 리뷰 카운트를 세다보니, 리뷰 수의 최댓 값이 같은 사람이 한명이 아니었다.

리뷰를 가장 많이 작성한 사람이 3명 임에도,

아래의 쿼리와 같이 LIMIT 1을 조건으로 걸면, 저 위에 리뷰 3개를 작성한 사람 3명 중 1명만 조회가 된다.

 

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

 

 

풀이:

 

1. 리뷰 수 최대 값 찾기

WITH 문으로, MEMBER_ID를 그룹으로 묶은 뒤 MEMBER_ID별 카운트 값을 찾기

그 카운트 값들 중 최고인 값을 SELECT MAX(Review_NUMBER)로 찾고 Alias는 MAX_NUMBER로 지정

 

2. 리뷰 수가 최대값 인 아이디 찾기

REST_REVIEW 테이블에서 SELECT 문으로 MEMBER_ID, MEMBER_ID별 카운트 값을 찾는 쿼리 작성 후 이를 서브쿼리로 활용

만들어진 서브쿼리를 테이블로서 활용하고, MEMBER_ID값을 다시 구함.

이떄 WHERE 구문 조건으로 WHERE NUM = (1번 쿼리 전체) 을 조건으로 추가.

그럼 리뷰 카운트가 3인, MEMBER_ID값 만 뽑아낼 수 있다.

 

3. 찾은 아이디를 활용하여 정답 찾기

뽑아낸 MEMBER_ID 들을 WHERE 조건으로 활용하는 쿼리문을 작성

테이블 2가지를 조인 후, 정답에서 원하는 컬럼들을 다 가지고 온다.

이때는 WHERE 조건에 들어가는 값들이 1개 이상이므로 IN을 활용하여,
WHERE RR.MOMBER_ID IN (2번 쿼리 전체) 를 조건으로 활용.

뒤에 ORDER BY 정렬조건까지 잊지말고 작성.

 

 

SELECT MEMBER_NAME
     , REVIEW_TEXT
     , DATE_FORMAT(REVIEW_DATE, "%Y-%m-%d") AS REVIEW_DATE
     
FROM REST_REVIEW AS RR
     LEFT JOIN MEMBER_PROFILE AS MP ON RR.MEMBER_ID = MP.MEMBER_ID
WHERE RR.MEMBER_ID IN (

                    SELECT MEMBER_ID
                    FROM(
                        SELECT MEMBER_ID, count(*) AS NUM
                        FROM REST_REVIEW
                        GROUP BY MEMBER_ID
                        ) sub
                    WHERE NUM = (

                        WITH counter as (
                            SELECT MEMBER_ID, COUNT(*) AS Review_NUMBER
                            FROM REST_REVIEW
                            GROUP BY MEMBER_ID
                                         )

                        SELECT MAX(Review_NUMBER) AS MAX_NUMBER
                        FROM counter
                                )
                        
                       )
ORDER BY REVIEW_DATE
       , REVIEW_TEXT