AI 시대 DB 모델링 & SQL 완벽 마스터6-2 연습 문제 ⭐
테크타니 LEARN — 섹션 06 · 연습 문제

6-2 연습 문제 — JOIN 뻥튀기 진단,
잘못된 SQL을 진단하고 고친다

섹션 6 연습의 정체성은 단 하나 — AI가 만든 잘못된 SQL을 진단하고 수정하는 것입니다. 눈으로 읽은 함정은 내일이면 잊히지만, 직접 진단하고 직접 고쳐본 SQL만 머리에 남습니다. 다 풀고 나면 본인 답을 AI 과외 선생님에게 던져 검증까지 받아보세요.

문제3문제 (도전 1 포함)권장 소요20~25분사용 테이블members · orders · order_items · products준비물6-2 수강 완료 + AI 과외 선생님 세션

풀기 전에 — 진단 도구 점검

섹션 3 ~ 5

완료 ✓

6-1 AI 틀리는 패턴 TOP 5

완료 ✓

6-2 JOIN 뻥튀기 심화 ⭐

완료 ✓

6-2 연습 문제

지금 여기

6-3 NULL 처리 실수

다음 마일스톤

이번 강의에서 배운 것 — 이 문제들에 그대로 씁니다
1:N의 N 쪽 JOIN은 행을 곱한다 — SUM·AVG도 같이 뒤틀린다
JOIN 직후 COUNT(*) 검산 — 가장 자식 테이블 행 수와 비교
금액 합계는 반드시 단가 × 수량
주문당 평균(객단가)은 CTE로 주문 총액부터 합치고 나서
검산 SQL까지 AI에게 시키는 협업 습관
AI 과외 선생님 활용법

2-4에서 만든 AI 과외 선생님 세션을 그대로 쓰세요. 막히면 정답이 아니라 힌트만 요청하고 — “정답 말고 힌트만 줘” — 다 푼 뒤에는 본인 진단과 수정 SQL을 던지면서 “내 SQL 검증해줘” 라고 물어보세요. 본인 진단이 맞는지 AI에게 되묻는 메타 학습까지가 이번 연습입니다.

문제 1. SUM 뻥튀기 진단

다음 AI가 만든 SQL은 — “회원별 총 매출” 의도였습니다. 어떤 부풀림이 있는지 진단하고, 수정 SQL을 작성하세요.

-- ❌ AI 가 만든 (잘못된) SQL
SELECT
  m.member_name,
  SUM(p.price) AS 총매출   -- ⚠️ quantity 빠짐
FROM
  members m
JOIN orders o
  ON m.member_id = o.member_id
JOIN order_items oi
  ON o.order_id = oi.order_id
JOIN products p
  ON oi.product_id = p.product_id
GROUP BY
  m.member_id,
  m.member_name;
힌트

컬럼 두 개 — price, quantity — 중 한 개를 누락하거나 곱하지 않으면 어떻게 될까?

정답 보기

진단: SUM(p.price)만 사용. quantity 곱하지 않음.

결과 — 김철수(member_id=1)의 주문 1에 프리미엄 그래놀라(12,000원) 수량 2인 행이 있습니다:

  • SUM(p.price)는 이 행에서 12,000원만 더함 — 진짜 매출은 12,000 × 2 = 24,000원.
  • 주문상세가 전부 수량 1인 회원은 두 값이 우연히 일치 — 한두 명만 보고 검증하면 속습니다.
  • 일반적으로: quantity가 2 이상인 행이 있으면 매출이 적게 계산됨
김철수 행 비교 — 잘못된 SQL vs 수정 SQL
member_nameSUM(price)SUM(price × quantity)
김철수486000498000 ← 진짜 매출
차이 12000 = 그래놀라(12000원) 수량 2 중 1개분 누락 · 단가에 수량을 곱해야 진짜 매출

수정 SQL:

SELECT
  m.member_name,
  SUM(p.price * oi.quantity) 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
JOIN products p
  ON oi.product_id = p.product_id
GROUP BY
  m.member_id,
  m.member_name
ORDER BY
  총매출 DESC;
✕ SUM(p.price)

수량을 무시한 합계

그래놀라를 2개 사도 단가 12,000원이 한 번만 더해집니다. quantity가 2 이상인 행이 있는 회원은 매출이 적게 계산됩니다.

✓ SUM(p.price * oi.quantity)

단가 × 수량의 합

한 주문상세 행의 매출 = 단가 × 수량. 행이 어떻게 펼쳐져 있든, 행마다 정확한 매출을 더합니다.

검산:

-- 김철수의 진짜 총 매출 — 단순 계산
SELECT
  SUM(p.price * oi.quantity)
FROM
  orders o
JOIN order_items oi
  ON o.order_id = oi.order_id
JOIN products p
  ON oi.product_id = p.product_id
WHERE
  o.member_id = 1;
-- → 498000

이 값이 위 수정 SQL의 김철수 행과 일치해야 정상.

문제 2. 평균 객단가 진단 (가장 위험한 패턴)

다음 SQL은 “회원별 평균 객단가” 의도. 어디가 잘못됐는지 진단하고, CTE로 수정하세요.

-- ❌ AI 가 만든 (잘못된) SQL
SELECT
  m.member_name,
  AVG(p.price * oi.quantity) 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
JOIN products p
  ON oi.product_id = p.product_id
GROUP BY
  m.member_id,
  m.member_name;
힌트

한 주문에 상품 3 개 있으면 — AVG가 3 개의 행별 매출 평균을 냄. 그게 “주문당 평균” 이 맞나?

정답 보기

진단: AVG(price × quantity)는 — 주문상세 행별 매출의 평균. 객단가 (= 한 주문당 평균)가 아님.

구체적 예: 김철수의 주문 14는 책 3 권 — SQL 입문서 24,000 + 데이터 모델링 실전 32,000 + AI 시대 개발자 28,000:

  • 진짜 주문 총액 = 84,000 원
  • AI의 평균 = (24000 + 32000 + 28000) / 3 = 28,000 원

3 배 작게 나옴.

김철수 행 비교 — 행별 평균 vs 주문별 평균
member_name잘못된 SQL수정 SQL (CTE)
김철수4980083000 ← 진짜 객단가
잘못된 SQL = 498000 ÷ 10행 / 진짜 = 498000 ÷ 6주문 · 주문 단위로 먼저 합쳐야 진짜 객단가

수정 SQL (CTE):

WITH order_totals AS (
  SELECT
    o.order_id,
    o.member_id,
    SUM(p.price * oi.quantity) AS order_total
  FROM
    orders o
  JOIN order_items oi
    ON o.order_id = oi.order_id
  JOIN products p
    ON oi.product_id = p.product_id
  GROUP BY
    o.order_id,
    o.member_id
)
SELECT
  m.member_name,
  AVG(ot.order_total) AS 평균_객단가
FROM
  members m
JOIN order_totals ot
  ON m.member_id = ot.member_id
GROUP BY
  m.member_id,
  m.member_name
ORDER BY
  평균_객단가 DESC;

단계:

  1. 주문별 총액 (CTE order_totals) — order_items 행 N 개를 1 행으로 합침.
  2. 그 다음 회원별 — 주문 총액들의 평균.
✕ 행별 평균

펼쳐진 행에 AVG를 바로

한 주문이 상품 수만큼 행으로 펼쳐진 상태에서 AVG주문상세 행별 매출의 평균이 나옵니다. 김철수는 49,800원 — 진짜 객단가의 60% 수준.

✓ 주문별 합 → 평균

CTE로 주문 총액부터

먼저 주문별 총액으로 합치고(행 N 개 → 1 행), 그 총액들의 평균 — 김철수 83,000원. 객단가의 정의 그대로입니다.

검산: 김철수 주문 6 건의 진짜 객단가 평균을 손으로 계산해서 (또는 단순 SQL로) 비교 → 498,000 ÷ 6 = 83,000 원.

문제 3 (도전). AI와 검산 협업 — 실시연

6-2 본문의 모범 SQL (회원별 총 매출)을 실제로 AI에게 던지고 — 그 결과를 검산하는 후속 메시지까지 진행하세요.

AI에 SQL 요청01 / 04

shop 정리본(테이블 + 관계)과 요구사항을 함께 보냅니다. 회원별 총 매출 — price × quantity 합, 매출 많은 순.

아래 메시지 ①을 AI 과외 선생님 세션에 전송
받은 SQL을 DBeaver에서 실행02 / 04

그럴듯한 결과가 나옵니다. 여기서 끝내면 6-1 이전의 나 — 검산 전까지는 가설일 뿐입니다.

결과를 눈으로 확인 — 아직 믿지 않기
검산 후속 메시지03 / 04

행 수 검산 SQL과 단순 집계 SQL — 검산 SQL까지 AI에게 시키는 것이 이 문제의 핵심입니다.

아래 메시지 ②를 같은 세션에 전송
검산 SQL 실행 → 비교04 / 04

AI가 만든 검산 SQL들도 DBeaver에서 실행하고, 메인 쿼리의 값과 일치하는지 비교합니다.

메인 SQL의 결과와 대조

보낼 메시지 ① — SQL 요청:

[테이블 + 관계] (shop 정리본)

[요구사항]
회원별 총 매출 (price × quantity 합). 매출 많은 순.

보낼 메시지 ② — 검산 요청:

방금 SQL 의 결과를 검산하고 싶어:

1. 이 JOIN 결과의 총 행 수가 — order_items (64 행) 과 같은지 확인하는 SQL.

2. 김철수 (member_id=1) 의 *진짜 매출* 을 — 단순 한 줄 SQL 로 구해줘.

이 두 결과를 메인 쿼리와 비교해서 부풀림이 없는지 점검할 거야.
자가 평가 — 셋 다 체크되면 합격
AI가 단계 1 (행 수 검산) SQL을 만들었나? → 64가 나와야 정상
AI가 단계 3 (단순 집계) SQL을 만들었나? → 김철수의 매출 단일 값
단순 SQL 값 = 메인 SQL의 김철수 행 매출? → 일치하면 메인 SQL 정상
가이드

기대되는 AI 응답:

-- 1. JOIN 결과 행 수
SELECT
  COUNT(*)
FROM
  members m
JOIN orders o
  ON m.member_id = o.member_id
JOIN order_items oi
  ON o.order_id = oi.order_id
JOIN products p
  ON oi.product_id = p.product_id;
-- → 64 ✓
 
-- 2. 김철수 매출
SELECT
  SUM(p.price * oi.quantity) AS 김철수_매출
FROM
  orders o
JOIN order_items oi
  ON o.order_id = oi.order_id
JOIN products p
  ON oi.product_id = p.product_id
WHERE
  o.member_id = 1;
-- → 498000
검산 결과 ① — JOIN 결과 행 수
COUNT(*)
64 ← order_items 행 수와 동일
검산 결과 ② — 김철수 매출
김철수_매출
498000 ← 메인 SQL 의 김철수 행과 일치
둘 다 통과 — 메인 SQL 에 뻥튀기 없음

검산 결과 일치 확인:

  • 메인 SQL의 김철수 행 매출 == 단순 SQL 결과 → ✓ 정상
  • 일치 안 하면 → 메인 SQL의 JOIN 또는 집계에 뻥튀기.
핵심 인사이트

AI한테 “검산도 시킨다” — 본인이 짜는 시간보다 훨씬 빠르고 정확. AI 협업 검증의 진수.

세 문제 모두 진단 → 수정 → 검산까지 직접 해봤다면, AI가 만든 SQL 앞에서 가장 비싼 사고를 미리 겪고 백신까지 맞은 셈입니다. 다음 단골 함정은 — 0도 아니고 빈 문자열도 아닌, NULL입니다.

NEXT LESSON6-3 NULL 처리 실수

0과 NULL은 다릅니다 — AI가 조용히 틀리는 NULL의 함정을 잡아냅니다.

GO ▸ 다음 강의 시작하기