Common Table Expressions (WITH) in MySQL - Time & Space Complexity
When using Common Table Expressions (CTEs), it's important to understand how the query's work grows as the data grows.
We want to know how the number of operations changes when the input data gets bigger.
Analyze the time complexity of the following code snippet.
WITH recent_orders AS (
SELECT * FROM orders WHERE order_date >= '2024-01-01'
)
SELECT customer_id, COUNT(*) AS order_count
FROM recent_orders
GROUP BY customer_id;
This code first selects recent orders using a CTE, then counts orders per customer.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Scanning the orders table to find recent orders.
- How many times: Once for the CTE, then grouping over the filtered results.
As the number of orders grows, the database must scan more rows to find recent orders and then group them.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 rows scanned and grouped |
| 100 | About 100 rows scanned and grouped |
| 1000 | About 1000 rows scanned and grouped |
Pattern observation: The work grows roughly in direct proportion to the number of rows scanned.
Time Complexity: O(n)
This means the time to run the query grows roughly in a straight line as the number of orders increases.
[X] Wrong: "Using a CTE makes the query run faster because it stores results."
[OK] Correct: The CTE is just a temporary result used during the query. It does not automatically speed up the scan or grouping steps.
Understanding how CTEs affect query time helps you explain your choices clearly and shows you know how databases handle data behind the scenes.
"What if we added an index on order_date? How would the time complexity change?"
Practice
WITH clause (Common Table Expression) in a MySQL query?Solution
Step 1: Understand the role of WITH clause
The WITH clause defines a temporary named result set, called a Common Table Expression (CTE), which exists only during the execution of the query.Step 2: Differentiate from permanent operations
Unlike creating tables or indexes, CTEs do not store data permanently but help organize complex queries by breaking them into parts.Final Answer:
To create a temporary named result set that can be referenced within the main query -> Option BQuick Check:
WITH clause = temporary named result set [OK]
- Thinking WITH creates permanent tables
- Confusing WITH with DELETE or UPDATE commands
- Assuming WITH creates indexes
Solution
Step 1: Recall the standard syntax for CTE
The correct syntax to define a CTE starts with the keyword WITH, followed by the CTE name, AS, and then the query in parentheses.Step 2: Compare options with syntax
Only WITH cte_name AS (SELECT * FROM table_name) matches the correct syntax: WITH cte_name AS (SELECT * FROM table_name). Other options use invalid keywords or structure.Final Answer:
WITH cte_name AS (SELECT * FROM table_name) -> Option DQuick Check:
WITH + name + AS + (query) = correct syntax [OK]
- Using CREATE or DEFINE instead of WITH
- Omitting AS keyword
- Not enclosing query in parentheses
WITH SalesCTE AS ( SELECT product_id, SUM(quantity) AS total_qty FROM sales GROUP BY product_id ) SELECT * FROM SalesCTE WHERE total_qty > 100;
Solution
Step 1: Analyze the CTE definition
The CTE named SalesCTE calculates total quantity sold per product by grouping sales by product_id and summing quantity.Step 2: Understand the main query filter
The main query selects rows from SalesCTE where total_qty is greater than 100, so only products with sales above 100 units appear.Final Answer:
All products with total quantity sold greater than 100 -> Option AQuick Check:
CTE sums and filters total_qty > 100 [OK]
- Confusing > 100 with <= 100
- Thinking GROUP BY is missing (it is present)
- Assuming CTE is unused or causes error
WITH cte AS ( SELECT id, name FROM users ) SELECT * FROM cte WHERE age > 30;
Solution
Step 1: Check columns selected in CTE
The CTE selects only 'id' and 'name' columns from users table; 'age' is not included.Step 2: Analyze main query filter
The main query tries to filter on 'age', which is not part of the CTE result, causing an error.Final Answer:
Column 'age' does not exist in the CTE result -> Option CQuick Check:
Filter column must be in CTE output [OK]
- Assuming semicolon needed inside CTE
- Thinking CTE name 'cte' is invalid
- Believing WITH must precede INSERT
Solution
Step 1: Check CTE calculation and grouping
WITH CustomerTotals AS ( SELECT customer_id, SUM(amount) AS total_amount FROM orders GROUP BY customer_id ) SELECT customer_id, total_amount FROM CustomerTotals ORDER BY total_amount DESC LIMIT 3; correctly groups orders by customer_id and sums amount inside the CTE.Step 2: Verify ordering and limiting in main query
WITH CustomerTotals AS ( SELECT customer_id, SUM(amount) AS total_amount FROM orders GROUP BY customer_id ) SELECT customer_id, total_amount FROM CustomerTotals ORDER BY total_amount DESC LIMIT 3; orders by total_amount descending and limits to top 3 customers outside the CTE, which is valid in MySQL.Step 3: Analyze other options for errors
WITH CustomerTotals AS ( SELECT customer_id, amount FROM orders ) SELECT customer_id, SUM(amount) AS total_amount FROM CustomerTotals GROUP BY customer_id ORDER BY total_amount DESC LIMIT 3; does not sum inside CTE, causing incorrect grouping. WITH CustomerTotals AS ( SELECT customer_id, SUM(amount) AS total_amount FROM orders ) SELECT * FROM CustomerTotals LIMIT 3; misses GROUP BY and ordering. WITH CustomerTotals AS ( SELECT customer_id, SUM(amount) AS total_amount FROM orders GROUP BY customer_id ORDER BY total_amount DESC LIMIT 3 ) SELECT * FROM CustomerTotals; tries to use ORDER BY and LIMIT inside CTE, which is invalid in MySQL.Final Answer:
Option A query correctly finds top 3 customers by total purchase amount -> Option AQuick Check:
Group and sum in CTE, order and limit outside [OK]
- Placing ORDER BY and LIMIT inside CTE
- Not grouping before summing
- Trying to sum outside CTE without grouping
Ready to prove it?
Pass the test and this pattern moves unknown
