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

6-3 연습 문제 — NULL 진단,
직접 고쳐본 SQL만 머리에 남는다

섹션 6 연습의 정체성 — AI가 만든 잘못된 SQL을 진단하고 직접 수정하기. 이번엔 NULL입니다. COALESCE / IS NULL / COUNT(컬럼) 세 가지 무기로 — 매출이 NULL로 새는 곳, 주문 0건이 1건으로 둔갑하는 곳, 부정 연산자가 회원을 조용히 빠뜨리는 곳을 잡아냅니다.

문제3문제 (도전 1 포함)권장 소요15~20분사용 테이블members · orders · order_items · products준비물DBeaver + AI 과외 선생님 (2-4)

이번 연습의 위치

6-1 ~ 6-2

완료 ✓

6-3 NULL 처리 실수

강의 완료 ✓

6-3 연습 문제

지금 여기

6-4 GROUP BY 단위 오류

집계 단위 함정

6-5 검증 체크리스트 ★

섹션 6 마무리

AI 과외 선생님 활용법

2-4에서 만든 AI 과외 선생님 세션을 그대로 쓰세요. 먼저 혼자 진단해 보고 — 막히면 정답이 아니라 힌트만 요청하세요. 다 푼 뒤에는 본인의 진단과 수정 SQL을 던지며 “내 SQL 검증해줘” 라고 요청하면, NULL 처리가 빠짐없이 됐는지까지 짚어줍니다.

문제 1. LEFT JOIN 매출 NULL

다음 AI SQL — “모든 회원의 매출” 의도. 어디가 잘못됐고 어떻게 수정?

-- ❌ AI 가 만든 SQL
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
ORDER BY
  매출 DESC;

힌트: 황태웅·안소영·류재민·백서윤의 매출 결과는?

정답 보기

진단: 주문 안 한 4 명의 매출이 NULL로 나옴. 0이 아님.

DBeaver — ❌ 잘못된 결과 (MySQL 기준, DESC 정렬의 마지막 4행)
SELECT m.member_name, SUM(p.price * oi.quantity) AS 매출 ... ORDER BY 매출 DESC;
member_name매출
......
황태웅NULL
안소영NULL
류재민NULL
백서윤NULL
20 rows — 주문 안 한 4명의 매출이 0 이 아니라 NULL

문제:

  • ORDER BY 결과에서 NULL 위치 헷갈림 (마지막 또는 처음, DB마다 다름)
  • 보고서에 “매출 NULL” 표시 — 비전공자 “0” 으로 착각 가능
  • 후속 계산 시 NULL이 끼면 결과 NULL

수정:

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;

효과: 황태웅·안소영 등의 매출이 명시적으로 0으로 표시.

문제 2. COUNT 함정

다음 두 SQL — 둘 다 “모든 회원의 주문 수” 의도. 결과가 다릅니다. 어떻게 다르고 어느 게 맞나요?

-- SQL A
SELECT
  m.member_name,
  COUNT(*) AS 주문수
FROM
  members m
LEFT JOIN orders o
  ON m.member_id = o.member_id
GROUP BY
  m.member_id,
  m.member_name;
 
-- SQL B
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;
정답 보기
SQL ASQL B
김철수 (주문 6건)66
황태웅 (주문 0건)10
✕ SQL A — COUNT(*)

결과 행 자체를 셉니다

COUNT(*)는 LEFT JOIN 결과 행 자체를 셈. 황태웅의 경우 members의 1 행 + orders의 NULL = 1 행 → COUNT(*)가 1.

“한 번 주문한 회원” 처럼 잘못 보고.

✓ SQL B — COUNT(o.order_id)

NULL 아닌 행만 셉니다

COUNT(o.order_id)order_id가 NULL 아닌 행만 셈. 황태웅은 o.order_id가 NULL이라 제외 → 0. 이게 정답.

✓ 규칙

“LEFT JOIN 후 자식 데이터 개수 세려면 — COUNT(자식테이블의컬럼) .”

문제 3 (도전). 비교 연산자 + NULL 함정

다음 SQL — “30살 아닌 모든 회원” 의도. 만약 회원 테이블에 age가 NULL인 회원이 있다면 어떻게 될까?

SELECT
  *
FROM
  members
WHERE
  age != 30;

1. age가 NULL인 회원은 결과에 포함될까요? 2. 의도와 다르다면 어떻게 수정? 3. 비슷한 함정이 일어날 수 있는 다른 SQL 패턴 한 개 더 들어보세요.

참고

shop의 members에는 age NULL이 없지만, 실무 DB에선 흔합니다.

정답 보기

1. NULL 회원 결과 포함 여부

❌ 결과에 안 들어옵니다. age = NULL 비교는 UNKNOWN (True 아님) → WHERE가 제외.

언뜻 “30살 아닌” 이면 NULL도 “아닌” 거 같지만 — SQL의 NULL 규칙은 “비교 불가 → 제외”.

2. 수정

SELECT
  *
FROM
  members
WHERE
  age != 30 OR age IS NULL;

OR ... IS NULL 명시 추가.

3. 같은 함정의 다른 SQL 패턴

-- 함정: 활성 회원이 아닌 회원 (= 비활성)
SELECT
  *
FROM
  members
WHERE
  is_active != 1;
-- → is_active 가 NULL 인 회원 누락
-- 함정: NOT IN 절
SELECT
  *
FROM
  members
WHERE
  member_id NOT IN (
    SELECT
      member_id
    FROM
      orders
  );
-- → orders 에 member_id 가 NULL 인 행이 있으면 — 전체 결과가 빈 셋이 됨 (가장 악명 높은 함정)
✓ 일반 규칙

WHERE 절에 !=, <>, NOT IN 같은 “부정” 연산자가 있고, 그 컬럼이 NULL일 가능성 있으면 — NULL 처리 분기를 명시.

매출 NULL → COALESCE, 행 세기 → COUNT(컬럼), 부정 연산자 → IS NULL 분기 — 세 무기를 직접 휘둘러봤다면, 다음은 AI가 가장 그럴듯하게 틀리는 GROUP BY 집계 단위 오류입니다.

NEXT LESSON6-4 GROUP BY 단위 오류

합계는 맞는데 단위가 틀렸다 — 주문 단위 vs 주문상세 단위, AI가 가장 자주 헷갈리는 집계 함정을 진단합니다.

GO ▸ 다음 강의 시작하기