AI 시대 DB 모델링 & SQL 완벽 마스터6-1 AI 틀리는 패턴 TOP 5
테크타니 LEARN — 섹션 06 · AI 결과 의심하기 ★

AI가 짠 SQL을 받는 순간,
제일 먼저 의심할 5가지

드디어 섹션 6 — 강의 소개에서 "화룡점정"이라고 했던 그 섹션입니다. 모델링도 알았고, AI에게 SQL을 잘 시키는 법도 배웠죠. 이게 다 끝일까요? 아닙니다. 진짜 AI 시대의 실무 역량은 따로 있습니다 — AI가 짠 SQL을 의심할 줄 아는 것. 오늘은 AI가 가장 자주 빠지는 함정 5가지를 한 장의 지도로 머릿속에 넣습니다.

난이도보통소요5–6분준비물섹션 3~5 완료오늘의 산출물5가지 패턴 의심 지도

이번 섹션의 여정

섹션 4에서 구조를 읽는 눈을, 섹션 5에서 AI에게 잘 시키는 법을 챙겼습니다. 마지막 한 기둥이 남았어요 — AI의 결과를 의심하고 검증하는 능력. 섹션 6은 5개 강의로 이 능력을 만듭니다. 오늘 5가지 패턴을 전부 훑고, 다음 강의들에서 하나씩 깊게 잡고, 마지막엔 일부러 틀린 SQL을 함께 디버깅하는 실습까지 갑니다.

섹션 1 ~ 5

완료 ✓

6-1 틀리는 패턴 TOP 5

지금 여기

6-2 JOIN 뻥튀기 심화

빈도 1위 ⭐

6-3 ~ 6-4

NULL · GROUP BY

6-5 검증 체크리스트 ★

+ 디버깅 실습

섹션 7 — 마무리

실무 가이드

★ 섹션 6의 한 문장

진짜 AI 시대의 실무 역량은 — “AI가 짠 SQL을 의심할 줄 아는 것.” 여기서 실력이 갈립니다.

다섯 가지 함정, 한눈에

좋은 소식부터 — AI가 SQL을 만들 때 빠지는 함정은 무한하지 않습니다. 실무에서 마주치는 건 사실상 이 5가지의 변주예요. 받자마자 이 지도를 머릿속에 띄우는 게 오늘의 목표입니다.

의심 지도 — AI가 자주 빠지는 함정 TOP 5
AI 가 만든 SQL — 받자마자 여기부터 의심
├─ ① JOIN 으로 행 뻥튀기 → 6-2 에서 심화 ⭐
├─ ② NULL 처리 빠뜨림 → 6-3 에서 심화
├─ ③ GROUP BY 단위 오류 → 6-4 에서 심화
├─ ④ 컬럼·테이블명 환각 → 오늘 여기서 끝
└─ ⑤ 비즈니스 의미 해석 오류 → 오늘 여기서 끝

①②③은 SQL 자체의 함정이라 강의 한 편씩 잡고 깊게 들어가고, ④⑤는 오늘 이 자리에서 끝을 봅니다.

이 함정들이 위험한 진짜 이유

에러가 나면 차라리 다행입니다. 5가지 중 ④를 뺀 나머지는 에러 없이 그럴듯한 결과를 돌려줘요 — 검증 습관이 없으면 틀린 숫자가 그대로 보고서에 올라갑니다.

패턴 1 — JOIN 으로 행 뻥튀기

3-7에서 우리가 직접 빠져봤던 그 함정 — AI도 똑같이 빠집니다. “회원별 주문 건수를 구해줘” 라고 했더니 AI가 이런 SQL을 줬다고 해볼게요.

-- ❌ AI 가 만든 SQL — 어디가 문제일까요?
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;

주문 건수만 필요한데 order_items까지 JOIN했습니다. 한 주문이 주문상세 개수만큼 여러 행으로 불어나고, COUNT(*)는 그 불어난 행을 셉니다.

DBeaver — 회원별 주문 건수…?
member_name주문수
김철수10 ← 실제 주문은 6건
이영희6 ← 실제 주문은 4건
에러는 없다. 숫자도 그럴듯하다. 그런데 전부 부풀려져 있다.

잡는 법 — 결과를 받자마자 COUNT(*) 검산. JOIN 결과의 행 수가 “가장 자식 테이블” 의 행 수와 같은지부터 확인합니다. (우리 DB라면 order_items 64행.)

6-2에서 끝까지 잡습니다

가장 빈도가 높은 패턴이라 다음 강의 한 편을 통째로 씁니다 — 뻥튀기가 일어나는 원리부터 검산하고 고치는 법까지.

패턴 2 — NULL 처리 빠뜨림

“회원별 매출 합계를 구해줘. 주문 없는 회원도 포함해서.” — AI가 LEFT JOIN까지는 잘 씁니다. 문제는 그다음이에요.

-- ❌ AI 가 만든 SQL — LEFT JOIN 까지는 좋았는데
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;
DBeaver — 회원별 매출 합계
member_name매출
김철수498000
황태웅NULL
안소영NULL
류재민NULL
백서윤NULL
주문이 없는 회원 4명 — 매출이 0 이 아니라 NULL 로 나온다

문제 — 주문 안 한 회원의 매출이 NULL입니다. “0원” 이 아니에요. NULL은 “값이 없음” 인데, 보고서를 받는 사람이 0으로 착각하는 순간 사고가 됩니다.

잡는 법COALESCE(SUM(...), 0) 으로 NULL을 0으로 명시합니다. 그리고 결과에 NULL이 보이면 “이게 0이라는 뜻인지, 모른다는 뜻인지” 를 꼭 확인하세요.

6-3에서 끝까지 잡습니다

NULL vs 0 vs ‘없음’ — 셋의 차이와 COALESCE, IS NULL 사용법을 6-3에서 깊게 다룹니다.

패턴 3 — GROUP BY 누락 · 잘못된 집계 단위

-- ❌ AI 가 만든 SQL — SELECT 와 GROUP BY 가 안 맞음
SELECT
  p.category_id,
  o.member_id,
  COUNT(*) 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
GROUP BY
  p.category_id;   -- ⚠️ member_id 가 빠졌다

문제 — SELECT에는 member_id가 있는데 GROUP BY에는 category_id뿐. 한 카테고리에는 여러 회원의 주문이 섞여 있을 텐데, 그중 누구의 member_id가 나올지 아무도 모릅니다. 설정에 따라 MySQL이 이걸 허용하기도 하는데 — 그러면 아무 값이나 조용히 나옵니다. 사고죠.

잡는 법 — 공식 하나면 됩니다. GROUP BY 컬럼 = SELECT의 모든 비집계 컬럼. 받은 SQL에서 둘을 대조만 해도 잡힙니다.

6-4에서 끝까지 잡습니다

MySQL 8의 기본 설정(ONLY_FULL_GROUP_BY)은 이런 SQL을 에러로 막아주지만, 이 설정이 꺼진 서버가 실무에 아직 많습니다. 집계 단위 감각은 6-4에서 제대로 만듭니다.

패턴 4 — 컬럼·테이블명 환각 (hallucination)

이번엔 SQL 문법이 아니라 프롬프트의 함정입니다. AI가 우리 스키마에 없는 컬럼을 “있을 것 같으니까” 그냥 지어내는 현상 — 환각(hallucination) 이에요.

-- ❌ AI 가 만든 SQL — 그럴듯하지만, 존재하지 않는 컬럼들
SELECT
  m.member_name,
  m.email,
  m.phone     -- ⚠️ members 에 email, phone 없음!
FROM
  members m
WHERE
  m.last_login_at > '2025-01-01';      -- ⚠️ last_login_at 도 없음!

세상의 ‘보통 쇼핑몰’ 회원 테이블에는 이메일이 있으니까, 우리 members에도 있을 거라고 추측한 겁니다. 하지만 우리 members의 컬럼은 member_id, member_name, gender, age, joined_at — 다섯 개가 전부예요.

DBeaver — 실행하면 바로 들통
SELECT
m.member_name,
m.email,
m.phone
FROM
members m
WHERE
m.last_login_at > '2025-01-01';
 
SQL Error [1054] [42S22]: Unknown column 'm.email' in 'field list'
 
에러가 나면 차라리 다행 — 환각 확정, 그 자리에서 잡았다

잡는 법은 3단계 — 사실 1단계에서 거의 끝납니다.

스키마를 항상 같이 주기01 / 03

환각의 가장 흔한 원인은 스키마를 안 줬을 때입니다. 5-1·5-2에서 배운 대로 스키마를 매번 같이 주면 환각이 거의 사라집니다.

5-1 · 5-2 의 프롬프트 포맷 그대로
컬럼·테이블명 대조02 / 03

받은 SQL에 등장하는 컬럼·테이블이 실제 스키마에 다 있는지 눈으로 점검합니다.

받은 SQL ↔ 실제 스키마
DBeaver 에서 실행03 / 03

실행해서 컬럼 에러가 나면 환각 확정 — 다섯 패턴 중 유일하게 에러로 즉시 잡히는 고마운 패턴입니다.

Unknown column 에러 = 환각 확정
스키마를 줬는데도 환각이 나온다면

대화가 길어져 AI의 파일 기억이 흐려진 신호입니다. 2-4의 규칙 그대로 — 새 대화 + init.sql 재첨부.

패턴 5 — 비즈니스 의미 해석 오류 ⭐

마지막 패턴은 결이 다릅니다. 이건 AI가 절대 못 잡는 영역 — 사람의 일이에요.

마케팅팀에서 “활성 사용자 분석해줘” 라는 요청이 왔다고 해볼게요. 그대로 AI에게 전달하면 —

✕ 모호한 단어 그대로

”활성 사용자 분석해줘”

AI의 해석은 “지난 7일 안에 로그인한 사용자”. 그런데 우리 회사의 정의는 “지난 30일 안에 주문한 사용자”. 같은 단어, 다른 의미 — SQL은 정확하게 돌아가는데 결과는 비즈니스 의도와 어긋납니다.

✓ 본인 정의로 구체화해서

”활성 = 지난 30일 안에 주문한 사용자”

정의를 먼저 못박고, 조건까지 같이 전달합니다 — orders.ordered_at >= NOW() - INTERVAL 30 DAY. AI가 해석할 여지를 없애는 것이 핵심입니다.

잡는 법 — 요청 문장에 모호한 단어가 보이면 멈추세요. “활성”, “인기”, “최근”, “VIP”, “잘 팔리는” — 전부 본인 회사의 정의로 먼저 구체화한 뒤 AI에게 전달합니다. 5-3“모호한 단어 → 구체화” 원칙과 정확히 같은 메시지예요.

⭐ 여기가 사람의 가치

SQL 함정은 검증으로, 프롬프트 함정은 컨텍스트로 잡지만 — 비즈니스 의미는 그 회사를 아는 사람만 잡을 수 있습니다.

한 표 요약 — 캡처해 두세요

#패턴1줄 정체잡는 법심화
JOIN 뻥튀기N:M JOIN 으로 행이 곱해짐COUNT(*) 검산6-2
NULLNULL vs 0 vs 없음 혼동COALESCE, IS NULL6-3
GROUP BY집계 단위 불일치GROUP BY = SELECT 비집계 컬럼6-4
환각없는 컬럼을 지어냄스키마 항상 명시오늘 완료 ✓
의미 오류모호한 단어를 멋대로 해석본인 정의로 구체화오늘 완료 ✓
함정의 세 갈래

①②③은 SQL의 함정 — 검증으로 잡고, ④는 프롬프트의 함정 — 컨텍스트로 막고, ⑤는 비즈니스의 함정 — 사람만 잡습니다.

다 외울 필요 없습니다

①②③의 검산법은 6-2 ~ 6-4에서 손으로 직접 잡아보고, 6-5에서 체크리스트 한 장으로 정리해 드립니다. 오늘은 이 지도만 머리에 넣으면 충분해요.

다음 강의는 빈도 1위 — 6-2 JOIN 뻥튀기 심화입니다. 그 전에, 방금 본 5가지 패턴을 보는 눈이 생겼는지 연습 문제로 점검하고 가세요.

NEXT LESSON6-1 연습 문제

틀린 SQL을 보고 — 5가지 중 어떤 패턴인지 짚어내는 눈을 테스트합니다.

GO ▸ 연습 문제 풀기