Subqueries in WHERE: IN, NOT IN, ANY, ALL
Filter rows against a list returned by a subquery with IN, NOT IN, ANY and ALL — and avoid the NOT IN + NULL trap.
A scalar subquery returns one value, so a simple > or = works. But often the inner query returns a list — for example, the ids of every Orange Cap winner. To compare one value against a whole list, SQL gives you IN, NOT IN, ANY and ALL.
For these examples we use a small extra table:
sql
CREATE TABLE orange_cap (player_id INT, season INT);
INSERT INTO orange_cap VALUES (1, 2024), (3, 2022); -- Kohli and Buttler(The playground examples below create it for you in their setup.)
Definition
IN returns TRUE when the value equals at least one value in the subquery's list. NOT IN returns TRUE when the value equals none of the values in the list. ANY (same as SOME) returns TRUE when the comparison is true for at least one value in the list. ALL returns TRUE when the comparison is true for every value in the list.
The subquery for all four must return exactly one column (a list). ANY and ALL are always combined with a comparison operator: > ANY, < ALL, = ANY and so on.
Syntax
sql
SELECT columns
FROM table_a
WHERE column_name IN (SELECT one_column FROM table_b);
-- or NOT IN (…)
-- or > ANY (…) = ANY is the same as IN
-- or > ALL (…) <> ALL is the same as NOT IN| Operator | Meaning | Easy way to remember |
|---|---|---|
= / > / < … (scalar) | compare with one value | the subquery must return 1 row |
IN (list) | value is in the list | many = joined with OR |
NOT IN (list) | value is not in the list | many <> joined with AND |
> ANY (list) | bigger than at least one | bigger than the minimum |
> ALL (list) | bigger than every one | bigger than the maximum |
Example — IN: Orange Cap winners
sql
SELECT id, name, runs
FROM players
WHERE id IN (SELECT player_id FROM orange_cap);| id | name | runs |
|---|---|---|
| 1 | Virat Kohli | 750 |
| 3 | Jos Buttler | 850 |
How it works: the inner query returns the list (1, 3). The outer query keeps a player when its id is in that list.
Example — NOT IN: everyone else
sql
SELECT id, name, runs
FROM players
WHERE id NOT IN (SELECT player_id FROM orange_cap);| id | name | runs |
|---|---|---|
| 2 | Rohit Sharma | 500 |
| 4 | MS Dhoni | 350 |
| 5 | David Warner | 700 |
| 6 | Jasprit Bumrah | 20 |
The NOT IN + NULL trap ⚠️
If the subquery list contains even one NULL, NOT IN returns no rows at all.
Why? id NOT IN (1, 3, NULL) means id <> 1 AND id <> 3 AND id <> NULL. Any comparison with NULL is UNKNOWN, and TRUE AND UNKNOWN is UNKNOWN — so WHERE never sees TRUE. The fix is either filtering NULLs out of the subquery or using NOT EXISTS (next topic):
sql
WHERE id NOT IN (SELECT player_id FROM orange_cap WHERE player_id IS NOT NULL)Example — ALL: better than every MI player
sql
SELECT id, name, runs
FROM players
WHERE runs > ALL (SELECT runs FROM players WHERE team = 'MI');| id | name | runs |
|---|---|---|
| 1 | Virat Kohli | 750 |
| 3 | Jos Buttler | 850 |
| 5 | David Warner | 700 |
MI runs are 500 and 20. > ALL means bigger than both, i.e. bigger than the maximum (500).
Example — ANY: better than at least one MI player
sql
SELECT id, name, runs
FROM players
WHERE runs > ANY (SELECT runs FROM players WHERE team = 'MI');| id | name | runs |
|---|---|---|
| 1 | Virat Kohli | 750 |
| 2 | Rohit Sharma | 500 |
| 3 | Jos Buttler | 850 |
| 4 | MS Dhoni | 350 |
| 5 | David Warner | 700 |
> ANY means bigger than at least one of (500, 20), i.e. bigger than the minimum (20). Only Bumrah (20) is not bigger than 20.
Note: The playground (SQLite) does not support
ANY/ALL. Their exact equivalents withMAX/MINrun everywhere:> ALL (…)≈> (SELECT MAX(…))and> ANY (…)≈> (SELECT MIN(…))(when the list is non-empty and has no NULLs).
Common mistakes
- ❌
WHERE id = (SELECT player_id FROM orange_cap)→ the subquery returns 2 rows; SQL Server errors. ✅WHERE id IN (…). - ❌
NOT INover a column that can contain NULL → silently returns 0 rows. ✅ addWHERE col IS NOT NULLinside, or useNOT EXISTS. - ❌
WHERE id IN (SELECT player_id, season FROM orange_cap)→ two columns. ✅ return exactly one column. - ❌ Thinking
> ANYmeans "bigger than all". ✅ ANY = at least one (minimum); ALL = every one (maximum). - Edge case: if the subquery returns no rows,
> ALLis TRUE for every row and> ANYis FALSE for every row.
Interview tip
Q: Why might NOT IN return no rows when you clearly expect some?
Because the subquery returned a NULL. x NOT IN (…, NULL) can never be TRUE, since x <> NULL is UNKNOWN. Use NOT EXISTS or filter out NULLs.
Key points to remember
- IN keeps a row when its value matches at least one value in the subquery list.
- NOT IN keeps a row when its value matches none of the values in the list.
- If the NOT IN list contains a NULL, NOT IN returns no rows at all — use NOT EXISTS or filter NULLs.
- > ALL means greater than every value (the maximum); > ANY means greater than at least one (the minimum).
- = ANY is the same as IN; <> ALL is the same as NOT IN; SOME is a synonym for ANY.
- IN / ANY / ALL subqueries must return exactly one column.
Try it yourself
IN and NOT IN with orange_cap
This example runs a small setup step first — click to see it
CREATE TABLE orange_cap (player_id INT, season INT); INSERT INTO orange_cap VALUES (1, 2024), (3, 2022);
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
See the NOT IN + NULL trap
This example runs a small setup step first — click to see it
CREATE TABLE orange_cap (player_id INT, season INT); INSERT INTO orange_cap VALUES (1, 2024), (3, 2022);
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
ANY and ALL (SQL Server syntax)
-- Better than EVERY MI player (> 500)
SELECT id, name, runs
FROM players
WHERE runs > ALL (SELECT runs FROM players WHERE team = 'MI');
-- Kohli 750, Buttler 850, Warner 700
-- Better than AT LEAST ONE MI player (> 20)
SELECT id, name, runs
FROM players
WHERE runs > ANY (SELECT runs FROM players WHERE team = 'MI');
-- Kohli, Rohit, Buttler, Dhoni, WarnerSQL Server-specific — run this in SQL Server (SSMS / Azure Data Studio).
Try it: same idea in the playground (MAX / MIN)
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Practice: players from teams based in Mumbai or Chennai
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Revision Flashcards
Tap a card to flip it and see the answer.
