6-4 연습 문제 — GROUP BY 진단,
직접 고쳐본 SQL만 머리에 남는다
섹션 6 연습의 정체성 — AI가 만든 잘못된 SQL을 진단하고 직접 수정하기. 이번엔 GROUP BY입니다. 누락 컬럼 · 집계 단위 · 비중 분모 세 함정 — 에러 없이 임의 값이 나오는 곳, 일별이 분기별로 둔갑한 곳, 모든 비중이 100%로 찍히는 곳을 직접 잡아냅니다.
이번 연습의 위치
완료 ✓
강의 완료 ✓
지금 여기
섹션 6 마무리
2-4에서 만든 AI 과외 선생님 세션을 그대로 쓰세요. 먼저 혼자 진단해 보고 — 막히면 정답이 아니라 힌트만 요청하세요. 다 푼 뒤에는 본인의 진단과 수정 SQL을 던지며 “내 SQL 검증해줘” 라고 요청하면, GROUP BY에 빠진 컬럼이 없는지·집계 단위가 의도와 맞는지까지 짚어줍니다.
문제 1. GROUP BY 누락 컬럼 진단
다음 SQL — 무엇이 문제? MySQL에서 실행하면 어떤 결과가 나올까?
-- ❌ AI 가 만든 SQL
SELECT
m.member_name,
m.gender,
m.age,
COUNT(o.order_id) AS 주문수
FROM
members m
LEFT JOIN orders o
ON m.member_id = o.member_id
GROUP BY
m.member_id;정답 보기
문제: SELECT에 member_name, gender, age가 있는데 GROUP BY에는 member_id만.
에러 없이 조용히 통과합니다
각 member_id 그룹에서 — member_name,
gender, age의 임의 한 값을 반환. shop
데이터에선 한 member_id에 한 회원이라 결과가 정확해 보일 수
있음. 하지만 DB가 보장하는 게 아님.
에러가 납니다 — 차라리 안전
비집계 컬럼이 GROUP BY에 없으면 즉시 에러 발생. 잘못된 SQL이 보고서까지 흘러가기 전에 막아줍니다.
수정:
SELECT
m.member_name,
m.gender,
m.age,
COUNT(o.order_id) AS 주문수
FROM
members m
LEFT JOIN orders o
ON m.member_id = o.member_id
GROUP BY
m.member_id,
m.member_name,
m.gender,
m.age;비집계 컬럼 모두 GROUP BY에 추가.
member_id가 PK라서 다른 컬럼들이 함수 종속이지만 —
명시가 안전.
문제 2. 집계 단위 오류
다음 SQL — “분기별 매출” (Q1, Q2, Q3, Q4) 의도. 잘못됐나? 어떻게 수정?
-- ❌
SELECT
ordered_at,
SUM(p.price * oi.quantity) AS 매출
FROM
orders o
JOIN order_items oi USING(order_id)
JOIN products p USING(product_id)
GROUP BY
ordered_at;정답 보기
진단: GROUP BY ordered_at — 일별로 묶음. 분기별 아님.
수정 (MySQL):
SELECT
CONCAT(YEAR(ordered_at), '-Q', QUARTER(ordered_at)) AS 분기,
SUM(p.price * oi.quantity) AS 매출
FROM
orders o
JOIN order_items oi USING(order_id)
JOIN products p USING(product_id)
GROUP BY
분기
ORDER BY
분기;핵심 함수:
YEAR(date)— 연도 추출QUARTER(date)— 분기 (1~4) 추출CONCAT(...)— 문자열 결합
| 분기 | 매출 |
|---|---|
| 2025-Q1 | 280000 |
| 2025-Q2 | 410000 |
| 2025-Q3 | 350000 |
| 2025-Q4 | 520000 |
| 2026-Q1 | 380000 |
문제 3 (도전). 비중 계산 + 다중 함정
다음 SQL — “카테고리별 매출 + 그 카테고리가 전체에서 차지하는 비중 (%)” 의도. 두 개 함정이 있어요.
-- ❌ AI 가 만든 (잘못된) SQL
SELECT
category_id,
category_name,
SUM(price * quantity) AS 매출,
SUM(price * quantity) / SUM(price * quantity) * 100 AS 비중_퍼센트
FROM
categories c
JOIN products p
ON c.category_id = p.category_id
JOIN order_items oi
ON p.product_id = oi.product_id
GROUP BY
category_id;1. 두 가지 함정을 찾으세요. 2. 수정 SQL을 작성하세요.
정답 보기
category_name이 빠졌습니다
SELECT에 category_name 있는데 GROUP BY에는
category_id만. MySQL은 허용 (category_id가 PK라
함수 종속) — 하지만 명시가 안전.
항상 100%가 나옵니다
SUM(price * quantity) / SUM(price * quantity) * 100 — 분모도
“이 그룹 안 SUM”. 항상 100%가 나옴. 모든 카테고리 비중 =
100%.
수정:
SELECT
c.category_id,
c.category_name,
SUM(p.price * oi.quantity) AS 매출,
SUM(p.price * oi.quantity)
/ (SELECT
SUM(p2.price * oi2.quantity)
FROM
products p2
JOIN order_items oi2 USING(product_id))
* 100 AS 비중_퍼센트
FROM
categories c
JOIN products p
ON c.category_id = p.category_id
JOIN order_items oi
ON p.product_id = oi.product_id
GROUP BY
c.category_id,
c.category_name
ORDER BY
매출 DESC;수정 두 곳:
GROUP BY c.category_id, c.category_name— category_name 추가- 분모를 서브쿼리로 — 그룹 밖의 전체 합
| category_name | 매출 | 비중_퍼센트 |
|---|---|---|
| 의류 | 800000 | 30 |
| 전자기기 | 700000 | 26.5 |
| 도서 | 500000 | 19 |
| 뷰티 | 350000 | 13 |
| 식품 | 300000 | 11.5 |
더 우아한 대안 — 윈도우 함수:
SELECT
c.category_name,
SUM(p.price * oi.quantity) AS 매출,
SUM(p.price * oi.quantity) * 100.0
/ SUM(SUM(p.price * oi.quantity)) OVER () AS 비중_퍼센트
FROM
categories c
JOIN products p
ON c.category_id = p.category_id
JOIN order_items oi
ON p.product_id = oi.product_id
GROUP BY
c.category_id,
c.category_name;SUM(SUM(...)) OVER () — “GROUP BY 결과의 모든 SUM의 합” (= 전체 합)을 윈도우 함수로.
비집계 컬럼은 GROUP BY에 명시, 집계 단위는 날짜 함수로 의도에 맞게, 비중 분모는 그룹 밖 전체 합으로 — 세 함정을 직접 고쳐봤다면, 이제 섹션 6의 화룡점정인 검증 체크리스트로 모든 무기를 하나의 습관으로 묶을 차례입니다.