문제
https://school.programmers.co.kr/learn/courses/30/lessons/131124
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
✍️ 문제 요약
- MEMBER_PROFILE와 REST_REVIEW 테이블에서 리뷰를 가장 많이 작성한 회원의 리뷰들을 조회
- 회원 이름, 리뷰 텍스트, 리뷰 작성일이 출력되도록 작성
- 리뷰 작성일 오름차순, 같다면 리뷰 텍스트 기준 오름차순 정렬
- 예시 테이블 참고
✍️ 내가 작성한 코드
SELECT p.member_name,
r.review_text,
r.review_date
FROM member_profile as p
JOIN rest_review as r
ON p.member_id=r.member_id
>>> 두 테이블 JOIN
SELECT member_id,
COUNT(member_id) AS cnt_member
FROM rest_review
GROUP BY member_id
ORDER BY cnt_member DESC
>>> 리뷰를 가장 많이 작성한 회원들(?)
>>> 위 쿼리문 실행하니 3개가 최대! 그런데 3명이나? LIMIT 3을 붙여도 되는건가
>>> LIMIT를 붙이는 건 가장 많이 작성한 회원이 3명이라는 것을 알고 있을 때 인건데...
>>> 만약 모른다면 어떻게 하지?
WITH max_review AS (
SELECT member_id,
COUNT(member_id) AS cnt_member
FROM rest_review
GROUP BY member_id
ORDER BY cnt_member DESC
LIMIT 1
)
SELECT p.member_name,
r.review_text,
DATE_FORMAT(r.review_date, '%Y-%m-%d') AS review_date
FROM member_profile as p
JOIN rest_review as r ON p.member_id=r.member_id
JOIN max_review as m ON m.member_id=r.member_id
ORDER BY review_date ASC, r.review_text ASC;
>>> 최종쿼리문! 정답이다.
>>> 근데 정말 리뷰 최대3개 인데, 3명이었는데 LIMIT 1을 했는데 왜 이게 맞는거지?
>>> 3명다 출력되어야 하는게 맞지 않을까?
>>> 🚨 LIMIT 1이 가능한 경우는 정말 리뷰를 가장 많이 작성한 사람이 1명일 경우에만 가능
>>> 🚨 따라서, 이 방식은 정답으로 처리됐더라도, 맞지 않는 쿼리문임!!! 🚨
✅ 개선된 방향 코드 설명(feat. JS 튜터님)
▶ CTE 2개 사용 방법 (JOIN도 여러번..ㅎㅎ;)
1. 회원별 리뷰 작성 횟수 집계 구하기
WITH cnt AS (
SELECT member_id, COUNT(*) AS c
FROM rest_review
GROUP BY member_id
),
2. 가장 많은 리뷰 수(최댓값)만 뽑기 : 위에서 뽑은 cnt에서 최댓값만 불러온다.
, mx AS (
SELECT MAX(c) AS max_c
FROM cnt
)
3. 최종 쿼리문:
ㄱ. rest_review r와 cnt c를 member_id로 조인 ➡️ 각 리뷰에 그 회원의 리뷰 개수 c 를 붙이고
ㄴ. 다시 mx m 와 조인 ➡️ 리뷰 개수가 최댓값인 회원의 리뷰만 남는다!!
ㄷ. member_profile 와 조인 ➡️ member_name 을 얻음
WITH cnt AS (
SELECT member_id, COUNT(*) AS c
FROM rest_review
GROUP BY member_id
),
mx AS (
SELECT MAX(c) AS max_c
FROM cnt
)
SELECT p.member_name,
r.review_text,
DATE_FORMAT(r.review_date, '%Y-%m-%d') AS review_date
FROM rest_review r
JOIN cnt c ON r.member_id = c.member_id
JOIN mx m ON c.c = m.max_c
JOIN member_profile p ON p.member_id = r.member_id
ORDER BY review_date ASC, r.review_text ASC;
💡 질문을 통해 배운 점
1) WITH 절에 만들어 놓은 테이블을 두 번째 WITH 절에서 참조하여 사용 가능
처음에 만든 cnt를 두번째 WITH절에서 테이블로 가져옴
2) JOIN은 정말 많이도 붙일 수가 있구나!!
붙이고 붙이고 붙이고
FROM rest_review r
JOIN cnt c ON r.member_id = c.member_id
JOIN mx m ON c.c = m.max_c
JOIN member_profile p ON p.member_id = r.member_id
🔍 또 다른 풀이
▶ CTE 1개 + 윈도우 함수 사용
WITH ranked AS (
SELECT member_id,
COUNT(*) AS c,
DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) AS rk
FROM rest_review
GROUP BY member_id
)
SELECT p.member_name, r.review_text, DATE_FORMAT(r.review_date, '%Y-%m-%d') AS review_date
FROM rest_review r
JOIN ranked k ON r.member_id = k.member_id
JOIN member_profile p ON p.member_id = r.member_id
WHERE k.rk = 1
ORDER BY review_date ASC, r.review_text ASC;
[ 설명 ]
ㄱ. DENSE_RANK() OVER ( ) 윈도우 함수로 member_id 별 리뷰작성 횟수 순위를 매김 [*RANK () OVER()도 사용가능]
ㄴ. JOIN으로 연결 후, 순위가 1위 인 것들만 불러온다.
문법 설명 참조
➡️ https://www.notion.so/teamsparta/SQL-_5-2492dc3ef5148026bfd5e5d3bc58ae1b
[SQL세션_5회차]강민정 튜터님 | Notion
[강의 녹화본]
www.notion.so
끝.
'SQL' 카테고리의 다른 글
| [SQL/코드카타] 프로그래머스 - 오프라인/온라인 판매 데이터 통합하기 | UNION & NULLIF (0) | 2025.09.22 |
|---|---|
| [SQL/코드카타] 프로그래머스 : 대여 횟수가 많은 자동차들의 월별 대여 횟수 (0) | 2025.09.18 |
| [SQL/코드카타] 프로그래머스 : 저자 별 카테고리 별 매출액 집계하기 | WITH, JOIN, GROUP BY (1) | 2025.09.17 |
