Skip to main content

Welcome to a Grasp lesson

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

Lesson 38

CTEs for Complex Queries

Recommended resources

Hello! Welcome to your next lesson in the "Advanced SQL for Business Analytics" module.

In our last few lessons, you've learned to build powerful queries using subqueries for multi-step filtering and CASE statements for conditional logic. As you've probably noticed, these queries can quickly become long and complex. Imagine handing a 100-line query with nested subqueries to a colleague or trying to debug it yourself after a few weeks. It can be a real challenge.

This lesson tackles that exact problem by introducing Common Table Expressions (CTEs). A CTE allows you to break down a complex query into logical, readable, and reusable steps. Think of it as giving a name to a subquery, which you can then reference like a normal table. Mastering CTEs is a sign of a proficient analyst, as it demonstrates your ability to write clean, maintainable, and professional code.

Your goal is to transition into a formal Business Analyst role, and writing clear, well-structured queries is a key part of "BA work management" and collaboration with technical teams. By the end of this lesson, you will be able to structure complex queries using CTEs to improve readability and build multi-step analyses.

From Subquery Spaghetti to Readable Recipes

Let's start with the fundamental question: what is a CTE and why is it better than a complex subquery? At its core, a CTE is a temporary, named result set that exists only for the duration of a single query. You define it using the WITH keyword.

This approach transforms a query from a nested, "bottom-to-top" logic (like a subquery) into a sequential, "top-to-bottom" recipe that is much easier to follow.

SQL WITH Clause | Clearly Explained | CTEs vs Subqueries vs Temp Tables | Recursive CTEs

To see this transformation in action, let's watch this excellent video from Maven Analytics. It starts with a business question and solves it first with a subquery, and then rewrites the exact same logic using a CTE. Pay close attention to the difference in structure and readability.

Watch from the beginning to 4:04. The video clearly explains the WITH syntax and demonstrates how a CTE makes the query's logic sequential and easier to understand compared to a nested subquery.

As the video shows, both queries produce the same result, but the CTE version is organized more logically:

  1. Define the building block first: The WITH clause creates a temporary table mp containing the max price per category.
  2. Use the building block: The main query then simply selects from mp as if it were a regular table.

This separation of concerns is a core principle of good coding and is highly valued in professional environments.


The Key Advantage: Reusability

One of the most significant advantages of CTEs over subqueries is reusability. A subquery's result can only be used once in the place it's defined. If you need the same intermediate result in another part of your query, you have to write the entire subquery again. This is inefficient and makes the query even harder to read.

A CTE, however, can be referenced multiple times within the same main query.

SQL WITH Clause | Clearly Explained | CTEs vs Subqueries vs Temp Tables | Recursive CTEs

Let's continue with the Maven Analytics video, which now demonstrates this exact point. It modifies the previous query to use the CTE's result in two different places.

Watch from 4:04 to 5:45. Notice how the mp CTE is referenced once in the WHERE clause and again in the subquery calculating the average. Imagine having to write out the full subquery in both of those places!

This ability to define a piece of logic once and reuse it is what makes CTEs so powerful for complex analysis, where you might need to compare a value to an overall average, a segment average, and a total sum—all derived from the same base calculation.

Test your understanding!

You're an analyst in the AdTech industry. You have a query that calculates the number of campaigns with high daily ad spend and the average spend of those high-performing campaigns. The query uses the same subquery twice:

SELECT
    COUNT(DISTINCT campaign_id) AS number_of_high_spend_campaigns,
    (SELECT AVG(daily_spend) FROM (SELECT campaign_id, SUM(spend) AS daily_spend FROM ad_spend GROUP BY campaign_id) AS daily_spends WHERE daily_spend > 1000) AS avg_spend_of_high_performers
FROM 
    (SELECT campaign_id, SUM(spend) AS daily_spend FROM ad_spend GROUP BY campaign_id) AS daily_spends
WHERE 
    daily_spend > 1000;

How would you rewrite this query using a CTE to make it more readable and efficient? Don't worry about perfect syntax; just describe the structure.

Show answer

You would create one CTE to calculate the daily spend for each campaign. Then, you would reference that CTE in your main query to calculate both the count and the average.

The structure would look like this:

WITH campaign_daily_spend AS (
    SELECT 
        campaign_id, 
        SUM(spend) AS daily_spend 
    FROM 
        ad_spend 
    GROUP BY 
        campaign_id
)
SELECT 
    COUNT(DISTINCT campaign_id) AS number_of_high_spend_campaigns,
    AVG(daily_spend) AS avg_spend_of_high_performers
FROM 
    campaign_daily_spend
WHERE 
    daily_spend > 1000;

This version is much cleaner. The logic for calculating daily_spend is defined once and then reused, which is exactly what CTEs are designed for.


Building a Narrative with Multiple CTEs

The true power of CTEs shines when you need to perform a multi-step analysis. You can define a series of CTEs, where each one builds on the one before it, creating a logical flow that tells the story of your data transformation.

This is like writing a report:

  • CTE 1: Gathers the raw data and performs initial cleaning/aggregation.
  • CTE 2: Takes the result of CTE 1 and adds customer segmentation.
  • CTE 3: Takes the result of CTE 2 and ranks the segments.
  • Main Query: Selects the final, polished data for presentation.

This approach is incredibly valuable for a BA because it makes your analytical process transparent and easy for others (and your future self) to understand.

SQL CTE (Common Table Expression) Visually Explained | Full Guide WITH Clause | #SQL Course 28

The video 'SQL CTE Visually Explained' by Data with Baraa provides an exceptionally clear, step-by-step example of building a customer report using multiple CTEs. It demonstrates both independent and 'nested' CTEs (where one CTE uses a previous one).

This is a longer segment, but it's worth it. Watch from 13:30 to 44:04. Follow along as the instructor builds a complex report step-by-step: First, Standalone CTEs (13:30 - 31:09): The instructor creates two separate CTEs, cte_total_sales and cte_last_order, and then joins them in the main query. This shows how to combine different, independent preparatory steps. Then, Nested CTEs (31:09 - 44:04): The instructor adds a new CTE, cte_customer_rank, that reuses the result from the first CTE (cte_total_sales) to avoid repeating the calculation. This demonstrates the power of building a logical chain of analysis.


Practical Advice and Broader Context

When to Use a CTE?

CTEs are fantastic, but they are not the only tool for organizing SQL. It's helpful to know where they fit.

CTE in SQL: A Complete Guide with Examples

This article from DataCamp provides a handy comparison table that puts CTEs in context with other SQL techniques.

Read the section 'When to Use CTEs vs. Other Techniques'. Focus on the table that compares CTEs, Derived Tables (Subqueries), and Views. Understand that CTEs are best for organizing complex logic within a single query.

In short:

  • Subquery/Derived Table: Fine for a simple, one-time use inside a query.
  • CTE: The best choice for organizing multi-step logic or when you need to reuse an intermediate result within a single, complex query.
  • View: A permanent, stored query. Use this when you have a piece of logic that needs to be reused across many different queries by multiple users.

A Word of Caution: Don't Overdo It

With great power comes great responsibility. It can be tempting to turn every single step of your query into a CTE. This can backfire, making a query unnecessarily long and complex.

SQL CTE (Common Table Expression) Visually Explained | Full Guide WITH Clause | #SQL Course 28

Let's finish with some 'real talk' from the 'Data with Baraa' video on the responsible use of CTEs.

Watch the short section from 44:51 to 47:00. The advice here is golden for any aspiring analyst: aim for clarity, and if your query has more than 3-5 CTEs, consider if there's a simpler way to structure your logic.


Conclusion

Today you've learned one of the most important techniques for writing professional, advanced SQL. By breaking down complex logic into named, sequential steps, CTEs make your queries dramatically more readable, maintainable, and easier to debug.

Key Takeaways:

  • A Common Table Expression (CTE) is a temporary result set defined with the WITH keyword to organize complex queries.
  • CTEs improve readability by creating a top-to-bottom logical flow, unlike nested subqueries.
  • A key advantage of CTEs is reusability: you can reference the same CTE multiple times within your main query.
  • You can chain multiple CTEs together, with later CTEs building upon earlier ones, to create a clear, step-by-step analytical narrative.
  • While powerful, CTEs should be used judiciously to maintain clarity. Aim for a manageable number of logical steps.

For a Business Analyst, writing code that is easy for others to understand is just as important as getting the right answer. CTEs are your best tool for achieving that clarity in SQL.

Preview of the Next Lesson:
We've now mastered how to structure and organize complex queries. Next, we will learn about Window Functions. These functions allow you to perform calculations across a set of table rows that are somehow related to the current row. Think of tasks like "ranking products by sales within each category" or "calculating a running total of revenue over time." Window functions are often used inside CTEs to prepare data for final analysis, and together, they form the backbone of advanced analytics in SQL.