SQL WHERE IN: Filter by a List of Values
IN checks whether a column's value is one of a list of values. WHERE status IN ('shipped', 'delivered') means the same as two conditions joined with OR, but stays short and readable however long the list gets. NOT IN keeps the rows that match none of them.
What Does IN Do?
Employees in three departments:
SELECT first_name, last_name, department
FROM employees
WHERE department IN ('Design', 'Legal', 'Product')
ORDER BY department, last_name
LIMIT 8;
▶ Run this query in the SQL Playground
| first_name | last_name | department |
|---|---|---|
| Joshua | Hall | Design |
| Sandra | Lewis | Design |
| Jason | Mitchell | Design |
| Amy | Nguyen | Design |
| Paul | Thomas | Design |
| Ashley | Thomas | Design |
| Michael | Walker | Design |
| Ashley | White | Design |
WHERE column IN (value_1, value_2, ...)
WHERE column NOT IN (value_1, value_2, ...)
WHERE column IN (SELECT column FROM ...)
Values are separated by commas inside round brackets. Text values need single quotes; numbers do not.
IN Is a Shorter OR
These two filters return the same rows:
SELECT (SELECT COUNT(*) FROM employees
WHERE department IN ('Design', 'Legal', 'Product')) AS with_in,
(SELECT COUNT(*) FROM employees
WHERE department = 'Design' OR department = 'Legal' OR department = 'Product') AS with_or;
▶ Run this query in the SQL Playground
| with_in | with_or |
|---|---|
| 35 | 35 |
Use IN whenever you would otherwise repeat column = ... OR column = .... Adding a value is then just adding a comma. For different columns, such as department = 'Sales' OR salary > 190000, you still need OR.
Performance is the same: databases treat both forms alike. For very long lists, thousands of values, a join to a table of those values or a subquery is usually easier to maintain and can be faster.
IN With Numbers and Text
Numbers
SELECT id, user_id, status, total
FROM orders
WHERE user_id IN (4, 77, 118)
ORDER BY user_id, id;
▶ Run this query in the SQL Playground
| id | user_id | status | total |
|---|---|---|---|
| 11 | 4 | processing | 1518.36 |
| 87 | 4 | delivered | 2501.23 |
| 181 | 4 | shipped | 843.7 |
| 24 | 77 | processing | 4595.72 |
| 99 | 77 | processing | 3268.65 |
| 110 | 77 | delivered | 345.48 |
| 164 | 77 | delivered | 4770.01 |
| 184 | 77 | cancelled | 1613.31 |
| 80 | 118 | cancelled | 2112.87 |
| 90 | 118 | pending | 3500.01 |
Text
SELECT category, COUNT(*) AS products
FROM products
WHERE category IN ('Books', 'Electronics', 'Toys')
GROUP BY category
ORDER BY category;
▶ Run this query in the SQL Playground
| category | products |
|---|---|
| Books | 16 |
| Electronics | 7 |
| Toys | 12 |
Text must match exactly, including spaces. Whether case matters depends on the database: SQLite and PostgreSQL compare with case ('books' does not match 'Books'), MySQL and SQL Server usually do not.
NOT IN and the NULL Trap
NOT IN keeps the rows whose value is in none of the list:
SELECT status, COUNT(*) AS orders
FROM orders
WHERE status NOT IN ('cancelled', 'refunded')
GROUP BY status
ORDER BY orders DESC;
▶ Run this query in the SQL Playground
| status | orders |
|---|---|
| delivered | 82 |
| processing | 28 |
| pending | 23 |
| shipped | 21 |
Two NULL rules matter. First, rows where the column itself is NULL match neither IN nor NOT IN. Second, if the list contains a NULL, NOT IN matches nothing at all. That usually happens with a subquery:
SELECT
(SELECT COUNT(*) FROM employees
WHERE id NOT IN (SELECT manager_id FROM employees)) AS not_in_result,
(SELECT COUNT(*) FROM employees
WHERE id NOT IN (SELECT manager_id FROM employees
WHERE manager_id IS NOT NULL)) AS not_in_without_nulls;
▶ Run this query in the SQL Playground
| not_in_result | not_in_without_nulls |
|---|---|
| 0 | 110 |
manager_id is NULL for the employees at the top, so the first version finds 0 non-managers instead of 110. Filter NULLs out of the list, or use NOT EXISTS, which does not have this problem.
IN With a Subquery
Instead of typing the list, a subquery can produce it. Orders from premium customers:
SELECT COUNT(*) AS premium_orders
FROM orders
WHERE user_id IN (SELECT id FROM users WHERE is_premium = 1);
▶ Run this query in the SQL Playground
| premium_orders |
|---|
| 85 |
The subquery must return exactly one column. For the full comparison of IN and EXISTS with subqueries, see IN vs EXISTS.
Combining IN With Other Conditions
IN is just one condition, so it combines with AND and OR like any other. Sales and Marketing employees earning more than 150,000:
SELECT first_name, last_name, department, salary
FROM employees
WHERE department IN ('Sales', 'Marketing')
AND salary > 150000
ORDER BY salary DESC;
▶ Run this query in the SQL Playground
| first_name | last_name | department | salary |
|---|---|---|---|
| Steven | Nguyen | Marketing | 204449 |
| Matthew | Wilson | Marketing | 196530 |
| Laura | Rivera | Sales | 195759 |
| Jeffrey | Lewis | Marketing | 193343 |
| Paul | Thompson | Sales | 168980 |
| Kenneth | Jackson | Marketing | 167158 |
| George | Martin | Sales | 151491 |
Common IN Mistakes
Five errors and how to avoid them.
1. = with a list
SELECT * FROM orders
WHERE user_id = (4, 77, 118);
SELECT * FROM orders
WHERE user_id IN (4, 77, 118);
= compares with one value. A list needs IN.
2. Square or curly brackets
WHERE category IN ['Books', 'Toys']
WHERE category IN ('Books', 'Toys')
SQL lists always use round brackets.
3. Text without quotes
WHERE category IN (Books, Toys)
WHERE category IN ('Books', 'Toys')
Without quotes, the database looks for columns called Books and Toys and reports an error.
4. NOT IN with a NULL in the list
WHERE id NOT IN (SELECT manager_id FROM employees)
WHERE id NOT IN (SELECT manager_id FROM employees
WHERE manager_id IS NOT NULL)
In the Playground the first version returns 0 rows instead of 110.
5. Expecting IN to find NULL
WHERE shipped_date IN (NULL, '2024-12-16')
WHERE shipped_date IS NULL
OR shipped_date = '2024-12-16'
Comparing with NULL is never true, so NULL inside an IN list matches nothing.
Practice WHERE IN Queries
5 exercises on the real Playground tables.
Write each query yourself first. Every solution has been run against the Playground database.
-
1Easy List the users who live in Austin, Dallas or Houston. Show the first 8 by last name. Table:
usersShow solution
SELECT first_name, last_name, city FROM users WHERE city IN ('Austin', 'Dallas', 'Houston') ORDER BY last_name, first_name LIMIT 8;▶ Run this query in the SQL Playground
One IN instead of three OR conditions.
-
2Easy Count the payments made with a card (Credit Card or Debit Card). Table:
paymentsShow solution
SELECT COUNT(*) AS card_payments FROM payments WHERE method IN ('Credit Card', 'Debit Card');▶ Run this query in the SQL Playground
Text values in quotes, matching exactly.
-
3Medium Count the employees in every department except HR and Finance. Table:
employeesShow solution
SELECT department, COUNT(*) AS employees FROM employees WHERE department NOT IN ('HR', 'Finance') GROUP BY department ORDER BY employees DESC, department;▶ Run this query in the SQL Playground
NOT IN is safe here: the list is literal and contains no NULL.
-
4Medium List the products that appear on order 1, 2 or 3, using IN on order_items. Table:
products, order_itemsShow solution
SELECT DISTINCT p.name FROM products p WHERE p.id IN (SELECT product_id FROM order_items WHERE order_id IN (1, 2, 3)) ORDER BY p.name;▶ Run this query in the SQL Playground
An IN with a literal list inside an IN with a subquery.
-
5Medium Count the reviews with a rating of 1, 2 or 5. Table:
reviewsShow solution
SELECT rating, COUNT(*) AS reviews FROM reviews WHERE rating IN (1, 2, 5) GROUP BY rating ORDER BY rating;▶ Run this query in the SQL Playground
A list of numbers; BETWEEN would not work because 3 and 4 must be left out.
📝 Quiz — WHERE IN
Test your understanding · 0/9 answered
What does WHERE IN do?
Like several OR conditions on one column.
Which query shows orders for customers 5, 11 and 29?
IN with round brackets.
WHERE city IN ('Austin', 'Dallas', 'Houston') is the same as which condition?
With AND it could never be true: a city has one value.
When should you prefer IN over OR?
Different columns still need OR.
What happens if you misspell the column name in a WHERE IN?
MySQL says "Unknown column"; SQLite says "no such column".
Which query shows products in the Books, Toys or Electronics category?
Column name, IN, then the values in round brackets.
What does NOT IN do?
Unless the list contains a NULL, in which case it returns nothing.
Which condition filters on the text values Books and Electronics correctly?
Text in single quotes, round brackets.
What is the difference between IN and BETWEEN?
IN (1, 2, 5) skips 3 and 4; BETWEEN 1 AND 5 does not.
WHERE IN Interview Questions
Q1. Is IN faster than OR?
Usually neither: databases treat them the same. IN is preferred because it is shorter and harder to get wrong.
Q2. Why can NOT IN return no rows?
If the list contains NULL, x NOT IN (a, NULL) becomes x <> a AND x <> NULL, and the second part is never true. Remove NULLs from the subquery or use NOT EXISTS.
Q3. Can IN find NULL values?
No. A NULL in the list matches nothing, and rows with NULL in the column never match. Add OR column IS NULL.
Q4. What should you use instead of a very long IN list?
A join to a table holding the values (for example a temporary table), or a subquery. It is easier to maintain, and some databases handle huge literal lists poorly.
Frequently Asked Questions
What does the SQL IN operator do?
IN checks whether a column's value appears in a list of values and keeps the rows where it does. It gives the same result as several OR conditions on the same column, for example WHERE city IN ('Austin', 'Dallas').
Is WHERE IN the same result as multiple OR?
Yes. WHERE city IN ('Austin', 'Dallas') returns the same rows as WHERE city = 'Austin' OR city = 'Dallas'. IN is shorter and easier to extend.
Can IN be used with text (string) values?
Yes. Put each text value in single quotes: WHERE category IN ('Books', 'Toys'). Numbers need no quotes: WHERE rating IN (1, 2, 5).
When should I use IN instead of OR?
Whenever you are comparing the same column with several values. If you see column = ... OR column = ... OR column = ..., switch to IN.
Is IN faster than OR in SQL?
For normal queries the speed is the same; databases handle both alike. The benefit of IN is readability. For lists of thousands of values, a join to a table of values is usually better.
What is NOT IN in SQL?
NOT IN keeps the rows whose value matches none of the list, for example WHERE department NOT IN ('HR', 'Finance'). If the list contains a NULL, NOT IN returns no rows at all.
Does SQL IN handle NULL values?
No. A comparison with NULL is never true, so IN never matches NULL. To include NULLs, add a separate condition: WHERE status IS NULL OR status IN ('active', 'pending').
What is the difference between IN and BETWEEN in SQL?
IN matches a list of specific values: WHERE rating IN (1, 2, 5) returns only those ratings. BETWEEN matches a continuous range including both ends: WHERE total BETWEEN 100 AND 500.
Can SQL IN be used with subqueries?
Yes. Instead of a fixed list, a subquery can produce the values: WHERE user_id IN (SELECT id FROM users WHERE is_premium = 1). The subquery must return a single column.
Is SQL IN case sensitive?
It depends on the database and collation. SQLite and PostgreSQL compare text with case, so IN ('books') does not match 'Books'. MySQL and SQL Server usually ignore case with their default collations.
How many values can I put inside SQL IN?
The SQL standard sets no limit, and databases accept very long lists, though limits on statement size and parameters apply (SQL Server allows about 2,100 parameters per query, for example). For long lists, a subquery or a temporary table is easier to maintain.
Can I combine IN with AND in SQL?
Yes. WHERE department IN ('Sales', 'Marketing') AND salary > 150000 returns only employees in those departments who also earn more than 150,000.
What is the difference between IN and LIKE in SQL?
IN matches exact values from a list. LIKE matches a pattern with wildcards: WHERE last_name LIKE 'A%' matches any last name starting with A.
Why is my SQL IN query returning no results?
Common causes: text values without quotes, extra spaces or different capitalisation in the values, a misspelled column, comparing NULL with IN, or a NULL inside a NOT IN list.
Where can I practise WHERE IN queries?
In the SQLabHub Playground: every query on this page has a "Run this query" link that opens it against the same practice database, and the SQL challenges include filtering exercises.