비유: 영수증 묶음
편의점 영수증이 100장 있다고 가정합니다.
날짜별로 묶으면 → 날짜별 총 구매 금액을 알 수 있습니다.
상품별로 묶으면 → 상품별 판매 수량을 알 수 있습니다.
GROUP BY 는 이 "묶는 기준"을 정하는 명령어입니다.
구조
SELECT 그룹컬럼, 집계함수
FROM 테이블명
GROUP BY 그룹컬럼;
use sns;
-- GROUP BY 없이 : 전체 좋아요 개수 출력
select count(*) as 전체좋아요수
from like_log;
select * from like_log;
-- 게시글 별 좋아요 수
select post_id, count(*) as 좋아요수
from like_log
group by post_id;
GROUP BY 동작 원리
쿼리 실행 흐름:
1. FROM like_log → like_log 테이블 전체 데이터를 가져옴
2. GROUP BY post_id → post_id 값이 같은 행끼리 하나의 그룹으로 묶음
3. COUNT(*) 집계 → 각 그룹 안의 행 수를 셈
4. SELECT → post_id 와 집계 결과를 화면에 출력
집계 함수 종류
함수
역할
예시
COUNT(*)
행 수
게시글별 좋아요 수
COUNT(컬럼)
NULL 제외 행 수
점수가 있는 수강 기록 수
SUM(컬럼)
합계
상태별 총 주문 금액
AVG(컬럼)
평균
사용자별 평균 조회수
MAX(컬럼)
최댓값
카테고리별 최고 가격
MIN(컬럼)
최솟값
카테고리별 최저 가격
-- 그룹바이와 집계함수 모두 사용해보기
select
post_id,
count(*) as 좋아요수,
min(created_at) as 첫번째좋아요,
max(created_at) as 마지막좋아요
from like_log
group by post_id
order by 좋아요수 desc;
그룹바이 사용 시 작성하면 안 되는 쿼리 예시
-- 그룹바이 사용시 안되는 쿼리 1
select user_id, title, count(*)
from post
group by user_id;
select * from post;
-- title 컬럼을 넣는 순간
-- (오늘 날씨가 정말 좋네요, 맛집 추천 받아요) 두개 데이중 무엇을 출력해야 될지 판단 불가
-- 그룹바이 사용시 안되는 쿼리 2
select id, count(*)
from post
where count(*) >= 3
group by id;
-- 오류 발생 : WHERE 절에는 집계 함수를 사용할 수 없습니다.
-- 이유 ? : WHERE 절은 그룹이 만들어지지 전에 실행이 됩니다.
-- 즉, 아직 COUNT 결과가 존재하지 않는 시점이라 사용이 불가능 하다.
-- 그럼 group by 는 where 못 사용하게 되나요. 맞습니다.
-- 대신 HAVING 절을 사용해야 합니다
WHERE : 행 단위 필터 → 그룹이 만들어지기 전
HAVING : 그룹 단위 필터 → 그룹이 만들어진 후
핵심 차이:
WHERE 에서는 집계함수(COUNT, SUM, AVG...) 사용 불가
HAVING 에서는 집계함수 사용 가능
HAVING 구조
SELECT 그룹컬럼, 집계함수
FROM 테이블명
GROUP BY 그룹컬럼
HAVING 집계함수 조건;
사용 코드
-- 예제 1
-- 좋아요가 2개 이상인 게시글만 조회하고 싶다면 어떻게 쿼리를 작성해야 될까?
-- 좋아요 개수 --> like_log 7개의 좋아요 저장되어 있음
select
post_id, count(*) as 좋아요수
from like_log
group by post_id
having count(*) >= 2;
-- 예제 2
-- WHERE 와 HAVING는 역할이 달라서 한 쿼리에 함께 쓸 수 있습니다.
-- 조회수 120이상 게시글을 중 좋아요 2개 이상인 게시글만 출력하시오.
-- 게시글 타이틀, 좋아요 수가 나와요 함.
select * from post;
select * FROM like_log;
select
p.title,
count(l.id) as 좋아요수
from post p
join like_log l on p.id = l.post_id
where p.view_count >= 120
group by p.id, p.title
having count(l.id) >= 2
order by 좋아요수 desc;
-- WHERE 절 조회수 120 이상인 게시글만 먼저 추림
-- 남은 게시글로 GROUP BY 실행
-- HAVING 으로 좋아요 2개 이상 그룹만 출력
1. FROM / JOIN : 테이블에서 데이터를 가져온다
2. WHERE : 개별 행을 필터링한다 (집계 전)
3. GROUP BY : 남은 행들을 같은 값끼리 바구니에 담는다
4. HAVING : 완성된 바구니 중 조건에 맞는 바구니만 남긴다 (집계 후)
5. SELECT : 화면에 보여줄 컬럼을 추출한다
6. ORDER BY : 마지막으로 정렬한다
7. LIMIT : 행 수를 제한한다
실습 코드
-- 실습 1
-- 게시글 별 좋아요 수를 출력하시오 단, 좋아요가 없는 게시글도 출력이 되어야 한다.
-- 게시글 타이틀, 좋아요 수
-- [결과확인] 게시글 4번 타이틀도 출력이 되어야 함.
select
p.id, p.title, count(l.id) as 좋아요수
from post p
left join like_log l on p.id = l.post_id
group by p.title, p.id;
-- 실습 2
-- 사용자별 작성 게시글 수 , 게시글 하나도 작성안한 회원도 나와야 한다.
-- 닉네임, 작성글 수
-- 실습 3
-- 사용자별 게시글에 평균게시글조회수 (단 2개 이상인 사람만)
-- 닉네임, 게시글 수, 평균조회수
만든 문제: sns DB에서 사용자의 이름, 작성한 게시물제목, 게시물에 달린 댓글수, 게시물평균조회수(내림차순), 사용자 email (@ 앞까지만 보이게, substring사용)를 출력하시오
답안:
select
u.nickname as 사용자이름,
p.title as 게시물제목,
count(DISTINCT c.id) as 포스트별댓글수,
p.view_count as 조회수,
substring(email, 1, locate('@',email) -1) as 사용자email
from user u
inner join post p on u.id = p.user_id
inner join comment c on p.id = c.post_id
group by p.id
order by 조회수 desc;