Skip to main content
SQL Fundamentals
CHAPTER 18 Beginner

SQL Subqueries | Nested SELECT Statements

Updated: May 16, 2026
15 min read

# CHAPTER 18

Subqueries and Nested Queries

1. Introduction

Sometimes, to answer a question, you have to ask a different question first. *Example:* "Who earns more than the average salary?" To answer this, you must first ask, "What *is* the average salary?" In SQL, you cannot just write WHERE salary > AVG(salary)—the engine will crash. To solve this, you must write a query *inside* another query. This is called a Subquery (or Nested Query). In this chapter, we will master the logic of query-inception.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the structural syntax of a Subquery.
  • Use a Subquery inside a WHERE clause for dynamic filtering.
  • Use a Subquery inside a SELECT clause to generate calculated columns.
  • Understand the EXISTS operator for performance optimization.
  • Differentiate between a Subquery and a JOIN.

3. The Subquery in the WHERE Clause

The most common place for a subquery is acting as a dynamic filter. Let's solve the intro problem: Find employees earning above average.
sql
12345678
SELECT first_name, salary 
FROM employees 
WHERE salary > (
    -- This inner Subquery executes FIRST.
    -- It returns a single number (e.g., 65000).
    -- The outer query then becomes: WHERE salary > 65000
    SELECT AVG(salary) FROM employees
);

*(The inner query must be wrapped in parentheses ()).*

4. Subqueries returning a List (IN)

If your inner query returns multiple rows, you cannot use the equals = or greater than > operator. You must use the IN operator.
sql
1234567
-- Find all customers who have placed an order in the last 30 days
SELECT customer_name FROM customers 
WHERE id IN (
    -- This subquery returns a massive list of IDs (e.g., 5, 12, 99)
    SELECT DISTINCT customer_id FROM orders 
    WHERE order_date > '2023-10-01'
);

*(Note: This exact same result could be achieved with a JOIN. Developers often debate which is better. Generally, JOIN is faster, but Subqueries are sometimes easier for humans to read).*

5. The Subquery in the SELECT Clause

You can use a subquery to generate a dynamic column on the fly.
sql
123456
SELECT 
    product_name, 
    price,
    (SELECT AVG(price) FROM products) AS 'Global Average',
    price - (SELECT AVG(price) FROM products) AS 'Difference From Avg'
FROM products;

*(Result: A beautiful grid comparing every single product's price to the global average!)*

6. The EXISTS Operator (High Performance)

If you just want to know *if* a customer has placed an order (you don't care what the order is), using an INNER JOIN or an IN subquery forces SQL to process massive amounts of data. The EXISTS operator is highly optimized. It stops searching the exact millisecond it finds a single match, making it blazing fast.
sql
1234567
-- Find customers who have at least one active order
SELECT customer_name FROM customers c
WHERE EXISTS (
    SELECT 1 FROM orders o 
    WHERE o.customer_id = c.id 
    AND o.status = 'Active'
);

*(This is a Correlated Subquery. The inner query relies on the c.id from the outer query to function!).*

7. Mini Project: The HR Analytics Dashboard

Let's use subqueries to build a complex HR report.
sql
1234567
-- 1. Who is our highest-paid employee?
SELECT name, salary FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);

-- 2. Which departments have NO employees assigned?
SELECT dept_name FROM departments
WHERE id NOT IN (SELECT DISTINCT dept_id FROM employees);

8. Common Mistakes

  • Returning Multiple Columns: If you write WHERE salary = (SELECT id, salary FROM employees), the query will crash. A subquery used with a standard mathematical operator (=, >, <) can ONLY return a single column and a single row (a scalar value).
  • Subquery Performance: Writing a Correlated Subquery inside a SELECT statement forces the inner query to re-execute for *every single row* in the outer table. If you have 1 million rows, the inner query runs 1 million times. This is called the "N+1 Problem" and destroys server performance.

9. Best Practices

  • JOIN vs Subquery: As a general rule of database architecture, if you can write a query using a standard JOIN, you should. The SQL Query Optimizer is incredibly efficient at processing JOINs. Use Subqueries specifically when calculating aggregates (MAX, AVG) or utilizing the EXISTS operator.

10. Exercises

  1. 1. What punctuation marks must encapsulate a nested Subquery?
  1. 2. If a Subquery in a WHERE clause returns a list of 50 different IDs, what operator must you use instead of the equals (=) sign?

11. SQL Challenges

Write a query to find all movies where the budget is greater than the MAX budget of movies released in the year 2010.
sql
12
SELECT title FROM movies
WHERE budget > (SELECT MAX(budget) FROM movies WHERE release_year = 2010);

12. MCQ Quiz with Answers

Question 1

When utilizing a Subquery in a WHERE clause combined with a standard comparison operator like >, what strict rule applies to the output of the Subquery?

Question 2

Why is the EXISTS operator considered a high-performance optimization over the IN operator when checking for relationships?

13. Interview Questions

  • Q: Differentiate between a standard Subquery and a "Correlated Subquery". Provide an example of how a Correlated Subquery operates row-by-row against the outer query.
  • Q: You are tasked with finding all Users who have never placed an Order. Explain how you could solve this using a LEFT JOIN combined with a WHERE NULL clause, versus solving it using a NOT EXISTS subquery.

14. FAQs

Q: Can I put a Subquery inside the FROM clause? A: Yes! This is called a "Derived Table". You can do SELECT * FROM (SELECT id, name FROM users) AS temp_table;. It treats the result of the inner query as a temporary, virtual table that you can query against!

15. Summary

You have mastered multi-layered logic. By wielding Subqueries, you can execute complex mathematical filters dynamically, generate calculated columns on the fly, and drastically optimize your backend application's performance using the highly efficient EXISTS operator.

16. Next Chapter Recommendation

Writing a 15-line query with JOINs and Subqueries every single day to generate a report is exhausting. What if we could write that massive query *once*, save it inside the database, and query it like a regular table? In Chapter 19: Views in SQL, we will learn how to create Virtual Tables.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·