게임 아이템 업그레이드 구조를 다루는 실전 예제를 통해 NOT IN 문법과, 그에 숨겨진 위험 요소인 NULL 이슈를 확실히 정리한다.
게임에는 아이템 업그레이드 트리가 존재한다. 아래는 업그레이드 관계의 예시다:
ITEM_A → ITEM_B → ITEM_D
↘ ITEM_C
ITEM_D, ITEM_C는 더 이상 업그레이드가 불가능한 아이템이다.ITEM_INFO
| ITEM_ID | ITEM_NAME | RARITY | PRICE |
|---|---|---|---|
| 0 | ITEM_A | RARE | 10000 |
| 1 | ITEM_B | RARE | 9000 |
| 2 | ITEM_C | LEGEND | 11000 |
| 3 | ITEM_D | RARE | 10000 |
| 4 | ITEM_E | RARE | 12000 |
ITEM_TREE
| ITEM_ID | PARENT_ITEM_ID |
|---|---|
| 0 | NULL |
| 1 | 0 |
| 2 | 0 |
| 3 | 1 |
| 4 | 1 |
SELECT
ITEM_ID,
ITEM_NAME,
RARITY
FROM ITEM_INFO
WHERE ITEM_ID NOT IN (
SELECT DISTINCT PARENT_ITEM_ID
FROM ITEM_TREE
WHERE PARENT_ITEM_ID IS NOT NULL
)
ORDER BY ITEM_ID DESC;
PARENT_ITEM_ID로 등장한 ITEM은 업그레이드 가능한 "부모 아이템"이다.ITEM_ID NOT IN (...) 조건을 통해, 이 목록에 포함되지 않은 아이템만 걸러낸다.IS NOT NULL 조건은 꼭 필요하다. 이유는 아래에서 설명한다.NOT IN과 NULL의 함정NOT IN 서브쿼리 결과에 NULL이 하나라도 포함되면 전체 비교가 UNKNOWN이 되어버린다.
SELECT 1
WHERE 5 NOT IN (1, 2, NULL); -- 결과 없음 (UNKNOWN)
SQL에서는 WHERE 조건이 TRUE일 때만 결과가 반환되며, UNKNOWN은 제외된다.
즉, NULL이 껴 있는 순간 NOT IN 조건은 절대 TRUE가 될 수 없으며, 모든 행이 필터된다.
WHERE ITEM_ID NOT IN (
SELECT PARENT_ITEM_ID
FROM ITEM_TREE
WHERE PARENT_ITEM_ID IS NOT NULL
)
IS NOT NULL 조건을 통해 NULL 값을 제거한 후 NOT IN을 사용해야 정확하게 동작한다.
NOT IN은 간단한 문법처럼 보이지만, NULL 하나로 전부 무력화될 수 있다.NULL 가능성이 있다면 반드시 IS NOT NULL을 함께 사용해야 한다.| 상황 | 처리 방식 |
|---|---|
NOT IN + NULL 가능성 있음 | WHERE ... IS NOT NULL로 제거 |
IN만 사용할 때 | NULL 영향 없음 |
| JOIN으로 우회 가능 여부 | 경우에 따라 LEFT JOIN으로 가능 |
🔚 NOT IN은 작지만 위험한 문법이다.
NULL을 제대로 처리하지 않으면, 원하지 않는 결과가 나올 수 있다.
실전에서는 반드시 IS NOT NULL을 붙여서 안전하게 사용하는 습관을 들여야 한다. 💥