SQL Common Table Expressions (CTEs) are an essential feature for simplifying complex queries, improving readability, and managing intermediate result sets. A CTE is a temporary result set that can be referenced within a SELECT
, INSERT
, UPDATE
, or DELETE
statement. CTEs are especially helpful when working with recursive queries, breaking down complex logic, and organizing query components into modular chunks.
A Common Table Expression (CTE) is essentially a temporary named result set that can be referenced within a SQL query. CTEs are defined at the beginning of a query and are used to improve query organization and readability.
CTEs are especially useful for:
WITH cte_name AS (
-- Subquery (CTE definition)
SELECT column1, column2
FROM table_name
WHERE condition
)
-- Main query
SELECT * FROM cte_name;
WITH
: Starts the definition of the CTE.cte_name
: The name of the CTE.Let’s say you have an employees
table and you need to find all employees with a salary greater than the average salary in the company. You could use a CTE to simplify the query.
WITH avg_salary AS (
SELECT AVG(salary) AS average_salary
FROM employees
)
SELECT first_name, last_name, salary
FROM employees
WHERE salary > (SELECT average_salary FROM avg_salary);
Explanation:
avg_salary
calculates the average salary from the employees
table.A recursive CTE is a type of CTE that references itself in order to solve problems that involve hierarchical or recursive data. Recursive CTEs are especially useful when working with data like organizational structures, bill-of-materials, or hierarchical relationships.
A recursive CTE generally consists of two parts:
WITH RECURSIVE cte_name AS (
-- Base query: Starting point of recursion
SELECT column1, column2
FROM table_name
WHERE condition
UNION ALL
-- Recursive query: References the CTE itself
SELECT column1, column2
FROM table_name
JOIN cte_name ON table_name.column = cte_name.column
)
SELECT * FROM cte_name;
Let’s say you have an employees
table with columns employee_id
, manager_id
, first_name
, and last_name
. You want to find the organizational hierarchy, i.e., all employees who report to a given manager and their subordinates.
WITH RECURSIVE org_hierarchy AS (
-- Base case: Select the manager
SELECT employee_id, manager_id, first_name, last_name
FROM employees
WHERE manager_id IS NULL -- Root level (CEO)
UNION ALL
-- Recursive case: Select employees who report to the previous level
SELECT e.employee_id, e.manager_id, e.first_name, e.last_name
FROM employees e
INNER JOIN org_hierarchy oh ON e.manager_id = oh.employee_id
)
SELECT * FROM org_hierarchy;
Explanation:
manager_id
is NULL
).employees
table with the org_hierarchy
CTE, effectively finding all employees who report to the previously selected employees, and so on.CTEs help break down complex queries into logical parts, making them easier to read and understand. Instead of nesting subqueries within other queries, you can use CTEs to organize intermediate result sets and keep the query structure cleaner.
Once defined, CTEs can be reused multiple times within the same query. This eliminates the need to repeat subqueries and makes the query more efficient and easier to maintain.
In some cases, CTEs can help optimize query performance. By defining intermediate results, the database can potentially reuse the results of the CTE across multiple parts of the query, reducing the amount of computation needed.
CTEs provide a simple way to perform recursive queries, such as navigating hierarchical structures (e.g., organizational charts, product categories, and bill-of-materials). Recursive queries can be extremely complex, but using CTEs simplifies the process.
While CTEs provide many benefits, they also have some limitations: