CTE stands for Common Table Expression. It is a temporary named result set that you can reference within a SELECT, INSERT, UPDATE, or DELETE statement.
Click to reveal answer
beginner
How do you define multiple CTEs in a single SQL query?
You define multiple CTEs by separating each CTE with a comma after the WITH keyword. Each CTE has its own name and query inside the same WITH clause.
Click to reveal answer
intermediate
Why use multiple CTEs in one query?
Using multiple CTEs helps break down complex queries into smaller, easier-to-understand parts. Each CTE can build on the previous ones, making the query clearer and more organized.
Click to reveal answer
beginner
Write a simple example of two CTEs used in one query.
WITH first_cte AS (SELECT 1 AS num), second_cte AS (SELECT num + 1 AS num_plus_one FROM first_cte) SELECT * FROM second_cte;
Click to reveal answer
intermediate
Can CTEs reference each other in the same WITH clause?
Yes, CTEs can reference earlier CTEs defined before them in the same WITH clause, but not the ones defined after.
Click to reveal answer
How do you separate multiple CTEs in a single SQL query?
AWith a comma
BWith a semicolon
CWith the AND keyword
DWith the OR keyword
✗ Incorrect
Multiple CTEs are separated by commas within the WITH clause.
Which keyword starts the definition of CTEs in a SQL query?
ASELECT
BJOIN
CWITH
DFROM
✗ Incorrect
The WITH keyword starts the CTE definitions.
Can a CTE reference another CTE defined after it in the same WITH clause?
AOnly in PostgreSQL
BYes, always
COnly if you use UNION
DNo, only earlier CTEs can be referenced
✗ Incorrect
A CTE can only reference CTEs defined before it in the same WITH clause.
What is the main benefit of using multiple CTEs in one query?
ATo make queries run faster
BTo break complex queries into simpler parts
CTo avoid using indexes
DTo store data permanently
✗ Incorrect
Multiple CTEs help organize complex queries into simpler, readable parts.
Which of the following is a valid way to start multiple CTEs?
AWITH cte1 AS (...), cte2 AS (...)
BWITH cte1 AS (...); WITH cte2 AS (...)
CSELECT cte1 AS (...), cte2 AS (...)
DFROM cte1, cte2
✗ Incorrect
Multiple CTEs are defined together after a single WITH keyword, separated by commas.
Explain how to write multiple CTEs in one SQL query and why it is useful.
Think about how you can organize a big task into smaller steps.
You got /5 concepts.
Describe the rules for referencing CTEs within multiple CTEs in the same query.
Consider the order you read a list from top to bottom.
You got /4 concepts.
Practice
(1/5)
1. What is the main purpose of using multiple CTEs (Common Table Expressions) in a single PostgreSQL query?
easy
A. To speed up the database server hardware
B. To create multiple databases at once
C. To permanently store data in the database
D. To break a complex query into smaller, readable parts
Solution
Step 1: Understand what CTEs do
CTEs let you write parts of a query separately with names, making complex queries easier to read.
Step 2: Identify the purpose of multiple CTEs
Using multiple CTEs helps organize and simplify complex logic by splitting it into smaller named queries.
Final Answer:
To break a complex query into smaller, readable parts -> Option D
Quick Check:
Multiple CTEs = Query readability [OK]
Hint: Think of CTEs as named steps in a recipe [OK]
Common Mistakes:
Confusing CTEs with permanent tables
Thinking CTEs improve hardware speed
Assuming CTEs create databases
2. Which of the following is the correct syntax to define two CTEs named cte1 and cte2 in one PostgreSQL query?
easy
A. WITH cte1 AS (SELECT * FROM table1), cte2 AS (SELECT * FROM table2) SELECT * FROM cte1 JOIN cte2 ON cte1.id = cte2.id;
B. WITH cte1 (SELECT * FROM table1); WITH cte2 (SELECT * FROM table2); SELECT * FROM cte1, cte2;
C. WITH cte1 = SELECT * FROM table1, cte2 = SELECT * FROM table2 SELECT * FROM cte1 JOIN cte2;
D. WITH cte1 AS SELECT * FROM table1, cte2 AS SELECT * FROM table2 SELECT * FROM cte1 JOIN cte2;
Solution
Step 1: Recall correct CTE syntax
CTEs start with WITH, each named, followed by AS and a query in parentheses, separated by commas.
Step 2: Check each option's syntax
WITH cte1 AS (SELECT * FROM table1), cte2 AS (SELECT * FROM table2) SELECT * FROM cte1 JOIN cte2 ON cte1.id = cte2.id; correctly uses commas, AS, and parentheses. Others miss parentheses or use wrong separators.
Final Answer:
WITH cte1 AS (SELECT * FROM table1), cte2 AS (SELECT * FROM table2) SELECT * FROM cte1 JOIN cte2 ON cte1.id = cte2.id; -> Option A
Quick Check:
Correct CTE syntax = WITH cte1 AS (SELECT * FROM table1), cte2 AS (SELECT * FROM table2) SELECT * FROM cte1 JOIN cte2 ON cte1.id = cte2.id; [OK]
Hint: Remember: WITH cte_name AS (query), separate multiple CTEs by commas [OK]
Common Mistakes:
Omitting parentheses around CTE queries
Using semicolons between CTEs
Using '=' instead of AS
3. Given the following query, what will be the output?
WITH cte1 AS (SELECT 1 AS num), cte2 AS (SELECT num * 2 AS double_num FROM cte1) SELECT * FROM cte2;
medium
A. [{num: 2}]
B. [{num: 1, double_num: 2}]
C. [{double_num: 2}]
D. Syntax error
Solution
Step 1: Analyze cte1
cte1 returns one row with column num = 1.
Step 2: Analyze cte2 using cte1
cte2 selects num * 2 as double_num, so double_num = 1 * 2 = 2.
Step 3: Final SELECT from cte2
Only double_num column is selected, so output is [{double_num: 2}].
Final Answer:
[{double_num: 2}] -> Option C
Quick Check:
cte2 output columns = double_num [OK]
Hint: Check which columns each CTE outputs carefully [OK]
Common Mistakes:
Assuming cte2 includes all columns from cte1
Expecting num column in final output
Thinking query has syntax errors
4. Identify the error in this query using multiple CTEs:
WITH cte1 AS (SELECT id, name FROM users), cte2 AS (SELECT id, age FROM users) SELECT cte1.id, cte1.name, cte2.age FROM cte1 JOIN cte2 ON cte1.id = cte2.user_id;
medium
A. CTEs must be defined with semicolons
B. Column cte2.user_id does not exist
C. Missing comma between CTEs
D. Cannot join two CTEs in one query
Solution
Step 1: Check CTE definitions
Both cte1 and cte2 select id and other columns from users table correctly.
Step 2: Check JOIN condition
Query joins on cte1.id = cte2.user_id, but cte2 has no user_id column, only id.
Step 3: Identify error
Using cte2.user_id causes a column not found error.
Final Answer:
Column cte2.user_id does not exist -> Option B
Quick Check:
Check column names in JOIN = Column cte2.user_id does not exist [OK]
Hint: Verify column names in JOIN conditions carefully [OK]
Common Mistakes:
Assuming user_id exists in cte2
Thinking semicolons separate CTEs
Believing CTEs cannot be joined
5. You want to calculate the average order amount per customer and then find customers whose average order is above 100. Which query correctly uses multiple CTEs to achieve this?
hard
A. WITH avg_orders AS (SELECT customer_id, AVG(amount) AS avg_amount FROM orders GROUP BY customer_id), high_avg AS (SELECT customer_id FROM avg_orders WHERE avg_amount > 100) SELECT * FROM high_avg;
B. WITH avg_orders AS (SELECT customer_id, SUM(amount) AS avg_amount FROM orders GROUP BY customer_id), high_avg AS (SELECT customer_id FROM avg_orders WHERE avg_amount > 100) SELECT * FROM high_avg;
C. WITH avg_orders AS (SELECT customer_id, AVG(amount) AS avg_amount FROM orders), high_avg AS (SELECT customer_id FROM avg_orders WHERE avg_amount > 100) SELECT * FROM high_avg;
D. WITH avg_orders AS (SELECT customer_id, AVG(amount) AS avg_amount FROM orders GROUP BY customer_id) SELECT * FROM avg_orders WHERE avg_amount > 100;
Solution
Step 1: Calculate average order per customer
WITH avg_orders AS (SELECT customer_id, AVG(amount) AS avg_amount FROM orders GROUP BY customer_id), high_avg AS (SELECT customer_id FROM avg_orders WHERE avg_amount > 100) SELECT * FROM high_avg; correctly uses AVG(amount) with GROUP BY customer_id in avg_orders CTE.
Step 2: Filter customers with avg_amount > 100
WITH avg_orders AS (SELECT customer_id, AVG(amount) AS avg_amount FROM orders GROUP BY customer_id), high_avg AS (SELECT customer_id FROM avg_orders WHERE avg_amount > 100) SELECT * FROM high_avg; uses a second CTE high_avg to select customers meeting the condition.
Step 3: Final SELECT returns customers with high average orders
WITH avg_orders AS (SELECT customer_id, AVG(amount) AS avg_amount FROM orders GROUP BY customer_id), high_avg AS (SELECT customer_id FROM avg_orders WHERE avg_amount > 100) SELECT * FROM high_avg; selects all from high_avg, giving correct result.
Final Answer:
WITH avg_orders AS (SELECT customer_id, AVG(amount) AS avg_amount FROM orders GROUP BY customer_id), high_avg AS (SELECT customer_id FROM avg_orders WHERE avg_amount > 100) SELECT * FROM high_avg; -> Option A
Quick Check:
Correct aggregation and filtering = WITH avg_orders AS (SELECT customer_id, AVG(amount) AS avg_amount FROM orders GROUP BY customer_id), high_avg AS (SELECT customer_id FROM avg_orders WHERE avg_amount > 100) SELECT * FROM high_avg; [OK]
Hint: Use one CTE for aggregation, another for filtering [OK]
Common Mistakes:
Using SUM instead of AVG for average calculation
Missing GROUP BY clause
Not filtering in a separate CTE
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.