A Common Table Expression (CTE) is a temporary named result set that exists only during the execution of a single SQL query.
CTEs improve query readability, simplify complex SQL statements, and make large queries easier to maintain. SQL CTE Practice questions with solutions help to understand the concepts.
A CTE is created using the WITH keyword.
Unlike subqueries, CTEs can be referenced multiple times within the same query, making them ideal for reporting and data analysis.
Why Use SQL CTE?
CTEs help you:
- Improve query readability
- Break complex queries into smaller logical parts
- Reuse query results within the same statement
- Simplify joins and aggregations
- Improve report development
- Build recursive queries
CTEs are widely used in:
- Data Analytics
- Business Intelligence
- Financial Reporting
- HR Dashboards
- Sales Analysis
- SQL Interviews
Basic Syntax
WITH cte_name AS
(
SELECT column1,
column2
FROM table_name
)
SELECT *
FROM cte_name;
Sample Table Used Throughout This Chapter
employees
| employee_id | employee_name | department | salary |
|---|---|---|---|
| 101 | Aman | HR | 45000 |
| 102 | Riya | IT | 70000 |
| 103 | Vikas | Finance | 85000 |
| 104 | Neha | HR | 50000 |
| 105 | Karan | IT | 60000 |
| 106 | Simran | Marketing | 90000 |
1. SQL CTE to Display Employees Earning More Than ₹50,000
Problem Statement
The HR department wants to generate a report of employees earning more than ₹50,000.
Instead of writing a long query, use a Common Table Expression (CTE).
SQL Solution
WITH high_salary AS
(
SELECT
employee_name,
department,
salary
FROM employees
WHERE salary > 50000
)
SELECT *
FROM high_salary;
Sample Output
| employee_name | department | salary |
|---|---|---|
| Riya | IT | 70000 |
| Vikas | Finance | 85000 |
| Karan | IT | 60000 |
| Simran | Marketing | 90000 |
Explanation
The CTE named high_salary temporarily stores employees whose salary exceeds ₹50,000.
The main query simply retrieves all rows from the CTE.
This approach makes the SQL query cleaner and easier to understand.
Concepts Covered
- WITH Clause
- Basic CTE
- Temporary Result Set
2. SQL CTE to Display IT Department Employees
Problem Statement
A company wants to generate a report showing only employees working in the IT department.
Use a CTE.
SQL Solution
WITH it_employees AS
(
SELECT
employee_name,
salary
FROM employees
WHERE department = 'IT'
)
SELECT *
FROM it_employees;
Sample Output
| employee_name | salary |
|---|---|
| Riya | 70000 |
| Karan | 60000 |
Explanation
The CTE stores only IT department employees.
The outer query retrieves the prepared result set.
CTEs make department-wise reports much easier to build.
Concepts Covered
- CTE
- WHERE Clause
- Department Reports
3. SQL CTE to Calculate Average Salary by Department
Problem Statement
The HR manager wants to calculate the average salary of each department.
Use a Common Table Expression.
SQL Solution
WITH department_salary AS
(
SELECT
department,
AVG(salary) AS average_salary
FROM employees
GROUP BY department
)
SELECT *
FROM department_salary;
Sample Output
| department | average_salary |
|---|---|
| HR | 47500 |
| IT | 65000 |
| Finance | 85000 |
| Marketing | 90000 |
Explanation
The CTE performs the aggregation first.
The final query simply displays the department-wise average salary.
Using a CTE keeps aggregation logic separate from the final report.
Concepts Covered
- CTE
- GROUP BY
- AVG()
4. SQL CTE to Display Premium Products
Problem Statement
An e-commerce company wants to generate a report showing products priced above ₹20,000.
Instead of filtering directly in the main query, use a Common Table Expression (CTE).
Sample Table
products
| product_id | product_name | category | price |
|---|---|---|---|
| 101 | Laptop | Electronics | 65000 |
| 102 | Keyboard | Accessories | 1200 |
| 103 | Monitor | Electronics | 18000 |
| 104 | Tablet | Electronics | 28000 |
| 105 | Headphones | Accessories | 2500 |
| 106 | Gaming PC | Electronics | 85000 |
SQL Solution
WITH premium_products AS
(
SELECT
product_name,
category,
price
FROM products
WHERE price > 20000
)
SELECT *
FROM premium_products;
Sample Output
| product_name | category | price |
|---|---|---|
| Laptop | Electronics | 65000 |
| Tablet | Electronics | 28000 |
| Gaming PC | Electronics | 85000 |
Explanation
The CTE named premium_products stores only expensive products.
The outer query simply displays the prepared dataset.
This approach improves readability, especially when multiple reports use the same filtered data.
Concepts Covered
- WITH Clause
- CTE
- Product Database
5. SQL CTE to Generate High-Value Customer Report
Problem Statement
A retail company wants to identify customers who have spent more than ₹10,000.
Use a Common Table Expression to simplify the report.
Sample Table
customer_orders
| customer_id | customer_name | total_purchase |
|---|---|---|
| 1 | Rahul | 8500 |
| 2 | Neha | 15000 |
| 3 | Amit | 9500 |
| 4 | Priya | 22000 |
| 5 | Sneha | 18000 |
SQL Solution
WITH high_value_customers AS
(
SELECT
customer_name,
total_purchase
FROM customer_orders
WHERE total_purchase > 10000
)
SELECT *
FROM high_value_customers;
Sample Output
| customer_name | total_purchase |
|---|---|
| Neha | 15000 |
| Priya | 22000 |
| Sneha | 18000 |
Explanation
The CTE creates a temporary table containing only high-value customers.
The final query retrieves this information, making the SQL easier to understand and maintain.
This type of report is commonly used for:
- Loyalty Programs
- Marketing Campaigns
- Customer Segmentation
- Sales Analysis
Concepts Covered
- CTE
- Customer Analytics
- Business Reporting
Why Use a CTE Instead of a Subquery?
Consider the following query using a subquery:
SELECT *
FROM
(
SELECT
customer_name,
total_purchase
FROM customer_orders
WHERE total_purchase > 10000
) AS customer_data;
Now compare it with a CTE:
WITH high_value_customers AS
(
SELECT
customer_name,
total_purchase
FROM customer_orders
WHERE total_purchase > 10000
)
SELECT *
FROM high_value_customers;
Why the CTE version is better
- Easier to read
- Easier to debug
- Easier to reuse
- Better suited for complex reports
- Preferred in modern SQL development
6. SQL CTE with JOIN to Display Employee and Department Details
Problem Statement
A company stores employee information and department information in separate tables.
Generate a report showing each employee along with their department name using a CTE.
Sample Tables
employees
| employee_id | employee_name | department_id |
|---|---|---|
| 101 | Aman | 1 |
| 102 | Riya | 2 |
| 103 | Vikas | 3 |
| 104 | Neha | 2 |
| 105 | Karan | 1 |
departments
| department_id | department_name |
|---|---|
| 1 | HR |
| 2 | IT |
| 3 | Finance |
SQL Solution
WITH employee_details AS
(
SELECT
e.employee_name,
d.department_name
FROM employees e
INNER JOIN departments d
ON e.department_id = d.department_id
)
SELECT *
FROM employee_details;
Sample Output
| employee_name | department_name |
|---|---|
| Aman | HR |
| Riya | IT |
| Vikas | Finance |
| Neha | IT |
| Karan | HR |
Explanation
The CTE performs the INNER JOIN first and stores the result as a temporary table named employee_details.
The outer query simply retrieves the prepared report.
This makes complex join queries easier to read.
Concepts Covered
- CTE
- INNER JOIN
- Employee Database
7. SQL CTE with GROUP BY to Generate Department-wise Sales Report
Problem Statement
A company wants to calculate the total sales generated by each department.
Use a CTE.
Sample Table
sales
| sale_id | department | amount |
|---|---|---|
| 1 | HR | 12000 |
| 2 | IT | 18000 |
| 3 | IT | 22000 |
| 4 | Finance | 35000 |
| 5 | HR | 8000 |
SQL Solution
WITH department_sales AS
(
SELECT
department,
SUM(amount) AS total_sales
FROM sales
GROUP BY department
)
SELECT *
FROM department_sales;
Sample Output
| department | total_sales |
|---|---|
| HR | 20000 |
| IT | 40000 |
| Finance | 35000 |
Explanation
The CTE calculates total sales for each department.
The final query simply displays the summarized report.
Concepts Covered
- CTE
- GROUP BY
- SUM()
8. SQL CTE to Display Top-Selling Products
Problem Statement
A retail company wants to identify products that sold more than 100 units.
Use a CTE.
Sample Table
product_sales
| product_name | units_sold |
|---|---|
| Laptop | 120 |
| Keyboard | 85 |
| Mouse | 250 |
| Monitor | 95 |
| Tablet | 150 |
SQL Solution
WITH top_products AS
(
SELECT
product_name,
units_sold
FROM product_sales
WHERE units_sold > 100
)
SELECT *
FROM top_products;
Sample Output
| product_name | units_sold |
|---|---|
| Laptop | 120 |
| Mouse | 250 |
| Tablet | 150 |
Explanation
The CTE filters products that sold more than 100 units.
The main query retrieves the filtered dataset.
This report is commonly used in inventory and sales analysis.
Concepts Covered
- CTE
- Filtering
- Product Analytics
9. SQL CTE to Display Customers with Multiple Orders
Problem Statement
An online shopping platform wants to identify customers who have placed more than one order.
Use a CTE.
Sample Table
orders
| order_id | customer_name |
|---|---|
| 5001 | Rahul |
| 5002 | Neha |
| 5003 | Rahul |
| 5004 | Amit |
| 5005 | Neha |
| 5006 | Rahul |
SQL Solution
WITH repeat_customers AS
(
SELECT
customer_name,
COUNT(*) AS total_orders
FROM orders
GROUP BY customer_name
HAVING COUNT(*) > 1
)
SELECT *
FROM repeat_customers;
Sample Output
| customer_name | total_orders |
|---|---|
| Rahul | 3 |
| Neha | 2 |
Explanation
The CTE groups orders by customer and counts how many orders each customer has placed.
Only customers with more than one order are included.
Concepts Covered
- CTE
- COUNT()
- GROUP BY
- HAVING
10. SQL CTE to Calculate Branch-wise Revenue
Problem Statement
A company has multiple branches and wants to calculate total revenue generated by each branch.
Use a CTE.
Sample Table
branch_sales
| branch | revenue |
|---|---|
| Delhi | 250000 |
| Delhi | 180000 |
| Noida | 320000 |
| Gurgaon | 280000 |
| Noida | 150000 |
SQL Solution
WITH revenue_report AS
(
SELECT
branch,
SUM(revenue) AS total_revenue
FROM branch_sales
GROUP BY branch
)
SELECT *
FROM revenue_report;
Sample Output
| branch | total_revenue |
|---|---|
| Delhi | 430000 |
| Noida | 470000 |
| Gurgaon | 280000 |
Explanation
The CTE aggregates revenue for each branch before the final report is generated.
This type of report is useful for:
- Branch Performance
- Revenue Analysis
- Business Intelligence
- Financial Dashboards
Concepts Covered
- CTE
- SUM()
- GROUP BY
- Revenue Reporting
11. SQL Query Using Multiple CTEs
Problem Statement
A company wants to generate a report showing:
- Employees earning more than ₹50,000
- Departments where these employees work
Use multiple Common Table Expressions in a single query.
Sample Tables
employees
| employee_id | employee_name | department_id | salary |
|---|---|---|---|
| 101 | Aman | 1 | 45000 |
| 102 | Riya | 2 | 70000 |
| 103 | Vikas | 3 | 85000 |
| 104 | Neha | 2 | 52000 |
| 105 | Karan | 1 | 60000 |
departments
| department_id | department_name |
|---|---|
| 1 | HR |
| 2 | IT |
| 3 | Finance |
SQL Solution
WITH high_salary AS
(
SELECT
employee_name,
department_id,
salary
FROM employees
WHERE salary > 50000
),
department_info AS
(
SELECT
department_id,
department_name
FROM departments
)
SELECT
h.employee_name,
d.department_name,
h.salary
FROM high_salary h
INNER JOIN department_info d
ON h.department_id = d.department_id;
Sample Output
| employee_name | department_name | salary |
|---|---|---|
| Riya | IT | 70000 |
| Vikas | Finance | 85000 |
| Neha | IT | 52000 |
| Karan | HR | 60000 |
Explanation
This query creates two separate CTEs:
high_salarydepartment_info
The final query joins both CTEs to generate a complete report.
Concepts Covered
- Multiple CTEs
- JOIN
- Report Generation
12. SQL CTE with ROW_NUMBER()
Problem Statement
Display employees ranked by salary using ROW_NUMBER() inside a CTE.
SQL Solution
WITH salary_rank AS
(
SELECT
employee_name,
salary,
ROW_NUMBER() OVER
(
ORDER BY salary DESC
) AS salary_rank
FROM employees
)
SELECT *
FROM salary_rank;
Sample Output
| salary_rank | employee_name | salary |
|---|---|---|
| 1 | Vikas | 85000 |
| 2 | Riya | 70000 |
| 3 | Karan | 60000 |
| 4 | Neha | 52000 |
| 5 | Aman | 45000 |
Explanation
The CTE calculates rankings first.
The outer query simply displays the ranked result.
This technique is commonly used in:
- Leaderboards
- Salary Reports
- Sales Rankings
- Business Dashboards
Concepts Covered
- CTE
- ROW_NUMBER()
- Window Function
13. Recursive CTE to Display Employee Hierarchy
Problem Statement
A company stores managers and employees in the same table.
Generate the employee hierarchy using a Recursive CTE.
Sample Table
employees
| employee_id | employee_name | manager_id |
|---|---|---|
| 1 | CEO | NULL |
| 2 | Manager A | 1 |
| 3 | Manager B | 1 |
| 4 | Developer 1 | 2 |
| 5 | Developer 2 | 2 |
| 6 | Tester | 3 |
SQL Solution
WITH RECURSIVE employee_hierarchy AS
(
SELECT
employee_id,
employee_name,
manager_id
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT
e.employee_id,
e.employee_name,
e.manager_id
FROM employees e
INNER JOIN employee_hierarchy h
ON e.manager_id = h.employee_id
)
SELECT *
FROM employee_hierarchy;
Sample Output
| employee_name |
|---|
| CEO |
| Manager A |
| Manager B |
| Developer 1 |
| Developer 2 |
| Tester |
Explanation
A Recursive CTE repeatedly executes until no more matching rows are found.
It is commonly used for:
- Organization Charts
- Folder Structures
- Category Trees
- Bill of Materials
Concepts Covered
- Recursive CTE
- UNION ALL
- Hierarchical Data
14. SQL CTE with Aggregate Comparison
Problem Statement
Display employees earning more than the average company salary using a CTE.
SQL Solution
WITH average_salary AS
(
SELECT
AVG(salary) AS avg_salary
FROM employees
)
SELECT
employee_name,
salary
FROM employees
WHERE salary >
(
SELECT avg_salary
FROM average_salary
);
Sample Output
| employee_name | salary |
|---|---|
| Riya | 70000 |
| Vikas | 85000 |
Explanation
The CTE calculates the company average salary once.
The main query compares every employee’s salary with that value.
Concepts Covered
- CTE
- Aggregate Functions
- AVG()
15. SQL Multi-Step Business Report Using Multiple CTEs
Problem Statement
A retail company wants to generate a report showing:
- Customers whose purchases exceed ₹10,000
- Their loyalty level
Use multiple CTEs.
Sample Table
customers
| customer_name | purchase_amount |
|---|---|
| Rahul | 8500 |
| Neha | 18000 |
| Priya | 25000 |
| Amit | 6000 |
| Sneha | 14000 |
SQL Solution
WITH high_value AS
(
SELECT
customer_name,
purchase_amount
FROM customers
WHERE purchase_amount > 10000
),
loyalty AS
(
SELECT
customer_name,
purchase_amount,
CASE
WHEN purchase_amount >= 20000
THEN 'Gold'
ELSE 'Silver'
END AS loyalty_level
FROM high_value
)
SELECT *
FROM loyalty;
Sample Output
| customer_name | purchase_amount | loyalty_level |
|---|---|---|
| Neha | 18000 | Silver |
| Priya | 25000 | Gold |
| Sneha | 14000 | Silver |
Explanation
This query uses multiple CTEs to solve a business problem in stages:
high_valuefilters premium customers.loyaltyassigns a loyalty category using aCASEstatement.- The final query displays the completed report.
This modular approach is much easier to read and maintain than one large query.
Concepts Covered
- Multiple CTEs
- CASE Statement
- Business Reporting
- Multi-Step Query Design
Chapter Summary
In this chapter, you learned how to use Common Table Expressions (CTEs) to simplify SQL queries and improve readability.
A CTE is a temporary named result set created using the WITH keyword. Unlike subqueries, CTEs make complex SQL easier to understand, maintain, and debug.
Throughout this chapter, you practiced:
- Creating basic CTEs
- Filtering data using CTEs
- Using CTEs with
GROUP BY - Joining tables inside CTEs
- Using multiple CTEs in one query
- Using CTEs with window functions
- Writing recursive CTEs
- Comparing aggregated values
- Building multi-step business reports
These concepts are commonly used in modern SQL development, business intelligence, and data analytics projects.
Key Takeaways
- A CTE is created using the
WITHkeyword. - A CTE exists only during the execution of a single SQL statement.
- CTEs improve query readability and organization.
- Multiple CTEs can be declared within one query.
- CTEs work well with
JOIN,GROUP BY,CASE, and aggregate functions. - Recursive CTEs are useful for hierarchical data.
- Window functions such as
ROW_NUMBER()are frequently combined with CTEs. - CTEs are widely used in reporting, dashboards, and ETL processes.
- Understanding CTEs is important for SQL interviews and real-world projects.
- CTEs often replace deeply nested subqueries with cleaner, more maintainable SQL.
Frequently Asked Questions (FAQs)
1. What is a Common Table Expression (CTE)?
A CTE is a temporary named result set that exists only for the duration of a single SQL query.
Example:
WITH high_salary AS
(
SELECT employee_name,
salary
FROM employees
WHERE salary > 50000
)
SELECT *
FROM high_salary;
2. Why should I use a CTE?
CTEs make SQL queries:
- Easier to read
- Easier to debug
- Easier to maintain
- Easier to reuse within the same query
3. What is the difference between a CTE and a Subquery?
| CTE | Subquery |
|---|---|
Uses WITH keyword | Written inside another query |
| Improves readability | Can become difficult to read when nested |
| Can be referenced multiple times | Usually referenced once |
| Better for complex reports | Suitable for smaller queries |
4. Can multiple CTEs be used in one SQL query?
Yes.
Example:
WITH sales AS
(
SELECT *
FROM monthly_sales
),
customers AS
(
SELECT *
FROM customer_data
)
SELECT *
FROM sales;
5. What is a Recursive CTE?
A Recursive CTE repeatedly executes itself until no additional rows are returned.
It is commonly used for:
- Employee hierarchies
- Folder structures
- Category trees
- Organizational charts
6. Can I use JOIN inside a CTE?
Yes.
Example:
WITH employee_details AS
(
SELECT
e.employee_name,
d.department_name
FROM employees e
INNER JOIN departments d
ON e.department_id = d.department_id
)
SELECT *
FROM employee_details;
7. Can I use Aggregate Functions inside a CTE?
Yes.
Example:
WITH department_sales AS
(
SELECT
department,
SUM(amount) AS total_sales
FROM sales
GROUP BY department
)
SELECT *
FROM department_sales;
8. Where are SQL CTEs used in real-world applications?
CTEs are widely used in:
- Business Intelligence Dashboards
- Financial Reporting
- HR Analytics
- Sales Reports
- Customer Analytics
- Inventory Management
- Banking Systems
- Healthcare Reporting
- ETL Pipelines
- Data Warehousing
Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.
