ποΈ 02092025 1020
1. What is a CTE?β
A Common Table Expression (CTE) is a temporary result set defined using WITH and used within a single query.
Think of it like creating a named subquery that improves readability and reusability.
WITH recent_orders AS (   SELECT id, user_id, created_at   FROM orders   WHERE created_at > NOW() - INTERVAL '30 days' ) SELECT user_id, COUNT(*) AS total_orders FROM recent_orders GROUP BY user_id;
Key traits β
- Defined once, referenced many times.
 - Scope = the main query only.
 - Can chain multiple CTEs in one 
WITHblock. 
2. Why Use a CTE?β
| Use Case | Why CTEs Help | 
|---|---|
| Readability | Break complex queries into logical steps | 
| Reusability | Avoid repeating the same subquery multiple times | 
| Composability | Chain transformations easily | 
| Recursive traversal | Perfect for trees, hierarchies, and graphs | 
3. Non-Recursive CTEsβ
Most CTEs are non-recursive β evaluated once like a normal subquery.
WITH top_customers AS (   SELECT user_id, SUM(amount) AS total_spent   FROM orders   GROUP BY user_id   HAVING SUM(amount) > 5000 ) SELECT u.name, t.total_spent FROM users u JOIN top_customers t ON u.id = t.user_id;
Execution π§
- CTE is materialized once.
 - The query planner inlines it in many engines (Postgres, MySQL 8+).
 - Acts like a temporary view.
 
4. Recursive CTEsβ
A CTE becomes recursive when it references itself in its definition.
Used for hierarchical data, graphs, paths, ancestor/descendant trees.
Structureβ
WITH RECURSIVE cte_name AS (     -- Anchor (base case)     SELECT ...     FROM ...     WHERE ...      UNION ALL      -- Recursive member (self-referencing step)     SELECT ...     FROM ...     JOIN cte_name c ON ... ) SELECT * FROM cte_name;
Key points β
- Requires 
WITH RECURSIVE(in Postgres/MySQL 8+). - Anchor = starting rows.
 - Recursive step = generates the βnext levelβ.
 - Stops when the recursive step returns 0 new rows.
 
5. Simple Recursive Exampleβ
Problem: Get all employees reporting under a specific manager.
WITH RECURSIVE subordinates AS (     -- Anchor: start from the given manager     SELECT id, name, manager_id     FROM employees     WHERE id = 1  -- CEO      UNION ALL      -- Recursive step: find direct reports     SELECT e.id, e.name, e.manager_id     FROM employees e     JOIN subordinates s ON e.manager_id = s.id ) SELECT * FROM subordinates;
How it works π§
- Start with 
id=1(anchor row). - Find employees where 
manager_id=1. - For each result, repeat the process.
 - Stops when there are no more reports.
 
6. How the Engine Executes Recursive CTEsβ
- Engine splits the recursive CTE into:
- Anchor member β initial result set.
 - Recursive member β applied repeatedly.
 
 - Maintains a working table for βnew rowsβ.
 - Iterates until no more rows are added.
 
Iteration 1 β Anchor rows Iteration 2 β Anchor + Recursive step 1 Iteration 3 β Previous + Recursive step 2 ... Stops when Recursive step returns 0 rows.
7. Performance Tipsβ
| Tip | Why | 
|---|---|
Use UNION ALL instead of UNION | Avoids unnecessary de-duplication work | 
Deduplicate early (DISTINCT) | Prevents exponential growth | 
| Carry fewer columns | Smaller working sets = less memory | 
| Add indexes on join keys | Recursive joins become faster | 
| Limit recursion depth if needed | Prevent runaway loops | 
8. Quick Summary Tableβ
| Type | Keyword | Self-Reference | Evaluated | Use Case | 
|---|---|---|---|---|
| Non-recursive | WITH | β No | Once | Simplify queries | 
| Recursive | WITH RECURSIVE | β Yes | Iteratively | Trees, graphs | 
Do you want me to also make a visual diagram showing: