SQL Tutorial › Subqueries & CTEs › EXISTS, ANY & ALL

SQL EXISTS, ANY and ALL

AdvancedLesson 42 of 6910 min read7 queries run on MySQL 8.4

EXISTS asks a yes/no question: “is there at least one matching row?” It is the clearest and safest way to filter by the presence or absence of related data. ANY and ALL compare one value with every value a subquery returns: “more than any sales salary”, “more than all of them”.

Advertisement
In this lesson
  • Filter with EXISTS and NOT EXISTS
  • Know why NOT EXISTS is safer than NOT IN
  • Compare against a list with ANY / SOME
  • Compare against every value with ALL

EXISTS syntax

MySQL
SELECT columnsFROM table_a aWHERE EXISTS (SELECT 1 FROM table_b b WHERE b.key = a.key);

The subquery’s select list does not matter: EXISTS only checks whether any row comes back. SELECT 1 is the usual convention.

Sample data

customers · 7 rows (some columns)
customer_idcustomer_namecity
1Ananya SharmaMumbai
2Rohit KumarDelhi
3Fatima KhanHyderabad
4David FernandesGoa
5Ishita BoseKolkata
6Manoj PillaiChennai
7Sara ThomasBengaluru
orders · 10 rows
order_idcustomer_idorder_datestatus
100112025-01-05Delivered
100222025-01-17Delivered
100312025-02-02Delivered
100432025-02-14Cancelled
100542025-03-08Delivered
100652025-03-22Shipped
100722025-04-10Delivered
100812025-04-28Pending
100932025-05-15Delivered
101052025-06-01Delivered

EXISTS: rows that have a match

Customers with at least one order:

SQL
SELECT c.customer_id, c.customer_nameFROM customers cWHERE EXISTS (  SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id)ORDER BY c.customer_id;
ResultMySQL 8.4
customer_idcustomer_name
1Ananya Sharma
2Rohit Kumar
3Fatima Khan
4David Fernandes
5Ishita Bose
5 rows in set
How this query works, step by step
  1. For each customer, the subquery looks for an order with the same customer_id.
  2. As soon as one is found, EXISTS is true; MySQL does not need to look for more.
  3. Five customers have orders. Unlike a join, a customer with three orders still appears once.

NOT EXISTS: rows without a match

Customers who have never ordered:

SQL
SELECT c.customer_id, c.customer_nameFROM customers cWHERE NOT EXISTS (  SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);
ResultMySQL 8.4
customer_idcustomer_name
6Manoj Pillai
7Sara Thomas
2 rows in set

Add conditions inside the subquery for more specific questions. Customers with no delivered order:

SQL
SELECT c.customer_nameFROM customers cWHERE NOT EXISTS (  SELECT 1 FROM orders o  WHERE o.customer_id = c.customer_id AND o.status = 'Delivered')ORDER BY c.customer_name;
ResultMySQL 8.4
customer_name
Manoj Pillai
Sara Thomas
2 rows in set

NOT EXISTS vs NOT IN with NULLs

Who manages nobody? With NOT IN and a subquery that contains a NULL, the answer is silently empty:

SQL
SELECT first_nameFROM employeesWHERE emp_id NOT IN (SELECT manager_id FROM employees);
ResultMySQL 8.4
Empty set

NOT EXISTS gives the right answer, because it only checks for matching rows:

SQL
SELECT e.first_nameFROM employees eWHERE NOT EXISTS (SELECT 1 FROM employees r WHERE r.manager_id = e.emp_id)ORDER BY e.emp_id;
ResultMySQL 8.4
first_name
Priya
Karan
Neha
Arjun
Rohan
Sneha
Amit
7 rows in set
How this query works, step by step
  1. For each employee e, the subquery looks for anyone whose manager_id is e.emp_id.
  2. The CEO’s NULL manager_id simply never matches; it cannot poison the result.
  3. Seven employees have no direct reports.
Tip

For “rows with no match in another table”, use NOT EXISTS (or LEFT JOIN ... IS NULL). Avoid NOT IN unless the column is declared NOT NULL.

ANY / SOME

value > ANY (subquery) is true if the value is greater than at least one value in the list. Employees who earn more than at least one sales employee:

MySQL
SELECT first_name, salaryFROM employeesWHERE salary > ANY (SELECT salary FROM employees WHERE dept_id = 2)  AND dept_id <> 2ORDER BY salary;
ResultMySQL 8.4
first_namesalary
Priya72000
Karan72000
Sneha78000
Kavya88000
Rahul98000
Asha125000
6 rows in set
How this query works, step by step
  1. The subquery returns the Sales salaries: 105,000, 54,000 and 48,000.
  2. > ANY means “more than the smallest of them”, here more than 48,000.
  3. = ANY is the same as IN. SOME is a synonym for ANY.

ALL

value > ALL (subquery) is true only if the value is greater than every value in the list:

MySQL
SELECT first_name, salaryFROM employeesWHERE salary > ALL (SELECT salary FROM employees WHERE dept_id = 2)ORDER BY salary;
ResultMySQL 8.4
first_namesalary
Asha125000
Meera250000
2 rows in set
How this query works, step by step
  1. > ALL means “more than the largest”, here more than 105,000.
  2. Only Asha (125,000) and Meera (250,000) qualify.
  3. <> ALL is the same as NOT IN, including its NULL problem.
ExpressionEquivalent
x > ANY (list)x > MIN(list)
x > ALL (list)x > MAX(list)
x = ANY (list)x IN (list)
x <> ALL (list)x NOT IN (list)

Exercise: Products that were ordered

List the products that appear in at least one order line, using EXISTS.

Expected resultMySQL 8.4
product_name
Wireless Mouse
Mechanical Keyboard
USB-C Hub
Office Chair
Standing Desk
Notebook Pack
Gel Pens
Desk Lamp
8 rows in set
Hint 1

Correlate order_items.product_id with products.product_id.

Exercise: Departments without staff

List departments that have no employees, using NOT EXISTS.

Expected resultMySQL 8.4
dept_name
Finance
1 row in set
Hint 1

Look for an employee whose dept_id matches the department.

Quick quiz

1. What does EXISTS check?

2. Why is NOT EXISTS safer than NOT IN?

3. salary > ALL (10, 20, 30) is true for…

EXISTS FAQ

What is the difference between EXISTS and IN?

IN compares a value with a list returned by the subquery. EXISTS only checks whether a correlated subquery returns any row. They often give the same result, but NOT EXISTS handles NULLs correctly where NOT IN does not.

Is EXISTS faster than IN?

In MySQL 8 the optimizer turns both into semi-joins in most cases, so performance is usually similar. Choose the one that reads best; prefer NOT EXISTS over NOT IN.

What does SELECT 1 mean inside EXISTS?

Nothing special: EXISTS ignores the selected values. SELECT 1 just shows that only the presence of a row matters.