6-3 연습 문제 — NULL 진단,
직접 고쳐본 SQL만 머리에 남는다
섹션 6 연습의 정체성 — AI가 만든 잘못된 SQL을 진단하고 직접 수정하기. 이번엔 NULL입니다. COALESCE / IS NULL / COUNT(컬럼) 세 가지 무기로 — 매출이 NULL로 새는 곳, 주문 0건이 1건으로 둔갑하는 곳, 부정 연산자가 회원을 조용히 빠뜨리는 곳을 잡아냅니다.
이번 연습의 위치
완료 ✓
강의 완료 ✓
지금 여기
집계 단위 함정
섹션 6 마무리
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이 아님.
| member_name | 매출 |
|---|---|
| ... | ... |
| 황태웅 | NULL |
| 안소영 | NULL |
| 류재민 | NULL |
| 백서윤 | 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 A | SQL B | |
|---|---|---|
| 김철수 (주문 6건) | 6 | 6 |
| 황태웅 (주문 0건) | 1 ❌ | 0 ✓ |
결과 행 자체를 셉니다
COUNT(*)는 LEFT JOIN 결과 행 자체를 셈. 황태웅의 경우
members의 1 행 + orders의 NULL = 1 행 →
COUNT(*)가 1.
“한 번 주문한 회원” 처럼 잘못 보고.
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 집계 단위 오류입니다.