Adventures in Machine Learning

CTEs vs Subqueries: Choosing the Right Tool for Your SQL Queries

Common Table Expressions (CTEs) vs. Subqueries: A Comprehensive Overview

Let’s face it; managing complex data can be challenging.

Every developer knows that querying databases, especially when dealing with large datasets, can be daunting. Fortunately, SQL provides us with several powerful tools to make this task more manageable: CTEs and subqueries.

These tools help us organize our code, increase the efficiency of our queries, and minimize errors. In this article, we’ll explore the differences between CTEs and subqueries, examining their strengths and weaknesses so you can make an informed choice when selecting the best option to use in your SQL queries.

Subqueries: What Are They? A subquery, also known as a nested query, is a query that is embedded inside the main query, enclosed in parentheses.

The subquery is executed first and generates a result set, which is then used in the primary query to filter data. For instance, consider the following example:



FROM orders

WHERE customer_id IN (

SELECT customer_id

FROM customers

WHERE customer_type = ‘wholesale’



Here, the subquery selects all the customer IDs of wholesale clients from the customers table. The primary query then uses this list to select all the orders from customers that match those IDs.

Subqueries are versatile and can be used in various SQL statements, such as


They can also be nested within other subqueries, enabling developers to retrieve highly specific data. CTEs: Definition and Examples

A Common Table Expression (CTE) is a named temporary result set derived from a

SELECT statement and defined within the execution scope of a single SQL statement.

Its syntax involves defining the CTE name followed by a

SELECT statement that defines the result set. Consider the following example:


WITH discount_sales AS (

SELECT id, SUM(total_price) AS discount_total

FROM orders

WHERE discount_code IS NOT NULL



SELECT id, discount_total

FROM discount_sales

WHERE discount_total > 500;


Here, we use the WITH statement to define the CTE named “discount_sales,” which retrieves the total sales amount of discounted orders per customer ID. This temporary table is then used to filter customers with more than S500 in discounted sales.

CTEs are highly versatile and can be used in different

SELECT statements, including UNIONs, joins, and self-referential recursive queries.

Differences Between CTEs and Subqueries

While both CTEs and subqueries perform similar tasks, they have differences that set them apart. Here are some essential variations between the two:

Readability: CTEs tend to provide cleaner, more readable SQL code, which developers can reuse in multiple SQL statements.

Reusability: With CTEs, developers can reuse the CTE’s result set as many times as needed in a single query, which is not possible with subqueries. Recursion: CTEs are an effective tool for performing recursive queries with SQL, while subqueries cannot perform the same task.

WHERE clause and UPDATE Statements: Subqueries are more flexible to use within a WHERE clause or an UPDATE statement.

Benefits of learning CTEs

Learning CTEs can significantly enhance your SQL skills, making you a better-developer. Fortunately, offers a comprehensive CTEs course that provides step-by-step explanations and interactive exercises to guide you through the process.

The course covers various concepts, including:

– Basic CTE syntax

– Recursive CTEs

– Using CTEs instead of subqueries

– Using CTEs in queries involving joins and window functions

The course is self-paced, allowing you to take it at your convenience, and takes approximately 18 hours to complete.


In conclusion, CTEs and subqueries are powerful tools for managing complex data retrieved from SQL databases. While both have similarities, they are also vastly different, each with its strengths and weaknesses.

By understanding the benefits of each tool, developers can select the most appropriate tool for any particular data management task and ultimately increase their productivity.

3) Basics of Subqueries

A subquery in SQL is a query nested inside another query, and it depends on the output of the outer query. In other words, a subquery is a query that returns a single value that is then used by the parent query in a WHERE, HAVING, or FROM clause.

Subqueries are the primary tool for working with complex SQL queries since they allow you to create more granular, targeted queries.

Syntax of Subqueries

The syntax of a subquery depends on the type of subquery you’re using. Still, in general, a subquery must be enclosed in parentheses and is typically used in comparison operators to compare the result set with a single value or another result set.

Here’s an example of a basic subquery that extracts a list of customers along with their annual purchases and average purchase amount. “`

SELECT first_name, last_name, annual_purchases

FROM customers

WHERE annual_purchases > (

SELECT AVG(annual_purchases)

FROM customers);


In this subquery, the subquery portion calculates the average annual purchase amount for all customers. This value is then used as a comparison within the WHERE clause of the main query to filter the customer list and retrieve only those customers whose annual purchases exceed the average purchase amount.

Additional Resources on Subqueries

If you’re looking to learn more about subqueries, many resources are available online, including the SQL Basics course on, which provides an in-depth introduction to SQL. Additionally, you can check out the Beginner’s Guide to the SQL Subquery or How to Practice SQL Subqueries for more information.

4) Basics of CTEs

A Common Table Expression (CTE) is a named temporary table that can be used in a

SELECT, INSERT, UPDATE, or DELETE statement. It allows you to define a result set that can be reused throughout a single query.

CTEs are an excellent tool for comparing or joining datasets and organizing complex SQL queries.

Syntax of CTEs

The syntax for CTEs is straightforward, and it closely resembles the syntax of subqueries. You define your CTE with a WITH statement, followed by the AS keyword and a

SELECT statement.

Here’s an example of a CTE that compares employee salaries to the company average:


WITH employees AS (

SELECT emp_id, first_name, last_name, salary,

AVG(salary) OVER () AS avg_salary

FROM employee_data


SELECT emp_id, first_name, last_name, salary

FROM employees

WHERE salary > avg_salary;


Here, the CTE named “employees” retrieves an employee’s ID, first name, last name, and salary from a table named “employee_data.” The CTE also calculates the average salary using the AVG function and the OVER keyword, which specifies an aggregate function’s window. The result set is then referenced in the subsequent

SELECT statement, where the comparison of the employee’s salary to the average salary is performed using a simple WHERE clause.

Explanation of Storing Results in Named Temporary Table

The primary advantage of using CTEs is the ability to store results in named temporary tables. By doing so, developers can reference the same result set multiple times throughout a single query without re-executing the underlying

SELECT statement.

Besides, CTEs are highly versatile and can include recursive queries, UNIONs, and joins, adding even more flexibility to SQL queries. In conclusion, CTEs and subqueries are valuable tools for managing complex SQL queries.

Both are useful in different situations and should be used according to the specific requirement of the task. By understanding the syntax and benefits of both CTEs and subqueries, developers can increase their productivity and make strides in their SQL knowledge.


Differences Between CTEs and Subqueries

While both CTEs and subqueries are used to process and retrieve data in SQL, there are distinct differences between the two. Here are the major differences between CTEs and subqueries:

Comparison of Major

Differences Between CTEs and Subqueries

– CTEs can be used in multiple statements within a single query, whereas subqueries can only be used in the WHERE and HAVING clauses.

– CTEs require a named result set that can be referenced multiple times, while subqueries are dependent on the outer query results and cannot be referenced multiple times. – CTEs are generally easier to read and understand than subqueries, which can be more complex and difficult to parse.

– Recursive CTEs allow for hierarchical navigation of complex graph and tree data structures, while subqueries cannot perform these tasks.

Explanation of Naming Requirements for CTEs

In PostgreSQL, CTEs require a name to be given. The name must be unique and follow regular PostgreSQL naming conventions.

After the name, a

SELECT statement follows, and any additional statements are included within parentheses. CTEs allow developers to assign a temporary name to a result set that can then be referenced within a query.

Explanation of Recursive Capabilities of CTEs

Recursive CTEs in SQL are an extension of standard CTEs that allow developers to work with hierarchical data structures such as trees and graphs. Recursive CTEs operate on the same table, starting with the base query, and then performing a UNION ALL statement that joins the previous results of the query with the new subquery results.

Recursive CTEs provide a powerful tool for performing hierarchical queries, making it easy to navigate tree structures with complex parent-child relationships.

Explanation of Limitations of CTEs in WHERE Clause and UPDATE Statement

While CTEs are an essential tool for structured SQL queries, they have some limitations. One of the main limitations of CTEs is their inability to be used within WHERE IN and EXISTS clauses.

Additionally, CTEs are not allowed within an UPDATE statement. 6) Example: Using Subqueries in WHERE and UPDATE

Using subqueries in WHERE and UPDATE statements is a powerful method for manipulating data in SQL.

Here are two examples of using subqueries in WHERE and UPDATE statements:

Example 1: Using Subqueries in WHERE Clause to Extract Transactions

Suppose you have a table of bank account transactions that includes data fields such as date, account number, transaction type (debit or credit), and amount. You can use subqueries to filter out the daily credit transactions in the following way:



FROM transactions

WHERE account_number IN (

SELECT account_number

FROM transactions

WHERE transaction_type = ‘credit’

AND date = ‘2021-07-15’



In this example, the subquery selects all the account numbers that have credit transactions on July 15th, 2021. The outer query uses this list to select all transactions for those accounts.

Example 2: Using Subqueries in UPDATE Statement to Reassign Support Employees

Suppose you have a customer table that includes a support person field, representing the employee assigned to that customer. You can use subqueries in an UPDATE statement to reassign customers to a new support person based on the old support person’s ID and the new support person’s ID.


UPDATE customers

SET support_person = ‘new_employee_ID’

WHERE support_person = (


FROM employees

WHERE name = ‘old_employee_name’



In this example, the subquery selects the old employee ID from the employees table based on their name. The outer query then uses this information to reassign all customers previously supported by this employee to the new support person.


In conclusion, using CTEs and subqueries in SQL queries can help you navigate complex data structures and perform complex queries efficiently. Understanding the differences between CTEs and subqueries, their syntax, and how to apply them to SQL queries can enhance your productivity and improve your overall SQL knowledge.

Finally, using subqueries in WHERE and UPDATE statements can help you manipulate data with precision.

7) Making Complex Queries More Readable with CTEs

When dealing with complex SQL queries, CTEs are highly effective in simplifying the code and making it more readable. Here’s an example of a sales report that uses subqueries:






SELECT SUM(quantity * price)

FROM purchases

WHERE customer_id =

AND product_type = products.type


FROM customers

CROSS JOIN products;


The outer query retrieves customer names and product types. The subquery then calculates the total purchases made by each customer for a specific product type.

However, the syntax uses cross-joined tables, nested subqueries, and conditional statements to extract information. Such use of subqueries can make the code less readable and difficult to parse.

Now, let’s look at how we can use CTEs to simplify this same sales report query:


WITH customer_purchases AS (

SELECT customer_id, product_type,

SUM(quantity * price) AS total_purchase

FROM purchases

GROUP BY customer_id, product_type


SELECT customers.customer_name, products.type, customer_purchases.total_purchase

FROM customers

CROSS JOIN products

LEFT JOIN customer_purchases

ON ( = customer_purchases.customer_id AND

products.type = customer_purchases.product_type);


Here, we use a single CTE to retrieve customer purchases by product type. In the outer query, we then join this CTE with customer and product tables to retrieve a readable report.

As a result, the readable query is much easier to construct, parse, and edit.

8) Recursive CTEs for Hierarchical Data

Recursive CTEs provide a way to traverse and manipulate hierarchical structures such as trees, graphs, and social networks. They allow developers to perform a specific task, start from a base-case, and then iteratively navigate through the hierarchy.

Recursive CTEs contain two parts, a base query, and a recursive query. Here’s an example of recursive CTEs in action.

Suppose we have an ice cream parlor, and we want to create a menu consisting of various ice creams that use specific ingredients. We want to include not only direct ingredients but also any indirect ingredients necessary to create the final ice cream product.



SELECT name, ARRAY[name] AS ingredients

FROM flavors

WHERE name = ‘Vanilla’


SELECT, ingredients ||

FROM ice_cream

JOIN sales ON = sales.flavor

JOIN flavors ON sales.ingredient =


SELECT DISTINCT ON(name) name, ingredients

FROM ice_cream;


Here, we recursively retrieve all ingredients required to make vanilla ice cream, including direct and indirect ingredients. The base case is vanilla ice cream, and the recursive query joins the ice cream CTE with the sales and flavor tables and then stores the result into an array.

We use the

Popular Posts