BAD: 0 rows(5건 누락)
NULL 포함 NOT IN 사용
SELECT c.base_dt
FROM startdbpg.cm_base_dt c
WHERE c.base_dt BETWEEN '2025-01-23' AND '2025-01-30'
AND c.base_dt NOT IN (
SELECT o.pkup_dtm::date
FROM startdbpg.tr_ord_big o
)
ORDER BY c.base_dt
;
SQL
복사
SQL 결과 보기
•
아직 픽업하지 않은 주문은 pkup_dtm이 NULL입니다.
•
x NOT IN (1, 2, NULL)은 x <> 1 AND x <> 2 AND x <> NULL과 같습니다. x <> NULL은 절대 참이 되지 않으므로, NULL이 하나라도 있으면 결과는 0건입니다.
•
지금은 맞게 나오던 SQL도, 데이터에 NULL이 하나 생기는 순간 0건이 됩니다.
GOOD: 5 rows(정상)
① NOT EXISTS 등으로 제외 조건 처리
SELECT c.base_dt
FROM startdbpg.cm_base_dt c
WHERE c.base_dt BETWEEN '2025-01-23' AND '2025-01-30'
AND NOT EXISTS(
SELECT o.pkup_dtm::date
FROM startdbpg.tr_ord_big o
WHERE o.pkup_dtm >= c.base_dt
AND o.pkup_dtm < c.base_dt + interval '1' day
-- 성능을 위해 전체 조회 범위를 한 번 더 지정
AND o.pkup_dtm >= '2025-01-23'
AND o.pkup_dtm < '2025-01-30'::DATE + interval '1' day
)
ORDER BY c.base_dt
;
SQL
복사
SQL 결과 보기
② EXCEPT 방식
SELECT c.base_dt
FROM startdbpg.cm_base_dt c
WHERE c.base_dt BETWEEN '2025-01-23' AND '2025-01-30'
EXCEPT
SELECT DISTINCT o.pkup_dtm::date
FROM startdbpg.tr_ord_big o
WHERE o.pkup_dtm >= '2025-01-23'
AND o.pkup_dtm < '2025-01-30'::DATE + interval '1' day
ORDER BY 1
;
SQL
복사
SQL 결과 보기
•
NULL 결과가 포함된 서브쿼리는 NOT EXISTS 또는 EXCEPT로 처리합니다.
•
①의 서브쿼리 아래 두 줄(전체 조회 범위)은 결과에는 영향이 없고, 성능을 위해 추가한 조건입니다.
KEY POINT
•
NOT IN 서브쿼리에 NULL이 하나라도 있으면 결과는 0건입니다.
•
제외 조건은 NOT EXISTS로 씁니다. 차집합이 필요하면 EXCEPT를 씁니다.
•
NULL이 들어올 수 있는 컬럼이면, 지금 결과가 맞아도 NOT IN을 쓰지 않습니다.
TIP. NOT IN을 꼭 써야 한다면
•
서브쿼리에 WHERE o.pkup_dtm IS NOT NULL을 넣어 NULL을 제외합니다.
•
다만 빠뜨리기 쉬우니, 제외 조건은 NOT EXISTS를 기본으로 씁니다.



