advanced
EXISTS and NOT EXISTS
Test whether a subquery returns any rows — a fast, set-based way to filter.
6 min read
Explanation
EXISTS checks whether a subquery returns at least one row. It doesn't care
about the values — only whether any row exists. That makes it ideal for
"find rows that have (or don't have) a related row somewhere else" questions.
NOT EXISTS is the negative form: "find rows where no related row exists."
Crucially, EXISTS is correlated — the subquery references the outer query
and is evaluated per outer row, stopping as soon as it finds a match.
EXISTS ignores the SELECT list
Write SELECT 1 or SELECT * inside EXISTS — the columns don't matter, only
the presence of a row does.
Syntax
SELECT col
FROM table_a a
WHERE EXISTS (
SELECT 1 FROM table_b b WHERE b.key = a.key
);Interactive Example
Find customers who have placed at least one order. Then find customers who have
not placed any order using NOT EXISTS.
Loading database engine...
Loading database engine...
Common Mistakes
- Using
=with EXISTS. EXISTS is a boolean test, not a value — never writeWHERE x = EXISTS (...). - Reaching for NOT IN with NULLs.
NOT IN (subquery)returns nothing if the subquery has a NULL; preferNOT EXISTS. - Selecting heavy columns inside EXISTS. It's wasted work;
SELECT 1is the convention.
Best Practices
- Use
EXISTSfor "has related rows" checks against large tables. - Prefer
NOT EXISTSoverNOT INto avoid NULL pitfalls. - Add the join condition (
b.key = a.key) so the subquery is properly correlated.
Practice Question
Using EXISTS, list products (products table) that have never been ordered —
i.e. no orders row references that product_id.
Summary
EXISTS returns true if a correlated subquery yields any row, making it a fast,
NULL-safe way to test relationships. NOT EXISTS is the reliable choice for
"does not appear" conditions.