꼭 서브쿼리를 써야 할까? GROUP BY + HAVING으로 충분했던 SQL 문제 풀이
SQL 문제를 풀다 보면 "이럴 땐 반드시 서브쿼리를 써야 하나?" 하는 고민을 자주 한다.
이번에 중고 거래 게시글 데이터를 다루면서 그런 고민을 했고,
결과적으로는 GROUP BY + HAVING만으로도 문제를 깔끔하게 해결할 수 있었다.
중고 거래 게시글(used_goods_board) 테이블에서
게시글을 3건 이상 등록한 사용자의user_id,nickname,전체 주소,전화번호를 조회하라.
- 주소는
city,street_address1,street_address2를 이어붙여 출력- 전화번호는
tlno컬럼을XXX-XXXX-XXXX형식으로 가공
처음에는 서브쿼리를 생각했다
SELECT user_id, nickname, "전체 주소", "전화번호"
FROM (
SELECT u.user_id,
u.nickname,
CONCAT(u.city, ' ', u.street_address1, ' ', u.street_address2) AS "전체 주소",
CONCAT(SUBSTR(u.tlno,1,3), '-', SUBSTR(u.tlno,4,4), '-', SUBSTR(u.tlno,8,4)) AS "전화번호",
COUNT(b.writer_id) AS post_count
FROM used_goods_board b
INNER JOIN used_goods_user u ON b.writer_id = u.user_id
GROUP BY 1,2,3,4
) sub
WHERE post_count >= 3;
의도: 먼저 집계한 뒤 WHERE로 필터링
단점: 쿼리가 다소 복잡해지고, 굳이 COUNT를 출력할 필요는 없는데 출력하고 있음
💡 그런데 아래와 같이 풀면 GROUP BY + HAVING만으로도 충분했다!
SELECT u.user_id,
u.nickname,
CONCAT(u.city, ' ', u.street_address1, ' ', u.street_address2) AS "전체 주소",
CONCAT(SUBSTR(u.tlno,1,3), '-', SUBSTR(u.tlno,4,4), '-', SUBSTR(u.tlno,8,4)) AS "전화번호"
FROM used_goods_board b
INNER JOIN used_goods_user u ON b.writer_id = u.user_id
GROUP BY 1,2,3,4
HAVING COUNT(b.writer_id) >= 3;
훨씬 직관적이고 간단한 쿼리
GROUP BY에 포함된 컬럼만 SELECT로 출력
HAVING절을 이용해 집계 조건만 필터링
✅ 핵심 요약
집계 전에 필터링해야 할 조건: WHERE
집계 후 그룹별로 필터링할 조건: HAVING
SELECT에 집계 결과가 필요하지 않을 때: 집계함수(ex.count) 없이도 HAVING만 사용 가능
📌 배운 점
GROUP BY는 반드시 COUNT, SUM 같은 집계함수를 SELECT절에 포함시킬 필요는 없다.
HAVING절은 집계된 결과를 필터링할 때 사용하는 구문이다.
불필요하게 서브쿼리를 쓰는 것보다, 직관적인 GROUP BY + HAVING 구조로 해결하는 것이 더 깔끔하고 효율적일 수 있다.