- country를 기준으로 GROUP BY 한 예
GROUP BY 예제
예제 데이터
customer_id | amount |
1 | 100 |
1 | 200 |
2 | 150 |
2 | 250 |
2 | 100 |
3 | 300 |
SELECT customer_id, SUM(amount)
FROM payment
GROUP BY customer_id;
동작 과정
GROUP BY customer_id
→customer_id
가 같은 행들을 그룹으로 묶음SUM(amount)
→ 각 그룹의amount
값을 합산각
customer_id
별 결제 총액을 출력
SQL 실행 결과
customer_id | SUM(amount) |
1 | 300 |
2 | 500 |
3 | 300 |
해석:
customer_id = 1
인 고객은100 + 200 = 300
원을 결제customer_id = 2
인 고객은150 + 250 + 100 = 500
원을 결제customer_id = 3
인 고객은300
원을 결제
✅ GROUP BY – 동일한 값을 가진 데이터를 그룹화
SELECT department, COUNT(*) FROM employees GROUP BY department;
employees 테이블에서 부서별 직원 수 조회
일반적으로 집계 함수 (SUM, COUNT, AVG 등)와 함께 사용
GROUP BY 문을 사용하고 특정 열만 선택하는 경우, GROUP BY에 그 열을 반드시 포함시켜야 함.
SELECT category_col FROM table GROUP BY category_col
열에 집계 함수를 적용시킨 경우에만 예외
SELECT category_col, AGG(data_col) FROM table GROUP BY category_col
원한다면 GROUP BY를 하기 전에 WHERE 문을 실행할 수 있음
SELECT category_col, AGG(data_col) FROM table WHERE category_col != 'A' GROUP BY category_col
- 카테고리 A를 전부 무시하고, GROUP BY 실행
GROUP BY는 FROM 문 바로 뒤나, WHERE 문 바로 뒤에 와야 함
GROUP BY에서 순서는 크게 중요하지 않음(대부분의 경우 SELECT와 순서를 맞춤)
이런 상황에 사용:
총액 기준으로 가장 많은 금액을 사용한 고객을 찾을 때
SELECT customer_id, SUM(amount) FROM payment GROUP BY customer_id -- 고객 ID '별(per)' ORDER BY SUM(amount) DESC -- 고객 ID 별 금액의 총 합을 나타내는 열
- ORDER BY는 질문이 무언인가에 따라 정하면 됨
마케팅 팀에서 월별 매출 추이를 분석하고 싶을 때
SELECT DATE_FORMAT(order_date, '%Y-%m') AS month, SUM(total_price) AS monthly_sales FROM orders GROUP BY DATE_FORMAT(order_date, '%Y-%m'); /* order_date의 연-월(%Y-%m)을 기준으로 그룹화하고, 각 월별 총 매출(SUM(total_price))을 계산 */
거래 총액이 가장 적은 날짜를 확인하고 싶을 때
SELECT DATE(payment_date), SUM(amount) FROM payment -- DATE는 타임 스탬프 정보 중 '날짜 부분'만 추출 GROUP BY DATE(payment_date) ORDER BY SUM(amount) -- (DESC)
✅ HAVING – 그룹화된 데이터에 조건 적용
SELECT company, SUM(sales)
FROM finance_table
WHERE company != 'Google' -- (2) 개별 행에서 'Google' 제외
GROUP BY company; -- (3) 그룹화 수행 (Google은 이미 없음)
WHERE
는 그룹화 전에 개별 행을 필터링즉,
'Google'
데이터를 미리 제거한 후 남은 데이터로 그룹화를 수행집계 결과(SUM)를 기준으로 필터링할 수 없음!
왜냐하면 집계는 아직 수행되지 않았기 때문
참고: SQL 실행 순서
FROM
→ 테이블 선택WHERE
→ 개별 행 필터링GROUP BY
→ 그룹화 수행집계 함수 실행 (
SUM
,AVG
등)HAVING
→ 그룹화된 데이터 필터링SELECT
→ 최종 결과 선택ORDER BY
→ 정렬 수행
즉, GROUP BY를 실행하고 회사별 판매액 총계를 계산한 후에 그 결과를 추가적으로 필터링해야함 → HAVING 사용
SELECT company, SUM(sales) FROM finance_table WHERE company != 'Google' GROUP BY company; -- (3) 회사별 그룹화 HAVING SUM(sales) > 1000 -- (5) 그룹화된 결과를 필터링
SUM(sales)
는GROUP BY
후에 계산되므로, 집계된 결과를 기준으로 필터링하려면HAVING
을 사용해야 함
SELECT department, COUNT(*)
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;
부서별 직원 수를 구한 후, 직원이 5명 이상인 부서만 조회
HAVING은 집계(aggregation)가 이미 수행된 이후에 자료를 필터링함
WHERE은 개별 행을 필터링, HAVING은 그룹화된 데이터 필터링
WHERE vs HAVING
WHERE와 .HAVING은 비슷해 보인다. 실제로 WHERE가 하는 역할을 HAVING이 대신할 수도 있다.
ex) 특정 회사만 필터링하고 싶다면:
SELECT company
FROM finance_table
GROUP BY company
HAVING company != 'Google';
- 이렇게 사용할 수 있지만,
WHERE
로 대체할 수 있기 때문에 실용적인 의미는 적다.
→ 같은 결과를WHERE
을 사용해서 더 효율적으로 만들 수 있기 때문
SELECT company
FROM finance_table
WHERE company != 'Google'
GROUP BY company;
⚠️ 언제 HAVING
을 쓰는 게 적절할까?
HAVING
을 집계 함수 없이 사용하면, 단순한 그룹 필터링을 수행하는데, 대부분WHERE
으로 대체할 수 있음하지만 그룹화된 데이터에 대한 필터링이 필요한 경우에는
HAVING
이 필수!
집계 함수가 있는 HAVING
(일반적인 경우)
대부분 HAVING
은 집계 함수와 함께 사용된다.
SELECT company, SUM(sales) AS total_sales
FROM finance_table
GROUP BY company
HAVING SUM(sales) > 10000;
- 이 경우
WHERE
로는SUM(sales) > 10000
을 필터링할 수 없기 때문에HAVING
을 반드시 사용해야 함
✨ In English:
GROUP BY
groups rows that have the same values in specified columns.HAVING
filters grouped data based on conditions.
📝 오늘 배운 점:
GROUP BY
는 집계 함수와 함께 사용해야 의미가 있다.HAVING
은WHERE
처럼 필터링하지만, 개별 행이 아니라 그룹화된 데이터에 적용된다.GROUP BY
에서 여러 컬럼을 지정하면 다중 레벨의 그룹화를 할 수 있다.HAVING
조건은GROUP BY
이후에 적용되므로, 필터링 기준을 정확히 이해해야 한다.SQL에서 데이터를 효과적으로 분석하려면
GROUP BY
와HAVING
을 적절히 활용하는 것이 중요하다.
연습 문제
연습 문제 1
Staff ID가 1과 2인 두 명의 직원 중 가장 많은 결제를 처리한 직원에게 보너스를 주려고 한다.
각 직원이 처리한 결제건수는 몇 건이며 누가 보너스를 받게 될까?
SELECT staff_id,COUNT(amount) FROM payment
GROUP BY staff_id
연습 문제 2
본사에서 교체 비용과 영화의 MPAA 등급(G, PG, R 등) 사이의 관계에 관한 연구를 수행하고 있다.
MPAA 등급 별 평균 replacement cost는 얼마(소수점 2자리수까지)일까?
SELECT rating,ROUND(AVG(replacement_cost),2) FROM film
GROUP BY rating
연습 문제 3
상위 5명의 고객에게 쿠폰을 증정하는 행사를 진행 중이다.
총 지출액 또는 총 사용을 기준으로 상위 고객 5명의 고객 ID는 무엇일까?
SELECT customer_id, ROUND(SUM(amount),2) FROM payment
GROUP BY customer_id
ORDER BY SUM(amount) DESC
LIMIT 5
연습 문제 4
충성도가 가장 높은 고객을 위한 플래티넘 서비스를 시작하려고 한다.
결제 거래 건수가 40건 이상인 고객에게 플래티넘 멤버십을 부여하려고 하는데, 플래티넘 자격이 있는 고객 ID는 무엇인가?
SELECT customer_id, COUNT(amount) FROM payment
GROUP BY customer_id
HAVING COUNT(amount) >= 40
연습 문제 5
직원ID 2와의 결제 거래에서 100달러를 초과해 사용한 고객의 고객 ID는 무엇인가?
첫 시도:
SELECT customer_id, SUM(amount) FROM payment
GROUP BY customer_id, staff_id = 2
HAVING SUM(amount) > 100
GROUP BY에 staff_id까지 넣어버림
GROUP BY에는 열(column)만 들어가야 하고, 조건문을 넣을 수 없음!
staff_id = 2
는 그룹핑 대상이 아니라 필터링 조건이므로WHERE
에서 처리해야 함
정답:
SELECT customer_id, SUM(amount) FROM payment
WHERE staff_id = 2
GROUP BY customer_id
HAVING SUM(amount) > 100