Bird
Raised Fist0
SQLquery~20 mins

CTE as readable subquery replacement in SQL - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
CTE Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ query_result
intermediate
2:00remaining
Output of CTE vs Subquery for Average Salary
Given the table employees with columns id, department, and salary, what is the output of the following query using a CTE that calculates the average salary per department and then selects departments with average salary above 5000?
SQL
WITH dept_avg AS (
  SELECT department, AVG(salary) AS avg_salary
  FROM employees
  GROUP BY department
)
SELECT department
FROM dept_avg
WHERE avg_salary > 5000
ORDER BY department;
AList of departments where the average salary is greater than 5000, sorted alphabetically
BList of all employees with salary above 5000, sorted by department
CList of departments with total salary above 5000, sorted alphabetically
DSyntax error due to missing GROUP BY clause
Attempts:
2 left
💡 Hint
Think about what the CTE calculates first and what the main query filters.
📝 Syntax
intermediate
2:00remaining
Identify the Syntax Error in CTE Usage
Which option contains a syntax error in the use of a CTE?
SQL
WITH dept_count AS (
  SELECT department, COUNT(*) AS emp_count
  FROM employees
  GROUP BY department
)
SELECT * FROM dept_count WHERE emp_count > 10;
AWITH dept_count AS (SELECT department, COUNT(*) AS emp_count FROM employees GROUP BY department) SELECT * FROM dept_count WHERE emp_count > '10';
BWITH dept_count AS (SELECT department, COUNT(*) AS emp_count FROM employees GROUP BY department) SELECT * FROM dept_count WHERE emp_count > 10;
CWITH dept_count AS SELECT department, COUNT(*) AS emp_count FROM employees GROUP BY department SELECT * FROM dept_count WHERE emp_count > 10;
D;01 > tnuoc_pme EREHW tnuoc_tped MORF * TCELES )tnemtraped YB PUORG seeyolpme MORF tnuoc_pme SA )*(TNUOC ,tnemtraped TCELES( SA tnuoc_tped HTIW
Attempts:
2 left
💡 Hint
Check the parentheses around the CTE definition.
❓ optimization
advanced
2:00remaining
Optimizing Query with CTE vs Subquery
Consider a query that calculates total sales per region and then filters regions with sales above 10000. Which option shows the best use of a CTE to improve readability and avoid repeating the aggregation?
AWITH region_sales AS SELECT region, SUM(sales) AS total_sales FROM sales_data GROUP BY region SELECT region FROM region_sales WHERE total_sales > 10000;
BSELECT region FROM (SELECT region, SUM(sales) AS total_sales FROM sales_data GROUP BY region) WHERE total_sales > 10000;
CSELECT region FROM sales_data GROUP BY region HAVING SUM(sales) > 10000;
DWITH region_sales AS (SELECT region, SUM(sales) AS total_sales FROM sales_data GROUP BY region) SELECT region FROM region_sales WHERE total_sales > 10000;
Attempts:
2 left
💡 Hint
Look for correct CTE syntax and clear separation of steps.
🔧 Debug
advanced
2:00remaining
Debugging Incorrect CTE Result
A developer wrote this query to find departments with more than 5 employees, but it returns no rows. What is the likely cause?
SQL
WITH dept_emps AS (
  SELECT department, COUNT(employee_id) AS emp_count
  FROM employees
)
SELECT department FROM dept_emps WHERE emp_count > 5;
AMissing GROUP BY clause in the CTE causing emp_count to be a total count, not per department
BIncorrect alias name emp_count used in WHERE clause
CThe WHERE clause should be HAVING clause
DCTE is missing a closing parenthesis
Attempts:
2 left
💡 Hint
Check if aggregation is grouped properly.
🧠 Conceptual
expert
2:00remaining
Why Use CTE Instead of Subquery?
Which of the following is the best explanation for why using a CTE can be better than a subquery in complex SQL queries?
ACTEs always run faster than subqueries because they are cached automatically by the database engine.
BCTEs improve query readability by naming intermediate results and can be referenced multiple times, avoiding repetition.
CCTEs allow modifying data directly inside the query, unlike subqueries which are read-only.
DCTEs eliminate the need for indexes on tables used in the query.
Attempts:
2 left
💡 Hint
Think about how CTEs help organize complex queries.

Practice

(1/5)
1. What is the main benefit of using a WITH clause (CTE) instead of a nested subquery in SQL?
easy
A. It always runs faster than nested subqueries.
B. It makes the query easier to read and maintain by naming parts of the query.
C. It removes the need for any JOIN operations.
D. It automatically indexes the tables used in the query.

Solution

  1. Step 1: Understand the purpose of CTEs

    CTEs (Common Table Expressions) allow you to name a subquery, making the SQL easier to read and organize.
  2. Step 2: Compare with nested subqueries

    Nested subqueries can be hard to read because they are embedded inside other queries without a clear name.
  3. Final Answer:

    It makes the query easier to read and maintain by naming parts of the query. -> Option B
  4. Quick Check:

    CTEs improve readability = A [OK]
Hint: CTEs name subqueries for clarity and maintenance [OK]
Common Mistakes:
  • Thinking CTEs always improve performance
  • Believing CTEs remove the need for JOINs
  • Assuming CTEs create indexes automatically
2. Which of the following is the correct syntax to start a CTE in SQL?
easy
A. WITH cte_name AS (SELECT ...) SELECT * FROM cte_name;
B. DEFINE cte_name AS (SELECT ...) SELECT * FROM cte_name;
C. CREATE CTE cte_name AS SELECT ...;
D. SELECT * FROM WITH cte_name AS (SELECT ...)

Solution

  1. Step 1: Recall the standard CTE syntax

    The correct syntax starts with WITH cte_name AS (subquery), followed by the main query.
  2. Step 2: Check each option

    WITH cte_name AS (SELECT ...) SELECT * FROM cte_name; correctly shows the CTE definition and usage. Options A, B, and C use invalid keywords or order.
  3. Final Answer:

    WITH cte_name AS (SELECT ...) SELECT * FROM cte_name; -> Option A
  4. Quick Check:

    CTE syntax starts with WITH = D [OK]
Hint: CTE always starts with WITH keyword followed by AS [OK]
Common Mistakes:
  • Placing WITH after SELECT
  • Using CREATE or DEFINE keywords for CTE
  • Missing AS keyword after CTE name
3. Given the tables orders(order_id, customer_id, amount) and customers(customer_id, name), what will this query return?
WITH high_orders AS (
  SELECT customer_id, SUM(amount) AS total
  FROM orders
  GROUP BY customer_id
  HAVING SUM(amount) > 100
)
SELECT c.name, h.total
FROM high_orders h
JOIN customers c ON h.customer_id = c.customer_id;
medium
A. Names and total order amounts for customers with orders over 100 in total.
B. All customers with their total order amounts, regardless of amount.
C. Only customers with a single order over 100.
D. An error because CTEs cannot use GROUP BY.

Solution

  1. Step 1: Analyze the CTE definition

    The CTE high_orders groups orders by customer and filters those with total amount > 100.
  2. Step 2: Understand the main query

    The main query joins high_orders with customers to get customer names and their total order amounts.
  3. Final Answer:

    Names and total order amounts for customers with orders over 100 in total. -> Option A
  4. Quick Check:

    CTE filters totals > 100, join adds names = C [OK]
Hint: CTE filters first, main query joins for details [OK]
Common Mistakes:
  • Confusing HAVING with WHERE
  • Thinking it returns all customers
  • Believing CTEs cannot use GROUP BY
4. Identify the error in this SQL query using a CTE:
WITH recent_orders AS (
  SELECT order_id, order_date
  FROM orders
  WHERE order_date > '2023-01-01'
)
SELECT *
FROM recent_orders
WHERE order_date < '2023-01-01';
medium
A. CTEs cannot be used with WHERE clauses inside them.
B. The CTE name cannot be used in the main query.
C. The query is missing a semicolon after the CTE definition.
D. The CTE filters orders after 2023-01-01 but main query filters before, resulting in no rows.

Solution

  1. Step 1: Check the CTE filter condition

    The CTE selects orders with order_date > '2023-01-01'.
  2. Step 2: Check the main query filter

    The main query filters order_date < '2023-01-01', which contradicts the CTE filter, so no rows match.
  3. Final Answer:

    The CTE filters orders after 2023-01-01 but main query filters before, resulting in no rows. -> Option D
  4. Quick Check:

    Conflicting filters cause empty result = B [OK]
Hint: Check filter conditions inside and outside CTE for conflicts [OK]
Common Mistakes:
  • Thinking WHERE is not allowed in CTE
  • Expecting semicolon after WITH clause
  • Believing CTE names are invalid in main query
5. You want to find customers who placed orders totaling more than 500, but only include those customers who have placed at least 3 orders. Which CTE-based query correctly achieves this?
hard
A. WITH order_summary AS ( SELECT customer_id, COUNT(order_id) AS order_count FROM orders GROUP BY customer_id HAVING COUNT(order_id) >= 3 ) SELECT * FROM order_summary WHERE total_amount > 500;
B. WITH order_summary AS ( SELECT customer_id, SUM(amount) AS total_amount FROM orders GROUP BY customer_id HAVING SUM(amount) > 500 ) SELECT * FROM order_summary WHERE order_count >= 3;
C. WITH order_summary AS ( SELECT customer_id, COUNT(order_id) AS order_count, SUM(amount) AS total_amount FROM orders GROUP BY customer_id HAVING SUM(amount) > 500 AND COUNT(order_id) >= 3 ) SELECT * FROM order_summary;
D. WITH order_summary AS ( SELECT customer_id, SUM(amount) AS total_amount FROM orders GROUP BY customer_id ) SELECT * FROM order_summary WHERE total_amount > 500 AND order_count >= 3;

Solution

  1. Step 1: Understand the requirements

    We need customers with total order amount > 500 and at least 3 orders.
  2. Step 2: Check each option's logic

    WITH order_summary AS ( SELECT customer_id, COUNT(order_id) AS order_count, SUM(amount) AS total_amount FROM orders GROUP BY customer_id HAVING SUM(amount) > 500 AND COUNT(order_id) >= 3 ) SELECT * FROM order_summary; calculates both count and sum in the CTE and filters with HAVING both conditions, which is correct. Options B, C, and D try to filter outside the CTE on columns not selected or missing.
  3. Final Answer:

    WITH order_summary AS ( SELECT customer_id, COUNT(order_id) AS order_count, SUM(amount) AS total_amount FROM orders GROUP BY customer_id HAVING SUM(amount) > 500 AND COUNT(order_id) >= 3 ) SELECT * FROM order_summary; -> Option C
  4. Quick Check:

    Filter both conditions inside CTE HAVING = A [OK]
Hint: Use HAVING to filter grouped results inside CTE [OK]
Common Mistakes:
  • Filtering aggregated columns outside CTE
  • Missing COUNT or SUM in CTE select
  • Using WHERE instead of HAVING for aggregates
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard