SQL Practice Logo

SQLPractice Online

Subqueries in WHERE Clause: Mistakes

Module: Subqueries & CTEs

-- NOT IN with NULL - THE TRAP!

SELECT name, email

FROM customers

WHERE customer_id NOT IN (

SELECT customer_id

FROM orders

);

-- If orders.customer_id contains ANY NULL value:

-- Returns ZERO rows!

-- Reason: NULL comparisons are unknown, not false

-- customer_id NOT IN (1, 2, NULL) is unknown for all values

-- Use NOT EXISTS instead

SELECT c.name, c.email

FROM customers c

WHERE NOT EXISTS (

SELECT 1

FROM orders o

WHERE o.customer_id = c.customer_id

);

-- Handles NULL correctly

-- Returns customers without orders

-- Always works as expected

NOT IN fails with NULL because NULL comparisons return unknown (not false). If subquery returns (1, 2, NULL), then "customer_id NOT IN (1, 2, NULL)" evaluates to unknown for all values, filtering out all rows. NOT EXISTS doesn't have this problem - it checks existence, not value comparison.

Never use NOT IN. Always use NOT EXISTS. This is a critical SQL gotcha that causes silent bugs.

Critical

NOT IN returns zero rows when subquery contains NULL

-- IN with large result set - SLOW

SELECT c.name, c.email

FROM customers c

WHERE c.customer_id IN (

SELECT customer_id

FROM orders

);

-- For 50,000 customers with orders:

-- Builds hash table of 50,000 IDs

-- Query time: 450ms

-- Use EXISTS for large datasets

SELECT c.name, c.email

FROM customers c

WHERE EXISTS (