WITH clause syntax in PostgreSQL - Time & Space Complexity
We want to understand how the time it takes to run a query with a WITH clause changes as the data grows.
How does using WITH affect the work the database does?
Analyze the time complexity of the following code snippet.
WITH recent_orders AS (
SELECT * FROM orders WHERE order_date > CURRENT_DATE - INTERVAL '7 days'
)
SELECT customer_id, COUNT(*) FROM recent_orders GROUP BY customer_id;
This query finds orders from the last 7 days and counts how many each customer made.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Scanning the orders table to find recent orders.
- How many times: Once to filter recent orders, then once to group and count by customer.
As the number of orders grows, the database must check more rows to find recent ones 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 in the orders table.
Time Complexity: O(n)
This means the time to run the query grows linearly as the number of orders increases.
[X] Wrong: "The WITH clause runs the subquery only once and does not affect performance as data grows."
[OK] Correct: Although the WITH clause runs the subquery only once, it still must scan the entire orders table to filter recent orders, so the time grows with data size.
Understanding how WITH clauses affect query time helps you write efficient queries and explain your reasoning clearly in interviews.
"What if we added an index on order_date? How would the time complexity change?"
Practice
WITH clause in PostgreSQL?Solution
Step 1: Understand the role of WITH clause
The WITH clause defines Common Table Expressions (CTEs) which are temporary named result sets used within a query.Step 2: Differentiate from other SQL commands
It does not create permanent tables, delete data, or create indexes; it only helps organize complex queries.Final Answer:
To create temporary named query results called CTEs -> Option CQuick Check:
WITH clause = Temporary named queries [OK]
- Thinking WITH creates permanent tables
- Confusing WITH with DELETE or CREATE INDEX
- Assuming WITH modifies data directly
Solution
Step 1: Recall correct WITH clause syntax
The correct syntax is: WITH cte_name AS (subquery) followed by the main SELECT using cte_name.Step 2: Check each option
WITH cte_name AS (SELECT * FROM table_name) SELECT * FROM cte_name; matches the correct syntax. Options A, B, and D have misplaced keywords or wrong order.Final Answer:
WITH cte_name AS (SELECT * FROM table_name) SELECT * FROM cte_name; -> Option DQuick Check:
WITH cte_name AS (query) = correct syntax [OK]
- Omitting AS keyword
- Placing SELECT before AS
- Using = instead of AS
WITH cte AS (SELECT id, name FROM users WHERE active = true) SELECT * FROM cte WHERE id < 5;
What will this query return?
Solution
Step 1: Analyze the CTE definition
The CTE named 'cte' selects users where active = true, so only active users are included.Step 2: Analyze the main query filtering
The main query selects from 'cte' where id < 5, so it filters active users with id less than 5.Final Answer:
All users with active = true and id less than 5 -> Option BQuick Check:
CTE filters active=true, main query filters id<5 [OK]
- Ignoring CTE filter and only applying main WHERE
- Assuming all users regardless of active status
- Thinking syntax error due to WHERE
WITH cte1 AS (SELECT * FROM orders), cte2 (SELECT * FROM customers) SELECT * FROM cte1 JOIN cte2 ON cte1.customer_id = cte2.id;
Solution
Step 1: Check syntax of multiple CTEs
Multiple CTEs must be separated by commas, each with the syntax: name AS (subquery).Step 2: Identify error in second CTE
The second CTE 'cte2' is missing the AS keyword before its subquery.Final Answer:
Missing AS keyword before the second CTE's subquery -> Option AQuick Check:
Each CTE needs AS (subquery) [OK]
- Omitting AS keyword in CTE definition
- Misplacing commas between CTEs
- Incorrect JOIN syntax confusion
Solution
Step 1: Verify correct syntax for multiple CTEs
Multiple CTEs must be separated by commas, each defined as name AS (subquery).Step 2: Check each option's syntax and logic
WITH active_users AS (SELECT * FROM users WHERE active = true), user_orders AS (SELECT * FROM orders WHERE user_id IN (SELECT id FROM active_users)) SELECT active_users.name, user_orders.order_date FROM active_users JOIN user_orders ON active_users.id = user_orders.user_id; correctly uses AS and commas, and references active_users in user_orders. Options B, C, and D have syntax errors or missing commas.Final Answer:
WITH active_users AS (SELECT * FROM users WHERE active = true), user_orders AS (SELECT * FROM orders WHERE user_id IN (SELECT id FROM active_users)) SELECT active_users.name, user_orders.order_date FROM active_users JOIN user_orders ON active_users.id = user_orders.user_id; -> Option AQuick Check:
Multiple CTEs separated by commas with AS (query) [OK]
- Missing commas between CTEs
- Omitting AS keyword
- Not referencing CTEs properly in later queries
Ready to prove it?
Pass the test and this pattern moves unknown
