집계함수는 여러 행의 값을 하나로 합쳐서 계산하는 함수로, “전체 게시글 수”, “평균 조회수”처럼 통계성 정보를 뽑을 때 사용합니다.
| 함수 | 의미 |
|---|---|
| COUNT(컬럼 또는 *) | 행의 개수 |
| SUM(컬럼) | 합계 |
| AVG(컬럼) | 평균 |
| MAX(컬럼) | 최댓값 |
| MIN(컬럼) | 최솟값 |
-- 전체 게시글 수
SELECT COUNT(*) FROM board;
-- content가 NULL이 아닌 게시글 수 (컬럼명을 넣으면 NULL은 제외하고 셈)
SELECT COUNT(content) FROM board;
-- 전체 게시글의 조회수 합계
SELECT SUM(view_count) FROM board;
-- 전체 게시글의 평균 조회수
SELECT AVG(view_count) FROM board;
-- 조회수가 가장 높은 값
SELECT MAX(view_count) FROM board;
-- 조회수가 가장 낮은 값
SELECT MIN(view_count) FROM board;
select
count(*) as 전체게시글수,
max(view_count) as 조회수최댓값,
min(view_count) as 조회수최솟값,
avg(view_count) as 조회수평균,
sum(view_count) as 조회수총합
from board
AS로 결과 컬럼에 별명(alias)을 붙이면 결과를 읽기 쉬워집니다.
집계함수를 전체 테이블이 아니라 그룹별로 적용하고 싶을 때 사용합니다.
-- 카테고리별 게시글 수
SELECT category_id, COUNT(*) AS board_count
FROM board
GROUP BY category_id;
결과 예시:
| category_id | board_count |
|---|---|
| 1 | 6 |
| 2 | 3 |
| 3 | 4 |
| 4 | 7 |
category_id가 같은 행끼리 묶어서, 그 안에서 COUNT를 계산합니다.
-- 회원별 작성한 게시글 수
SELECT member_id, COUNT(*) AS board_count
FROM board
GROUP BY member_id;
-- 카테고리별 평균 조회수
SELECT category_id, AVG(view_count) AS avg_view
FROM board
GROUP BY category_id;
SELECT에 나열하는 컬럼은 GROUP BY에 포함된 컬럼 또는 집계함수로 감싼 컬럼이어야 합니다.
WHERE는 그룹화하기 전 행 단위로 조건을 거는 것이고, HAVING은 그룹화한 이후 그룹 단위로 조건을 거는 것입니다.
-- 게시글이 5개 이상인 카테고리만 조회
SELECT category_id, COUNT(*) AS board_count
FROM board
GROUP BY category_id
HAVING COUNT(*) >= 5;
select category_id, count(*) as board_count
from board
group by category_id
having board_count >= 5
-- 평균 조회수가 0보다 큰 카테고리만 조회
SELECT category_id, AVG(view_count) AS avg_view
FROM board
GROUP BY category_id
HAVING AVG(view_count) > 0;
-- member_id가 1~5인 게시글만 대상으로, 카테고리별 게시글 수를 구하고,
-- 그중 게시글 수가 2개 이상인 카테고리만 조회
SELECT category_id, COUNT(*) AS board_count
FROM board
WHERE member_id BETWEEN 1 AND 5
GROUP BY category_id
HAVING COUNT(*) >= 2;
실행 순서: WHERE(행 필터링) → GROUP BY(그룹화) → HAVING(그룹 필터링) → ORDER BY(정렬)
💡 WHERE는 집계함수를 사용할 수 없습니다 (
WHERE COUNT(*) >= 2는 에러). 집계 결과에 조건을 걸려면 반드시 HAVING을 사용해야 합니다.
SELECT member_id, COUNT(*) AS board_count
FROM board
GROUP BY member_id
ORDER BY board_count DESC
LIMIT 3;
SELECT board_id, COUNT(*) AS comment_count
FROM comments
GROUP BY board_id
ORDER BY comment_count DESC
LIMIT 1;
SELECT board_id, COUNT(*) AS like_count
FROM board_like
GROUP BY board_id
ORDER BY like_count DESC;
관리자 화면에 흔히 나오는 “오늘의 통계” 같은 형태입니다.
SELECT
(SELECT COUNT(*) FROM member) AS total_member,
(SELECT COUNT(*) FROM board) AS total_board,
(SELECT COUNT(*) FROM comment) AS total_comment,
(SELECT COUNT(*) FROM board_like) AS total_like;
서브쿼리를 SELECT 안에 여러 개 넣으면, 서로 다른 테이블의 집계를 한 줄의 결과로 모을 수 있습니다.
-- 카테고리별 게시글 수, 평균 조회수, 최고 조회수
SELECT
category_id,
COUNT(*) AS board_count,
AVG(view_count) AS avg_view,
MAX(view_count) AS max_view
FROM board
GROUP BY category_id
ORDER BY board_count DESC;
-- 게시글이 5개 이상이면서 평균 조회수가 0보다 큰 카테고리만
SELECT
category_id,
COUNT(*) AS board_count,
AVG(view_count) AS avg_view
FROM board
GROUP BY category_id
HAVING COUNT(*) >= 5 AND AVG(view_count) > 0;
“게시글 작성 수 + 댓글 작성 수”를 기준으로 활동량이 많은 회원을 가려내고 싶을 때, 우선 각각 따로 집계해봅니다.
-- 회원별 게시글 수
SELECT member_id, COUNT(*) AS board_count
FROM board
GROUP BY member_id;
-- 회원별 댓글 수
SELECT member_id, COUNT(*) AS comment_count
FROM comment
GROUP BY member_id;
두 결과를 합쳐서 보는 방법은 다음 단계(JOIN)에서 본격적으로 다룹니다. 지금은 각각 따로 집계하는 연습에 집중합니다.
게시글을 “인기글(조회수 10 이상)”과 “일반글”로 나누어 각각 몇 개인지 한 번에 보고 싶다면 CASE WHEN을 사용합니다.
SELECT
SUM(CASE WHEN view_count >= 10 THEN 1 ELSE 0 END) AS popular_count,
SUM(CASE WHEN view_count < 10 THEN 1 ELSE 0 END) AS normal_count
FROM board;
동작 원리: CASE WHEN은 행 하나하나를 조건에 맞게 1 또는 0으로 바꿔주고, SUM이 그 값들을 더해서 개수처럼 사용하는 방식입니다.
-- 카테고리별로 인기글/일반글 개수를 나누어 집계
SELECT
category_id,
SUM(CASE WHEN view_count >= 10 THEN 1 ELSE 0 END) AS popular_count,
SUM(CASE WHEN view_count < 10 THEN 1 ELSE 0 END) AS normal_count
FROM board
GROUP BY category_id;
-- 좋아요를 가장 많이 받은 게시글 TOP 5 (board_id와 좋아요 수만)
SELECT board_id, COUNT(*) AS like_count
FROM board_like
GROUP BY board_id
ORDER BY like_count DESC
LIMIT 5;
-- 좋아요를 가장 많이 누른 회원(활동적인 회원) TOP 5
SELECT member_id, COUNT(*) AS like_given_count
FROM board_like
GROUP BY member_id
ORDER BY like_given_count DESC
LIMIT 5;
H2에서는 날짜 함수로 날짜 단위를 추출할 수 있습니다.
-- 날짜별 게시글 작성 수 (시간은 빼고 날짜만 추출)
SELECT CAST(created_at AS DATE) AS write_date, COUNT(*) AS board_count
FROM board
GROUP BY CAST(created_at AS DATE)
ORDER BY write_date DESC;
-- 월별 게시글 작성 수
SELECT FORMATDATETIME(created_at, 'yyyy-MM') AS write_month, COUNT(*) AS board_count
FROM board
GROUP BY FORMATDATETIME(created_at, 'yyyy-MM')
ORDER BY write_month DESC;
날짜 함수는 DBMS마다 문법이 조금씩 다릅니다 (
FORMATDATETIME은 H2 문법). 추후 MySQL로 옮길 때는DATE_FORMAT(created_at, '%Y-%m')처럼 바뀐다는 점을 알아두면 좋습니다.