That makes the final filtering straightforward.
📈 6. CTE + JOIN
CTEs become even more useful when combined with JOINs.
WITH customer_sales AS (
SELECT
customer_id,
SUM(amount) AS total_spending
FROM orders
GROUP BY customer_id
)
SELECT
c.customer_name,
cs.total_spending
FROM customers c
JOIN customer_sales cs
ON c.customer_id = cs.customer_id;
• The CTE handles the aggregation.
• The main query handles the customer information.
💰 7. CTE + COALESCE
Want to include customers who haven't placed orders?
WITH customer_sales AS (
SELECT
customer_id,
SUM(amount) AS total_spending
FROM orders
GROUP BY customer_id
)
SELECT
c.customer_id,
c.customer_name,
COALESCE(cs.total_spending, 0) AS total_spending
FROM customers c
LEFT JOIN customer_sales cs
ON c.customer_id = cs.customer_id;
Now customers without orders appear with:
total_spending = 0🧮 8. CTE + CASE
We can also create business segments.
WITH customer_sales AS (
SELECT
customer_id,
SUM(amount) AS total_spending
FROM orders
GROUP BY customer_id
)
SELECT
customer_id,
total_spending,
CASE
WHEN total_spending >= 100000 THEN 'VIP'
WHEN total_spending >= 50000 THEN 'Premium'
ELSE 'Standard'
END AS customer_segment
FROM customer_sales;
• The CTE creates the metric.
• "CASE" converts the metric into business categories.
🔍 9. CTE vs Subquery
Both can solve similar problems.
• Subquery
SELECT *
FROM (
SELECT
customer_id,
SUM(amount) AS total_spending
FROM orders
GROUP BY customer_id
) AS customer_sales
WHERE total_spending > 50000;
• CTE
WITH customer_sales AS (
SELECT
customer_id,
SUM(amount) AS total_spending
FROM orders
GROUP BY customer_id
)
SELECT *
FROM customer_sales
WHERE total_spending > 50000;
The CTE often makes multi-step logic easier to read.
🧠 10. CTE vs Temporary Table
A CTE is not the same as a permanent table.
• CTE
WITH sales AS (...)
SELECT ...
Generally exists only for the duration of that SQL statement.
• Temporary table
CREATE TEMP TABLE sales AS
SELECT ...;
A temporary table can generally be referenced by multiple statements during its session, depending on the database.
Simple distinction:
• CTE → temporary named query result
• Temporary table → temporary database object
⚡ 11. CTE Does Not Automatically Mean Faster
A common misconception is:
CTEs make queries faster. Not necessarily.
CTEs primarily improve:
• readability
• organization
• maintainability
• debugging
• step-by-step logic
Performance depends on the database engine and how it optimizes the query. Some databases may inline a CTE, while others may materialize it in certain situations.
So: Use CTEs for clear logic, not simply because you expect better performance.
🧪 12. CTE for Data Quality Analysis
Suppose we want to identify customers with missing contact information.
First create a cleaned customer dataset:
WITH cleaned_customers AS (
SELECT
customer_id,
TRIM(customer_name) AS customer_name,
LOWER(TRIM(email)) AS email
FROM customers
)
SELECT *
FROM cleaned_customers
WHERE email IS NULL;
This creates a clean intermediate layer before analysis.
📊 13. CTE for KPI Calculation
Suppose we want: «Revenue per customer.»