Skip to content
Laviyx Learn

Try

SQL course menu

SQL EXISTS and NOT EXISTS: Check Whether Related Rows Exist

Learn SQL EXISTS and NOT EXISTS with correlated subqueries: find rows that have (or lack) related rows, why NOT EXISTS is safer than NOT IN, and how EXISTS compares with JOIN and IN.

Intermediate8 min readUpdated
On this page

Many questions are about whether something exists: customers who have placed an order, products that have never been sold, employees with no direct reports. EXISTS answers exactly that. It returns true if a subquery finds at least one row.

The example tables#

customers

customer_idnamecity
1AshaMumbai
2RaviDelhi
3MeeraPune
4JohnChennai

orders

order_idcustomer_idamount
1011250
1021120
1032560
104590

Syntax#

SQL
SELECT columns
FROM table_a a
WHERE EXISTS (
  SELECT 1
  FROM table_b b
  WHERE b.some_column = a.some_column
);

The subquery is correlated: it refers to the outer row (a.some_column), so it is checked once for each row of table_a.

Customers who have ordered#

SQLRun
SELECT name
FROM customers c
WHERE EXISTS (
  SELECT 1
  FROM orders o
  WHERE o.customer_id = c.customer_id
);
Output
name
----
Asha
Ravi

For each customer, the database asks: is there at least one order with this customer's id? For Asha the answer is yes (twice, but once is enough), so she is kept. Note that each customer appears once, even though Asha has two orders. A JOIN would have returned her twice.

NOT EXISTS: rows with no match#

Customers who have never ordered:

SQLRun
SELECT name
FROM customers c
WHERE NOT EXISTS (
  SELECT 1
  FROM orders o
  WHERE o.customer_id = c.customer_id
);
Output
name
-----
Meera
John

This is the same "anti-join" as LEFT JOIN ... WHERE o.order_id IS NULL, written in a way that reads almost like English.

Why NOT EXISTS is safer than NOT IN#

NOT IN breaks when the list it checks against contains a NULL:

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

No rows at all, because 3 NOT IN (1, 2, NULL) cannot be proven true when one value is unknown. If orders.customer_id ever contained a NULL, WHERE customer_id NOT IN (SELECT customer_id FROM orders) would silently return nothing. NOT EXISTS is not affected by NULLs, so it is the safer default. (More in IN.)

EXISTS vs IN vs JOIN#

These three find customers who have ordered:

SQLRun
-- EXISTS
SELECT name FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);

-- IN
SELECT name FROM customers
WHERE customer_id IN (SELECT customer_id FROM orders);

-- JOIN (needs DISTINCT, because Asha has two orders)
SELECT DISTINCT c.name
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id;
EXISTSINJOIN
Duplicates from many matchesnonoyes
Can use columns of the other table in the resultnonoyes
Safe with NULLs when negatedyes (NOT EXISTS)no (NOT IN)yes (LEFT JOIN ... IS NULL)

Modern optimisers often run EXISTS and IN the same way. Choose EXISTS for "has related rows" checks, especially negated ones.

Adding conditions inside EXISTS#

The subquery can contain any conditions. Customers with at least one order over 200:

SQLRun
SELECT name
FROM customers c
WHERE EXISTS (
  SELECT 1
  FROM orders o
  WHERE o.customer_id = c.customer_id
    AND o.amount > 200
);

This returns Asha (order 101 is 250) and Ravi (order 103 is 560).

Common mistakes#

Practice#

Practice exercise

Using the employees table (id, name, manager_id), find the employees who manage at least one person: employees whose id appears as someone else's manager_id.

Show hint

WHERE EXISTS (SELECT 1 FROM employees r WHERE r.manager_id = e.id). You need two aliases of the same table.

Show solution
SQLRun
SELECT e.name
FROM employees e
WHERE EXISTS (
  SELECT 1
  FROM employees r
  WHERE r.manager_id = e.id
);
Output
name
-----
Meera
Priya

Meera manages Ravi; Priya manages Asha and John. Priya still appears only once.

Key takeaway#

Finished this lesson?