Skip to content
Laviyx Learn

Try

SQL course menu

SQL IN and NOT IN: Match Against a List of Values

Learn the SQL IN operator: match a column against a list of values or a subquery, use NOT IN to exclude values, and avoid the NOT IN with NULL trap that silently returns no rows.

Intermediate6 min readUpdated
On this page

IN checks whether a value is in a list. It is a tidy replacement for several OR conditions on the same column, and it also works with a subquery that produces the list.

The example table#

idnamedepartmentcitymanager_id
1AshaSalesMumbai5
2RaviEngineeringBengaluru3
3MeeraEngineeringPuneNULL
4JohnMarketingMumbai5
5PriyaSalesDelhiNULL

IN with a list of values#

SQLRun
SELECT name, city
FROM employees
WHERE city IN ('Mumbai', 'Pune')
ORDER BY name;
Output
name  | city
------+-------
Asha  | Mumbai
John  | Mumbai
Meera | Pune

This is exactly the same as WHERE city = 'Mumbai' OR city = 'Pune', but shorter and easier to extend. The list can contain numbers, text, or dates, as long as they match the column's type.

NOT IN#

SQLRun
SELECT name, city
FROM employees
WHERE city NOT IN ('Mumbai', 'Pune')
ORDER BY name;
Output
name  | city
------+----------
Priya | Delhi
Ravi  | Bengaluru

IN with a subquery#

The list can come from another query. Employees who are someone's manager:

SQLRun
SELECT name, department
FROM employees
WHERE id IN (SELECT manager_id FROM employees);
Output
name  | department
------+------------
Meera | Engineering
Priya | Sales

The subquery returns the list (5, 3, NULL, 5, NULL), and IN keeps employees whose id is in it. Duplicates in the list do not matter.

The NOT IN trap#

Now the opposite question: employees who are not anyone's manager. The obvious query:

SQLRun
SELECT name
FROM employees
WHERE id NOT IN (SELECT manager_id FROM employees);
Output
name
----
(0 rows)

Zero rows, even though Asha, Ravi and John clearly manage nobody. The reason is the NULLs in the list. NOT IN (5, 3, NULL) means id <> 5 AND id <> 3 AND id <> NULL. Comparing with NULL is never true, so the whole condition can never be true, and every row is dropped.

The same thing happens with a written list:

SQLRun
SELECT name FROM customers WHERE customer_id NOT IN (1, 2, NULL);
Output
name
----
(0 rows)

IN (without NOT) is safe: a NULL in the list simply never matches, and the other values still work.

IN vs JOIN vs EXISTS#

WHERE id IN (subquery) is a filter: it keeps each outer row at most once and cannot show columns from the subquery. Use a JOIN when you need columns from the other table, and EXISTS for "has related rows" checks.

Long lists#

IN with a handful of values is perfect. If you find yourself pasting thousands of ids into an IN list, load them into a table (or a temporary table) and join instead; very long lists are slow to parse and some databases limit their size.

Common mistakes#

Practice#

Practice exercise

Using the products table, list the names and categories of products in the Furniture or Stationery categories, sorted by name.

Show hint

WHERE category IN ('Furniture', 'Stationery').

Show solution
SQLRun
SELECT name, category
FROM products
WHERE category IN ('Furniture', 'Stationery')
ORDER BY name;
Output
name       | category
-----------+-----------
Bookshelf  | Furniture
Desk Chair | Furniture
Notebook   | Stationery

Key takeaway#

Finished this lesson?