Understanding Common Table Expressions (CTEs) for Cleaner SQL Queries

Advertisement

Jun 14, 2025 By Alison Perry

You’re knee-deep in SQL code, trying to break down a large query into something that actually makes sense. Maybe you’ve copied and pasted the same subquery more than once. Maybe it’s buried in parentheses, hard to follow. That’s where a Common Table Expression — or CTE — steps in. It’s one of those features in SQL that doesn’t just make your life easier; it makes your code readable, reusable, and, above all, maintainable.

Without any further ado, let's walk through what a CTE really is and why developers keep reaching for it, especially when queries get long, logic gets messy, or performance starts to matter.

What Is a CTE, Really?

A Common Table Expression is like a temporary result set — one that you can reference within a SELECT, INSERT, UPDATE, or DELETE statement. Think of it as giving a nickname to a subquery, except this nickname is easier to call, doesn’t clutter your main query, and can be used more than once.

It starts with a WITH clause. You define the expression, give it a name, and from there, just treat it like a table.

Here’s a quick look:

sql

CopyEdit

WITH EmployeeSales AS (

SELECT EmployeeID, SUM(SalesAmount) AS TotalSales

FROM Sales

GROUP BY EmployeeID

)

SELECT * FROM EmployeeSales

WHERE TotalSales > 50000;

Instead of stuffing that aggregation logic directly into the WHERE clause or duplicating it, you let the CTE handle it. Short. Clear. You can breathe.

Why Use a CTE Instead of a Subquery?

You could argue that CTEs and subqueries solve the same problems. And sometimes, yes — they can. But CTEs do a few things better, and once you get used to them, it’s hard to go back.

1. Readability

Nested subqueries tend to go off the rails when you’re three levels deep. It’s like solving a riddle inside a puzzle inside an enigma. A CTE pulls that logic out front. You see the setup right at the top — no scrolling or deciphering parentheses.

2. Reusability

Here’s something subqueries can’t do well: repeat themselves. If you need to use the same derived set multiple times, you'd have to duplicate that entire subquery. With a CTE, you define it once and reuse it — no extra cost in readability.

3. Recursion

This one’s big. CTEs allow recursion, which is a game-changer for hierarchical data. Whether you’re climbing an org chart or breaking down categories and subcategories, a recursive CTE lets you walk through those levels with just one query.

Step-by-Step: How to Write and Use a CTE

If you've never written one before, it can feel a bit abstract. But once you’ve written it once, it clicks. Here's how to break it down.

Step 1: Start With the WITH Clause

You begin with WITH, followed by the name you’re giving your temporary result. This name should follow the same naming rules as any other table or alias.

sql

CopyEdit

WITH DepartmentCount AS (

SELECT DepartmentID, COUNT(*) AS EmployeeCount

FROM Employees

GROUP BY DepartmentID

)

That’s your setup. Nothing will run until you call this in a query.

Step 2: Reference the CTE Like a Table

Now that you’ve defined DepartmentCount, you can call it directly in your main query.

sql

CopyEdit

SELECT d.DepartmentName, dc.EmployeeCount

FROM DepartmentCount dc

JOIN Departments d ON dc.DepartmentID = d.DepartmentID;

The DepartmentCount CTE is treated just like any table — no special syntax required.

Step 3: Stack Multiple CTEs (If Needed)

Yes, you can have more than one. Just separate them with commas.

sql

CopyEdit

WITH

DepartmentCount AS (

SELECT DepartmentID, COUNT(*) AS EmployeeCount

FROM Employees

GROUP BY DepartmentID

),

HighHeadcount AS (

SELECT DepartmentID

FROM DepartmentCount

WHERE EmployeeCount > 10

)

SELECT d.DepartmentName

FROM HighHeadcount h

JOIN Departments d ON h.DepartmentID = d.DepartmentID;

You define both CTEs upfront, and each can reference the one above it. No re-nesting required. This is how you untangle logic without breaking it apart.

Step 4: Use Recursive CTEs for Hierarchies

Recursive CTEs handle scenarios where you need to walk through parent-child relationships. These are rare in everyday work, but invaluable when you need them.

sql

CopyEdit

WITH OrgChart AS (

SELECT EmployeeID, ManagerID, 0 AS Level

FROM Employees

WHERE ManagerID IS NULL

UNION ALL

SELECT e.EmployeeID, e.ManagerID, oc.Level + 1

FROM Employees e

JOIN OrgChart oc ON e.ManagerID = oc.EmployeeID

)

SELECT * FROM OrgChart;

This query starts with top-level employees and keeps pulling in their direct reports until it reaches the bottom. The recursive logic keeps stacking rows until no more children are found.

When CTEs Don’t Stick Around

A CTE isn’t stored. It lives during the execution of the statement and vanishes right after. So, if you think of creating something permanent for reuse across multiple queries, that’s where views or temp tables come in.

Also, it's worth noting that a CTE isn't always the most efficient choice. If you need to reuse logic in different queries or across sessions, the better move might be to save the logic in a view or procedure. But for single-use readability? The CTE wins, hands down.

Final Thoughts

CTEs don’t just clean up your code — they change how you think through it. By lifting logic out of deep subqueries, giving it a name, and letting you write in steps, they bring structure to SQL that’s easier to write, easier to test, and easier to debug.

They encourage modular thinking, which helps you spot inefficiencies sooner. And if you're working with a team, they make your queries far easier for others to follow. Next time your query looks like a jungle of joins and filters, try rewriting it with a CTE. You’ll see where the complexity lives, isolate it, and keep your core query focused. Once you get used to it, you’ll wonder how you ever wrote SQL without it.

Advertisement

You May Like

Top

Getting Started with Apache Oozie: Build Reliable Hadoop Workflows with XML

Learn how Apache Oozie coordinates Hadoop jobs with XML workflows, time-based triggers, and clean orchestration. Ideal for production-ready data pipelines and complex ETL chains

Jun 17, 2025
Read
Top

Assigning DOIs to Datasets and Models for Better Research

How do we keep digital research accessible and citable over time? Learn how assigning DOIs to datasets and models supports transparency, reproducibility, and proper credit in modern research

Jun 30, 2025
Read
Top

Why Vyper Is Gaining Ground in Smart Contract Development

Curious why developers are switching from Solidity to Vyper? Learn how Vyper simplifies smart contract development by focusing on safety, predictability, and auditability—plus how to set it up locally

Jul 06, 2025
Read
Top

Inside Q-Learning: From Tables to Smarter Decisions

How Q-learning works in real environments, from action selection to convergence. Understand the key elements that shape Q-learning and its role in reinforcement learning tasks

Jul 01, 2025
Read
Top

Running Stable Diffusion with JAX and Flax: What You Need to Know

How Stable Diffusion in JAX improves speed, scalability, and reproducibility. Learn how it compares to PyTorch and why Flax diffusion models are gaining traction

Jun 30, 2025
Read
Top

Enhancing CLIP Accuracy with Remote Sensing (Satellite) Images and Captions

How fine-tuning CLIP with satellite data improves its performance in interpreting remote sensing images and captions for tasks like land use mapping and disaster monitoring

Jul 04, 2025
Read
Top

The Rise of Shadow AI: Why Unapproved Tools Are a Growing Risk in the Workplace

Is your team using AI tools you don’t know about? Shadow AI is growing inside companies fast—learn how to manage it without stifling innovation or exposing your data

Jul 23, 2025
Read
Top

How Google Cloud Platform Drives Innovation and Scalability in 2025

Explore how Google Cloud Platform (GCP) powers scalable, efficient, and secure applications in 2025. Learn why developers choose GCP for data analytics, app development, and cloud infrastructure

Jun 19, 2025
Read
Top

Understanding the Annotated Diffusion Model in AI Image Generation

How the Annotated Diffusion Model transforms the image generation process with transparency and precision. Learn how this AI technique reveals each step of creation in clear, annotated detail

Jul 01, 2025
Read
Top

How CodeParrot Was Trained from Scratch Using Python Code

A detailed look at training CodeParrot from scratch, including dataset selection, model architecture, and its role as a Python-focused code generation model

Jul 04, 2025
Read
Top

How to Convert Transformers to ONNX with Hugging Face Optimum for Faster Inference

How to convert transformers to ONNX with Hugging Face Optimum to speed up inference, reduce memory usage, and make your models easier to deploy across platforms

Jul 01, 2025
Read
Top

Getting Started with Your First ML Project: A Beginner Guide to Machine Learning

Curious about how to start your first machine learning project? This beginner-friendly guide walks you through choosing a topic, preparing data, selecting a model, and testing your results in plain language

Jul 01, 2025
Read