SQL Subqueries
SQL

SQL Subqueries: Nested Queries in WHERE, FROM and SELECT

SQL Tutorial · Chapter 28 of 32

A SQL subquery is a SELECT statement nested inside another statement. The inner query runs first and its result feeds the outer query: as a single value to compare against, as a list for IN, or as a temporary table in FROM. Subqueries let you answer two-step questions such as “which orders are above the average amount?” in a single statement.

SQL Subquery Syntax

-- in WHERE (scalar or list)
SELECT columns FROM table1
WHERE column OPERATOR (SELECT column FROM table2 WHERE condition);

-- in FROM (derived table, needs an alias)
SELECT t.column FROM (SELECT ... FROM table2 GROUP BY ...) AS t;

-- in SELECT (scalar, one value per row)
SELECT column, (SELECT AGG(x) FROM table2 WHERE ...) AS alias FROM table1;

Sample Tables

Customers
CustomerID Name City Country
1 Anita Sharma Mumbai India
2 John Smith London UK
3 Maria Garcia Madrid Spain
4 Wei Chen Singapore Singapore
5 Emma Brown Sydney Australia
Orders
OrderID CustomerID Product Amount OrderDate
101 1 Laptop 1200 2026-01-05
102 2 Mouse 25 2026-01-07
103 1 Monitor 300 2026-01-12
104 3 Keyboard 45 2026-02-02
105 6 Headset 80 2026-02-15
106 4 Laptop 1150 2026-03-01

Example 1: Scalar Subquery in WHERE

The inner query returns one value (the average, 466.67) and the outer query compares every row against it.

SELECT OrderID, Product, Amount
FROM Orders
WHERE Amount > (SELECT AVG(Amount) FROM Orders);
OrderID Product Amount
101 Laptop 1200
106 Laptop 1150

Example 2: Multi-Row Subquery with IN

SELECT Name, Country
FROM Customers
WHERE CustomerID IN (SELECT CustomerID FROM Orders WHERE Amount > 100);
Name Country
Anita Sharma India
Wei Chen Singapore

The inner query returns the list (1, 1, 4); the outer query keeps customers whose ID is in that list.

Example 3: Subquery in FROM (Derived Table)

First total each customer’s spend, then filter and sort those totals. The derived table must have an alias.

SELECT t.CustomerID, t.Total
FROM (SELECT CustomerID, SUM(Amount) AS Total
      FROM Orders
      GROUP BY CustomerID) AS t
WHERE t.Total > 50
ORDER BY t.Total DESC;
CustomerID Total
1 1500
4 1150
6 80

Example 4: Scalar Subquery in SELECT

SELECT Name,
       (SELECT COUNT(*) FROM Orders o WHERE o.CustomerID = c.CustomerID) AS Orders
FROM Customers c
ORDER BY Orders DESC, Name;
Name Orders
Anita Sharma 2
John Smith 1
Maria Garcia 1
Wei Chen 1
Emma Brown 0

This is a correlated subquery: it references c.CustomerID from the outer row, so it is evaluated once per customer.

Example 5: Correlated Subquery in WHERE

Find each customer’s largest order: keep an order only if no other order by the same customer is bigger.

SELECT o.CustomerID, o.OrderID, o.Amount
FROM Orders o
WHERE o.Amount = (SELECT MAX(o2.Amount) FROM Orders o2 WHERE o2.CustomerID = o.CustomerID)
ORDER BY o.CustomerID;
CustomerID OrderID Amount
1 101 1200
2 102 25
3 104 45
4 106 1150
6 105 80

Subquery vs JOIN

Many subqueries can be rewritten as joins, and the optimizer often produces the same plan. Use a JOIN when you need columns from both tables in the output; use a subquery when you only need the second table to filter or to supply a single computed value. Correlated subqueries in SELECT can be slow on large tables; a JOIN with GROUP BY or a window function usually scales better.

Works in MySQL, SQL Server, PostgreSQL, SQLite

  • Subqueries in WHERE, FROM and SELECT work in all four. Derived tables need an alias everywhere except SQLite, which tolerates its absence.
  • MySQL cannot reference the table being modified in a subquery inside UPDATE or DELETE (“You can’t specify target table”); wrap it in another derived table.
  • All four support Common Table Expressions (WITH t AS (...)) as a more readable alternative to FROM subqueries.

Common Mistakes

  • A scalar subquery returning more than one row: “subquery returns more than 1 row”. Use IN, or add LIMIT 1 / an aggregate.
  • Forgetting the alias on a derived table.
  • Selecting more than one column in a subquery used with IN or =.
  • Using ORDER BY inside a subquery where it has no effect (except with LIMIT).

Practice Exercise

  1. List orders whose Amount is below the average Amount.
  2. List the names of customers who have ordered a Laptop.
Show answers
-- 1
SELECT OrderID, Amount FROM Orders WHERE Amount < (SELECT AVG(Amount) FROM Orders);
-- 102, 103, 104, 105

-- 2
SELECT Name FROM Customers
WHERE CustomerID IN (SELECT CustomerID FROM Orders WHERE Product = 'Laptop');
-- Anita Sharma, Wei Chen

Related Chapters

FAQ

What is a subquery in SQL?

A SELECT statement placed inside another SQL statement. The inner query’s result is used by the outer query as a value, a list or a temporary table.

What is a correlated subquery?

A subquery that references a column from the outer query, so it must be re-evaluated for each outer row. It is powerful but can be slow on large tables.

Are subqueries slower than joins?

Not necessarily. Modern optimizers often rewrite subqueries as joins internally. Correlated subqueries in the SELECT list are the ones most likely to be slow.

Chapter 28 of 32 · SQL from Scratch: all 32 chapters

PK
Meet PK, the founder of NeotechNavigators.com! With over 15 years of experience in Data Visualization, Excel Automation, and dashboard creation. PK is a Microsoft Certified Professional who has a passion for all things in Excel. PK loves to explore new and innovative ways to use Excel and is always eager to share his knowledge with others. With an eye for detail and a commitment to excellence, PK has become a go-to expert in the world of Excel. Whether you're looking to create stunning visualizations or streamline your workflow with automation, PK has the skills and expertise to help you succeed. Join the many satisfied clients who have benefited from PK's services and see how he can take your data analysis skills to the next level!
https://neotechnavigators.com