6-1 연습 문제 — 5 패턴 진단,
직접 진단해 본 패턴만 머리에 남는다
이번 연습부터는 SQL을 새로 짜는 게 아니라 — AI가 만든 잘못된 SQL을 진단합니다. 5개의 SQL을 보고 어떤 패턴인지 짚어내고, 고칠 수 있는 건 직접 고치고, SQL 수정으로 안 되는 건 후속 프롬프트로 보완합니다. 영상으로 5 패턴을 봤다고 끝이 아니에요 — 직접 진단해 본 패턴만 머리에 남습니다.
이번 연습의 위치
완료 ✓
강의 완료 ✓
지금 여기
JOIN·NULL·GROUP BY 심화
섹션 6 마무리
모든 문제가 “AI가 만든 잘못된 SQL을 진단” 형식입니다. 정답 SQL을 짜는 능력이 아니라 — 틀린 SQL을 알아보는 눈을 기르는 연습이에요.
2-4에서 만든 AI 과외 선생님 세션을 그대로 쓰세요. 먼저 혼자 진단하고 — 막히면 정답이 아니라 힌트만 요청하세요. 다 푼 뒤에는 본인의 진단을 던지며 “내 진단이 맞는지 검증해줘” 라고 물어보면 — AI의 실수를 AI에게 확인받는 메타 학습까지 같이 됩니다.
문제 1. 다음 5 개 SQL의 패턴 진단
각 SQL이 6-1의 5 패턴 중 어느 패턴에 해당하는지 진단하세요.
SQL A
SELECT
m.member_name,
COUNT(*) AS 주문수
FROM
members m
JOIN orders o
ON m.member_id = o.member_id
JOIN order_items oi
ON o.order_id = oi.order_id
GROUP BY
m.member_id,
m.member_name;SQL B
SELECT
m.member_name,
m.email_address
FROM
members m
WHERE
m.is_premium = 1;(shop 스키마: members에 email_address, is_premium 컬럼 없음)
SQL C
SELECT
category_id,
MAX(price),
product_name
FROM
products
GROUP BY
category_id;SQL D — 요구사항: “신규 회원”
SELECT
*
FROM
members
WHERE
joined_at > '2025-01-01';(“신규”_ 정의가 안 됨 — 강사 의도는 “지난 30일” 이었음)_
SQL E
SELECT
m.member_name,
SUM(p.price * oi.quantity) AS 매출
FROM
members m
LEFT JOIN orders o
ON m.member_id = o.member_id
LEFT JOIN order_items oi
ON o.order_id = oi.order_id
LEFT JOIN products p
ON oi.product_id = p.product_id
GROUP BY
m.member_id,
m.member_name;정답 보기
| SQL | 패턴 | 이유 |
|---|---|---|
| A | 1 (JOIN 뻥튀기) | order_items까지 JOIN 후 COUNT(*) — 한 주문이 N 행으로 부풀려 셈 |
| B | 4 (환각) | shop의 members에는 email_address, is_premium 컬럼이 존재하지 않음. AI가 “있을 거 같으니” 만들어 씀 |
| C | 3 (GROUP BY) | SELECT에 product_name 있는데 GROUP BY에 없음. MySQL 허용하지만 어느 행의 product_name인지 불명 |
| D | 5 (의미 오류) | “신규” 의 정의가 모호. 회사마다 다른 정의. “2025-01-01 이후” 가 “신규” 의미인지 불명 |
| E | 2 (NULL 처리) | 주문 안 한 회원의 매출이 NULL로 나옴. COALESCE(..., 0) 없으면 “매출 NULL” 로 표시됨 — 보는 사람이 0으로 착각 위험 |
문제 2. SQL A와 SQL E — 어떻게 수정?
위 문제 1의 SQL A와 SQL E를 — 패턴을 제거한 올바른 SQL로 수정하세요.
정답 보기
SQL A 수정
-- 옵션 1: order_items 안 JOIN (가장 깔끔)
SELECT
m.member_name,
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;
-- 옵션 2: DISTINCT 로 뻥튀기 제거
SELECT
m.member_name,
COUNT(DISTINCT o.order_id) AS 주문수
FROM
members m
JOIN orders o
ON m.member_id = o.member_id
JOIN order_items oi
ON o.order_id = oi.order_id
GROUP BY
m.member_id,
m.member_name;옵션 1이 의도 명확: “order_items까지 안 가도 주문 수는 셀 수 있다.”
SQL E 수정
SELECT
m.member_name,
COALESCE(SUM(p.price * oi.quantity), 0) AS 매출
FROM
members m
LEFT JOIN orders o
ON m.member_id = o.member_id
LEFT JOIN order_items oi
ON o.order_id = oi.order_id
LEFT JOIN products p
ON oi.product_id = p.product_id
GROUP BY
m.member_id,
m.member_name
ORDER BY
매출 DESC;COALESCE(..., 0) 추가 — NULL을 0으로 명시.
문제 3 (도전). SQL B와 SQL D — AI와 협업으로 보완
SQL B (환각)와 SQL D (의미 오류)는 — SQL 자체를 바꾸는 게 아니라, AI와 다시 협업해서 보완 해야 합니다. 어떤 후속 프롬프트를 보내야 할까요?
정답 보기
SQL B (환각) 보완 프롬프트
방금 만든 SQL 에서 사용한 email_address, is_premium 컬럼이 — 우리 shop 스키마에 없어.
[실제 shop 스키마]
- members: member_id PK, member_name, gender (M/F), age, joined_at
위 스키마만 가지고 — "프리미엄 회원 (= 주문 5건 이상인 회원)" 의 이름을 뽑는 SQL 로 다시 만들어줘.핵심 변경:
- 실제 스키마 명시 (환각 차단)
- “프리미엄” 의 비즈니스 정의 명시 (의미 오류 동시 차단)
SQL D (의미 오류) 보완 프롬프트
"신규 회원" 의 정의를 명확히 했어:
"오늘 기준으로 가입한 지 30일 이내인 회원" (joined_at >= CURDATE() - INTERVAL 30 DAY)
이 정의로 SQL 을 다시 만들어줘.핵심 변경:
- 모호한 단어 (“신규”)의 정의를 명시 — 회사 / 본인 의도 그대로
5 패턴 중 4와 5는 — 후속 프롬프트로 해결.
1, 2, 3은 SQL 수정으로 해결. 진단 패턴에 따라 다른 대응.
5개 SQL을 진단하고 → 고칠 건 고치고 → 프롬프트로 보완할 건 보완까지 했다면 — 이제 5 패턴 중 가장 자주, 가장 크게 사고를 내는 JOIN 뻥튀기를 심화로 파고듭니다.