📖 Scenario: You work for a small bookstore that keeps track of book sales and authors in a database. You want to find the total sales for each author in a clear and readable way.
🎯 Goal: Build a SQL query using a Common Table Expression (CTE) to calculate total sales per author, replacing a subquery for better readability.
📋 What You'll Learn
Create a CTE named AuthorSales that sums sales per author from the sales table.
Use the CTE to select each author's name and their total sales.
Order the results by total sales in descending order.
💡 Why This Matters
🌍 Real World
CTEs help make complex queries easier to read and maintain, especially when working with aggregated data like sales summaries.
💼 Career
Database developers and analysts often use CTEs to organize queries for reports and data analysis in business environments.
Progress0 / 4 steps
1
Create the authors and sales tables
Write SQL statements to create two tables: authors with columns author_id (integer, primary key) and author_name (text), and sales with columns sale_id (integer, primary key), author_id (integer), and amount (integer).
SQL
Hint
Use CREATE TABLE statements with the specified columns and data types.
2
Insert sample data into authors and sales
Insert these exact rows into authors: (1, 'Alice'), (2, 'Bob'), (3, 'Charlie'). Insert these exact rows into sales: (1, 1, 100), (2, 2, 150), (3, 1, 200), (4, 3, 50).
SQL
Hint
Use INSERT INTO with multiple rows for both tables.
3
Write a CTE named AuthorSales to sum sales per author
Write a SQL query that starts with WITH AuthorSales AS and defines a CTE that selects author_id and the sum of amount as total_sales from sales, grouped by author_id.
SQL
Hint
Use WITH AuthorSales AS (SELECT author_id, SUM(amount) AS total_sales FROM sales GROUP BY author_id).
4
Select author names and total sales using the CTE
Write a SQL query that selects author_name and total_sales by joining authors with the AuthorSales CTE on author_id. Order the results by total_sales in descending order.
SQL
Hint
Join authors with AuthorSales on author_id and order by total_sales descending.
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
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.
Step 2: Compare with nested subqueries
Nested subqueries can be hard to read because they are embedded inside other queries without a clear name.
Final Answer:
It makes the query easier to read and maintain by naming parts of the query. -> Option B
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
Step 1: Recall the standard CTE syntax
The correct syntax starts with WITH cte_name AS (subquery), followed by the main query.
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.
Final Answer:
WITH cte_name AS (SELECT ...) SELECT * FROM cte_name; -> Option A
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
Step 1: Analyze the CTE definition
The CTE high_orders groups orders by customer and filters those with total amount > 100.
Step 2: Understand the main query
The main query joins high_orders with customers to get customer names and their total order amounts.
Final Answer:
Names and total order amounts for customers with orders over 100 in total. -> Option A
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
Step 1: Check the CTE filter condition
The CTE selects orders with order_date > '2023-01-01'.
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.
Final Answer:
The CTE filters orders after 2023-01-01 but main query filters before, resulting in no rows. -> Option D
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
Step 1: Understand the requirements
We need customers with total order amount > 500 and at least 3 orders.
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.
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
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 unknownstrongwhile earning +1 Grip toward your certificate.