Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 27

Subqueries in WHERE for Dynamic Filtering

Recommended resources

Hello! Welcome to your next lesson on SQL.

In our last lesson, we saw how to combine multiple aggregate functions like COUNT, SUM, and AVG into a single query to create rich summary reports. We ended with a question: What if the value you need for filtering isn't static, but needs to be calculated first? For instance, how do you find all employees who earn more than the average salary? You can't use an aggregate function directly in the WHERE clause like this: WHERE salary > AVG(salary).

This lesson introduces the powerful concept that solves this problem: the subquery. We'll focus on the most common use case, which directly addresses today's learning outcome: to write a subquery in the WHERE clause to filter results based on a dynamic value. This is a fundamental skill that dramatically increases the power and flexibility of your queries.

What is a Subquery and Why Do We Need It?

A subquery, also known as an inner query, is simply a SELECT statement nested inside another SQL statement. Its purpose is to provide data—often a single value or a list of values—that the outer query can then use.

The main reason for using a subquery is that the filtering criteria for your main query depends on the result of another query.

When to Use a Subquery in SQL

To start, let's watch a short video from Database Star that clearly defines a subquery and explains the core reason for using one.

Watch from 00:36 to 01:46. Pay attention to the idea that a subquery is used when the results of one query are needed to complete another.

This approach allows you to break down a complex problem into smaller, more logical steps, which aligns with the structured thinking you'd use in programming. Instead of one monolithic, hard-to-read query, you construct a main query that relies on a simpler, helper query for a specific piece of information.


Constructing a Subquery in the WHERE Clause

Let's stick with the classic example: "Find all products that have a price greater than the average price of all products."

Logically, you need to perform two steps:

  1. Calculate the average price of all products.
  2. Find all products where the price is greater than the value from Step 1.

You could do this by running two separate queries.
First, to find the average:

SELECT AVG(price) FROM product;
-- Let's say this returns 25.00

Then, you would manually plug that value into your main query:

SELECT product_name, price 
FROM product 
WHERE price > 25.00;

This works, but it's inefficient and static. If the prices change, you have to run the first query again and update the second one. A subquery lets you combine these two steps into a single, dynamic query.

The video below walks through this exact process, showing how to embed the first query directly into the WHERE clause of the second.

When to Use a Subquery in SQL

This next segment from the same Database Star video is a perfect step-by-step demonstration of building a subquery in the WHERE clause.

Watch from 01:46 to 04:24. Observe how the hardcoded value (25) is replaced by the SELECT AVG(price)... query, which is enclosed in parentheses.

The final query looks like this:

SELECT product_name, price
FROM product
WHERE price > (SELECT AVG(price) FROM product);

Here, (SELECT AVG(price) FROM product) is the subquery. The database executes it first, it returns a single value (the average price), and the outer query then uses this value to filter the products.

Let's reinforce this with a text-based example that follows the same logic.

SQL Subqueries

This article from w3resource.com provides another great example, this time involving students and marks. It clearly shows the 'two-query' thought process before combining them into one.

Read the section titled 'SQL Subqueries Example'. Start from where it introduces the 'student' and 'marks' tables and follow the logic down to the final combined SQL code.


How it Works: The Execution Flow

Your interest in low-level systems makes this next part particularly relevant. How does the database engine actually handle a query with a subquery? For the type of subquery we're discussing today (a non-correlated subquery), the process is very straightforward and logical.

  1. The subquery (inner query) executes first, and only once. The database runs SELECT AVG(price) FROM product to get a single result.
  2. The result of the subquery is substituted into the outer query. The database essentially treats the outer query as if you had typed the result yourself: WHERE price > 25.00.
  3. The main query (outer query) executes. Now with a simple condition, the database scans the product table to find the matching rows.

This modular execution is efficient. The subquery's result is held in memory temporarily while the main query runs.

The following video provides an excellent visual metaphor for this process.

SQL Subquery (Visually Explained) | Complete Guide with Correlated Subquery | #SQL Course 27

This clip from Data with Baraa visually explains the execution flow, showing how the subquery produces a temporary 'intermediate result' that the main query then uses.

Watch from 00:52 to 03:45. Focus on the diagram that illustrates the subquery executing, creating an intermediate result, and feeding it to the main query. This conceptual model is key.


Key Rules and Constraints

When writing subqueries in the WHERE clause with comparison operators (=, >, <, etc.), there is a critical rule you must follow.

The subquery must return a single value.

This is known as a scalar subquery—it returns a result set of exactly one row and one column. Our AVG() example works perfectly because aggregate functions like AVG(), SUM(), MAX(), etc. (without a GROUP BY) are designed to return a single value.

If your subquery were to return multiple values, for example (SELECT price FROM product WHERE category = 'Electronics'), the database would raise an error because it doesn't know how to compare a single price to a list of prices using the > operator. price > (100, 150, 200) is logically invalid.

When to Use a Subquery in SQL

Let's go back to the Database Star video for a concise explanation of this important rule.

Watch from 04:24 to 05:03. The video clearly states that operators like 'greater than' expect a single value, and that an aggregate function without a GROUP BY provides this.

Here are the essential guidelines to remember:

  • A subquery must be enclosed in parentheses ().
  • When used with a standard comparison operator (=, !=, >, <), it must be a scalar subquery (return a single value).
  • The subquery is placed on the right side of the comparison operator.
Test your understanding!

You have a table named support_tickets with columns: ticket_id, customer_id, and response_time_hours.

Write a single SQL query to find all tickets that were resolved faster than the average response time for all tickets.

Show answer
SELECT ticket_id, response_time_hours
FROM support_tickets
WHERE response_time_hours < (SELECT AVG(response_time_hours) FROM support_tickets);

Explanation:

  1. The subquery (SELECT AVG(response_time_hours) FROM support_tickets) runs first. It calculates the single average value for response_time_hours across all tickets.
  2. The outer query then uses this single value to filter the support_tickets table, returning only those rows where the response_time_hours is less than the calculated average.

Conclusion

Today you've learned how to make your queries significantly more dynamic and powerful. By nesting one query inside another, you can filter your data based on conditions that are calculated on the fly.

Key Takeaways:

  • A subquery is a SELECT statement nested inside another query.
  • They are used when your WHERE clause depends on a value you must first calculate from your data.
  • For non-correlated subqueries, the inner query runs first, and its result is used by the outer query.
  • When using comparison operators like >, <, or =, the subquery must be a scalar subquery, meaning it must return exactly one row and one column.

Preview of the Next Lesson:
In this lesson, our subquery was restricted to returning a single value. But what if you need to compare against a list of values? For instance, "find all orders placed by customers who live in Germany." Your subquery would need to return a list of all customer IDs from Germany. This is not a scalar subquery. In the next lesson, we will learn how to handle this by using special operators like IN and NOT IN with our subqueries.