parent
cc8879c675
commit
2794993ef3
11 changed files with 1376 additions and 0 deletions
@ -0,0 +1,122 @@ |
|||||||
|
--- |
||||||
|
title: Author Book Stats |
||||||
|
description: Practice basic aggregation with author and book data |
||||||
|
order: 93 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE author ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
name VARCHAR(255), |
||||||
|
country VARCHAR(100) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE book ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
author_id INT, |
||||||
|
price DECIMAL(10,2), |
||||||
|
pages INT |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO author (id, name, country) VALUES |
||||||
|
(1, 'Jane Smith', 'USA'), |
||||||
|
(2, 'John Brown', 'UK'), |
||||||
|
(3, 'Maria Garcia', 'Spain'), |
||||||
|
(4, 'David Wilson', 'USA'); |
||||||
|
|
||||||
|
INSERT INTO book (id, title, author_id, price, pages) VALUES |
||||||
|
(1, 'Database Design', 1, 29.99, 300), |
||||||
|
(2, 'SQL Basics', 1, 24.99, 250), |
||||||
|
(3, 'Python Programming', 2, 34.99, 400), |
||||||
|
(4, 'Web Development', 2, 39.99, 350), |
||||||
|
(5, 'Data Science', 2, 44.99, 450), |
||||||
|
(6, 'Machine Learning', 3, 49.99, 500), |
||||||
|
(7, 'AI Fundamentals', 3, 54.99, 550); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore wants to understand how many books each author has written and their average book price. They need a summary of author statistics to help with inventory planning. |
||||||
|
|
||||||
|
Given the following data in table `author`: |
||||||
|
|
||||||
|
| id | name | country | |
||||||
|
| --- | ------------ | ------- | |
||||||
|
| 1 | Jane Smith | USA | |
||||||
|
| 2 | John Brown | UK | |
||||||
|
| 3 | Maria Garcia | Spain | |
||||||
|
| 4 | David Wilson | USA | |
||||||
|
|
||||||
|
And the following data in table `book`: |
||||||
|
|
||||||
|
| id | title | author_id | price | pages | |
||||||
|
| --- | ----------------- | --------- | ----- | ----- | |
||||||
|
| 1 | Database Design | 1 | 29.99 | 300 | |
||||||
|
| 2 | SQL Basics | 1 | 24.99 | 250 | |
||||||
|
| 3 | Python Programming| 2 | 34.99 | 400 | |
||||||
|
| 4 | Web Development | 2 | 39.99 | 350 | |
||||||
|
| 5 | Data Science | 2 | 44.99 | 450 | |
||||||
|
| 6 | Machine Learning | 3 | 49.99 | 500 | |
||||||
|
| 7 | AI Fundamentals | 3 | 54.99 | 550 | |
||||||
|
|
||||||
|
Write a query that shows for each author: |
||||||
|
- Author name |
||||||
|
- Number of books written |
||||||
|
- Average book price |
||||||
|
- Total pages written |
||||||
|
|
||||||
|
Only include authors who have written books, and order the results by number of books in descending order. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| author_name | book_count | avg_price | total_pages | |
||||||
|
| ------------- | ---------- | --------- | ----------- | |
||||||
|
| John Brown | 3 | 39.99 | 1200 | |
||||||
|
| Maria Garcia | 2 | 52.49 | 1050 | |
||||||
|
| Jane Smith | 2 | 27.49 | 550 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
a.name as author_name, |
||||||
|
COUNT(*) as book_count, |
||||||
|
AVG(b.price) as avg_price, |
||||||
|
SUM(b.pages) as total_pages |
||||||
|
FROM author a |
||||||
|
INNER JOIN book b ON a.id = b.author_id |
||||||
|
GROUP BY a.name |
||||||
|
ORDER BY book_count DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
First, we join the author and book tables: |
||||||
|
```sql |
||||||
|
FROM author a |
||||||
|
INNER JOIN book b ON a.id = b.author_id |
||||||
|
``` |
||||||
|
|
||||||
|
We then calculate various aggregates for each author: |
||||||
|
```sql |
||||||
|
COUNT(*) -- Counts the number of books |
||||||
|
AVG(b.price) -- Calculates average book price |
||||||
|
SUM(b.pages) -- Sums up total pages |
||||||
|
``` |
||||||
|
|
||||||
|
We group the results by author name: |
||||||
|
```sql |
||||||
|
GROUP BY a.name |
||||||
|
``` |
||||||
|
|
||||||
|
Finally, we order by the book count: |
||||||
|
```sql |
||||||
|
ORDER BY book_count DESC |
||||||
|
``` |
||||||
|
|
||||||
|
This query helps the bookstore understand: |
||||||
|
- John Brown has written the most books (3) |
||||||
|
- Maria Garcia's books have the highest average price ($52.49) |
||||||
|
- John Brown has written the most pages (1,200) |
@ -0,0 +1,131 @@ |
|||||||
|
--- |
||||||
|
title: Author Tier Analysis |
||||||
|
description: Practice using CASE WHEN with aggregate functions |
||||||
|
order: 92 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE author ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
name VARCHAR(255) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE book ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
author_id INT, |
||||||
|
price DECIMAL(10,2) |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO author (id, name) VALUES |
||||||
|
(1, 'John Smith'), |
||||||
|
(2, 'Emma Wilson'), |
||||||
|
(3, 'Michael Brown'), |
||||||
|
(4, 'Sarah Davis'), |
||||||
|
(5, 'James Miller'); |
||||||
|
|
||||||
|
INSERT INTO book (id, title, author_id, price) VALUES |
||||||
|
(1, 'SQL Basics', 1, 29.99), |
||||||
|
(2, 'Advanced SQL', 1, 39.99), |
||||||
|
(3, 'Database Design', 1, 44.99), |
||||||
|
(4, 'Web Development', 2, 34.99), |
||||||
|
(5, 'JavaScript Guide', 2, 29.99), |
||||||
|
(6, 'Python Programming', 3, 24.99), |
||||||
|
(7, 'Data Analysis', 4, 49.99); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore wants to categorize their authors based on how many books they've published. They want to label authors as: |
||||||
|
- `Prolific Author` if they have written 3 or more books |
||||||
|
- `Established Author` if they have written 2 books |
||||||
|
- `New Author` if they have written 1 book |
||||||
|
|
||||||
|
Given the following data in table `author`: |
||||||
|
|
||||||
|
| id | name | |
||||||
|
| --- | ------------- | |
||||||
|
| 1 | John Smith | |
||||||
|
| 2 | Emma Wilson | |
||||||
|
| 3 | Michael Brown | |
||||||
|
| 4 | Sarah Davis | |
||||||
|
| 5 | James Miller | |
||||||
|
|
||||||
|
And the following data in table `book`: |
||||||
|
|
||||||
|
| id | title | author_id | price | |
||||||
|
| --- | ----------------- | --------- | ----- | |
||||||
|
| 1 | SQL Basics | 1 | 29.99 | |
||||||
|
| 2 | Advanced SQL | 1 | 39.99 | |
||||||
|
| 3 | Database Design | 1 | 44.99 | |
||||||
|
| 4 | Web Development | 2 | 34.99 | |
||||||
|
| 5 | JavaScript Guide | 2 | 29.99 | |
||||||
|
| 6 | Python Programming| 3 | 24.99 | |
||||||
|
| 7 | Data Analysis | 4 | 49.99 | |
||||||
|
|
||||||
|
Write a query that shows: |
||||||
|
- Author name |
||||||
|
- Number of books written |
||||||
|
- Author tier (based on the categories above) |
||||||
|
|
||||||
|
Only include authors who have published at least one book, and order the results by number of books in descending order. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| author_name | book_count | author_tier | |
||||||
|
| ------------- | ---------- | ---------------- | |
||||||
|
| John Smith | 3 | Prolific Author | |
||||||
|
| Emma Wilson | 2 | Established Author| |
||||||
|
| Michael Brown | 1 | New Author | |
||||||
|
| Sarah Davis | 1 | New Author | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
a.name as author_name, |
||||||
|
COUNT(*) as book_count, |
||||||
|
CASE |
||||||
|
WHEN COUNT(*) >= 3 THEN 'Prolific Author' |
||||||
|
WHEN COUNT(*) = 2 THEN 'Established Author' |
||||||
|
ELSE 'New Author' |
||||||
|
END as author_tier |
||||||
|
FROM author a |
||||||
|
INNER JOIN book b ON a.id = b.author_id |
||||||
|
GROUP BY a.name |
||||||
|
ORDER BY book_count DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
We join the author and book tables: |
||||||
|
```sql |
||||||
|
FROM author a |
||||||
|
INNER JOIN book b ON a.id = b.author_id |
||||||
|
``` |
||||||
|
|
||||||
|
We count books for each author: |
||||||
|
```sql |
||||||
|
COUNT(*) as book_count |
||||||
|
``` |
||||||
|
|
||||||
|
We use CASE WHEN to categorize authors: |
||||||
|
```sql |
||||||
|
CASE |
||||||
|
WHEN COUNT(*) >= 3 THEN 'Prolific Author' |
||||||
|
WHEN COUNT(*) = 2 THEN 'Established Author' |
||||||
|
ELSE 'New Author' |
||||||
|
END as author_tier |
||||||
|
``` |
||||||
|
|
||||||
|
We group by author name and order by book count: |
||||||
|
```sql |
||||||
|
GROUP BY a.name |
||||||
|
ORDER BY book_count DESC |
||||||
|
``` |
||||||
|
|
||||||
|
This query helps the bookstore: |
||||||
|
- Identify their most productive authors |
||||||
|
- Categorize authors based on their output |
||||||
|
- See the exact number of books by each author |
@ -0,0 +1,160 @@ |
|||||||
|
--- |
||||||
|
title: Book Performance |
||||||
|
description: Practice using aggregate functions with temporal data and joins |
||||||
|
order: 120 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE book ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
category VARCHAR(100), |
||||||
|
release_date DATE |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE sale ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
book_id INT, |
||||||
|
sale_timestamp TIMESTAMP, |
||||||
|
quantity INT, |
||||||
|
unit_price DECIMAL(10,2) |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO book (id, title, category, release_date) VALUES |
||||||
|
(1, 'The Great Gatsby', 'Fiction', '2024-01-01'), |
||||||
|
(2, 'SQL Mastery', 'Technical', '2024-01-15'), |
||||||
|
(3, 'Data Science 101', 'Technical', '2024-02-01'), |
||||||
|
(4, 'Pride and Prejudice', 'Fiction', '2024-02-15'); |
||||||
|
|
||||||
|
INSERT INTO sale (id, book_id, sale_timestamp, quantity, unit_price) VALUES |
||||||
|
(1, 1, '2024-02-01 10:30:00', 2, 19.99), |
||||||
|
(2, 1, '2024-02-15 14:20:00', 1, 19.99), |
||||||
|
(3, 2, '2024-02-01 11:15:00', 3, 29.99), |
||||||
|
(4, 2, '2024-02-20 16:45:00', 2, 29.99), |
||||||
|
(5, 3, '2024-02-05 09:30:00', 1, 24.99), |
||||||
|
(6, 3, '2024-02-25 13:20:00', 2, 24.99), |
||||||
|
(7, 4, '2024-02-15 15:45:00', 1, 14.99), |
||||||
|
(8, 4, '2024-02-28 10:10:00', 3, 14.99); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore manager wants to analyze book performance for February 2024. They need a report showing how each book performed during that month, including details about when the book was released. |
||||||
|
|
||||||
|
Given the following data in table `book`: |
||||||
|
|
||||||
|
| id | title | category | release_date | |
||||||
|
| --- | ------------------- | --------- | ------------ | |
||||||
|
| 1 | The Great Gatsby | Fiction | 2024-01-01 | |
||||||
|
| 2 | SQL Mastery | Technical | 2024-01-15 | |
||||||
|
| 3 | Data Science 101 | Technical | 2024-02-01 | |
||||||
|
| 4 | Pride and Prejudice | Fiction | 2024-02-15 | |
||||||
|
|
||||||
|
And the following data in table `sale`: |
||||||
|
|
||||||
|
| id | book_id | sale_timestamp | quantity | unit_price | |
||||||
|
| --- | ------- | ------------------- | -------- | ---------- | |
||||||
|
| 1 | 1 | 2024-02-01 10:30:00 | 2 | 19.99 | |
||||||
|
| 2 | 1 | 2024-02-15 14:20:00 | 1 | 19.99 | |
||||||
|
| 3 | 2 | 2024-02-01 11:15:00 | 3 | 29.99 | |
||||||
|
| 4 | 2 | 2024-02-20 16:45:00 | 2 | 29.99 | |
||||||
|
| 5 | 3 | 2024-02-05 09:30:00 | 1 | 24.99 | |
||||||
|
| 6 | 3 | 2024-02-25 13:20:00 | 2 | 24.99 | |
||||||
|
| 7 | 4 | 2024-02-15 15:45:00 | 1 | 14.99 | |
||||||
|
| 8 | 4 | 2024-02-28 10:10:00 | 3 | 14.99 | |
||||||
|
|
||||||
|
Write a query that shows: |
||||||
|
|
||||||
|
- Book title |
||||||
|
- Category |
||||||
|
- Whether the book was released in February (show as 'New Release' or 'Existing') |
||||||
|
- Total quantity sold |
||||||
|
- Total revenue |
||||||
|
- Number of sales transactions |
||||||
|
|
||||||
|
Only include books that had sales in February 2024, and order the results by total revenue in descending order. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| title | category | release_status | total_quantity | total_revenue | sale_count | |
||||||
|
| ------------------- | --------- | -------------- | -------------- | ------------- | ---------- | |
||||||
|
| SQL Mastery | Technical | Existing | 5 | 149.95 | 2 | |
||||||
|
| Data Science 101 | Technical | New Release | 3 | 74.97 | 2 | |
||||||
|
| The Great Gatsby | Fiction | Existing | 3 | 59.97 | 2 | |
||||||
|
| Pride and Prejudice | Fiction | New Release | 4 | 59.96 | 2 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
b.title, |
||||||
|
b.category, |
||||||
|
CASE |
||||||
|
WHEN EXTRACT(MONTH FROM b.release_date) = 2 THEN 'New Release' |
||||||
|
ELSE 'Existing' |
||||||
|
END as release_status, |
||||||
|
SUM(s.quantity) as total_quantity, |
||||||
|
SUM(s.quantity * s.unit_price) as total_revenue, |
||||||
|
COUNT(*) as sale_count |
||||||
|
FROM book b |
||||||
|
INNER JOIN sale s ON b.id = s.book_id |
||||||
|
WHERE |
||||||
|
EXTRACT(MONTH FROM s.sale_timestamp) = 2 |
||||||
|
AND EXTRACT(YEAR FROM s.sale_timestamp) = 2024 |
||||||
|
GROUP BY |
||||||
|
b.title, |
||||||
|
b.category, |
||||||
|
CASE |
||||||
|
WHEN EXTRACT(MONTH FROM b.release_date) = 2 THEN 'New Release' |
||||||
|
ELSE 'Existing' |
||||||
|
END |
||||||
|
ORDER BY total_revenue DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
First, we join the tables to get book information with sales: |
||||||
|
|
||||||
|
```sql |
||||||
|
FROM book b |
||||||
|
INNER JOIN sale s ON b.id = s.book_id |
||||||
|
``` |
||||||
|
|
||||||
|
We filter for February 2024 sales: |
||||||
|
|
||||||
|
```sql |
||||||
|
WHERE |
||||||
|
EXTRACT(MONTH FROM s.sale_timestamp) = 2 |
||||||
|
AND EXTRACT(YEAR FROM s.sale_timestamp) = 2024 |
||||||
|
``` |
||||||
|
|
||||||
|
We use a CASE statement to identify new releases: |
||||||
|
|
||||||
|
```sql |
||||||
|
CASE |
||||||
|
WHEN EXTRACT(MONTH FROM b.release_date) = 2 THEN 'New Release' |
||||||
|
ELSE 'Existing' |
||||||
|
END as release_status |
||||||
|
``` |
||||||
|
|
||||||
|
We calculate aggregates for each book: |
||||||
|
|
||||||
|
```sql |
||||||
|
SUM(s.quantity) as total_quantity, |
||||||
|
SUM(s.quantity * s.unit_price) as total_revenue, |
||||||
|
COUNT(*) as sale_count |
||||||
|
``` |
||||||
|
|
||||||
|
Finally, we group by the necessary columns and order by revenue: |
||||||
|
|
||||||
|
```sql |
||||||
|
GROUP BY |
||||||
|
b.title, |
||||||
|
b.category, |
||||||
|
CASE |
||||||
|
WHEN EXTRACT(MONTH FROM b.release_date) = 2 THEN 'New Release' |
||||||
|
ELSE 'Existing' |
||||||
|
END |
||||||
|
ORDER BY total_revenue DESC |
||||||
|
``` |
@ -0,0 +1,91 @@ |
|||||||
|
--- |
||||||
|
title: Book Sales Summary |
||||||
|
description: Practice using basic aggregate functions to analyze sales data |
||||||
|
order: 90 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE book_sale ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
quantity INT, |
||||||
|
price DECIMAL(10,2), |
||||||
|
sale_date DATE |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO book_sale (id, title, quantity, price, sale_date) |
||||||
|
VALUES |
||||||
|
(1, 'The Great Gatsby', 2, 19.99, '2024-01-15'), |
||||||
|
(2, 'Pride and Prejudice', 1, 14.99, '2024-01-15'), |
||||||
|
(3, '1984', 3, 12.99, '2024-01-16'), |
||||||
|
(4, 'The Hobbit', 2, 24.99, '2024-01-16'), |
||||||
|
(5, 'To Kill a Mockingbird', 1, 16.99, '2024-01-17'); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore owner wants a quick summary of their book sales. They need to know: |
||||||
|
- How many sales transactions they've had |
||||||
|
- The total number of books sold |
||||||
|
- The average price of books sold |
||||||
|
- The total revenue from all sales |
||||||
|
|
||||||
|
Given the following data in table `book_sale`: |
||||||
|
|
||||||
|
| id | title | quantity | price | sale_date | |
||||||
|
| --- | ---------------------- | -------- | ----- | ---------- | |
||||||
|
| 1 | The Great Gatsby | 2 | 19.99 | 2024-01-15 | |
||||||
|
| 2 | Pride and Prejudice | 1 | 14.99 | 2024-01-15 | |
||||||
|
| 3 | 1984 | 3 | 12.99 | 2024-01-16 | |
||||||
|
| 4 | The Hobbit | 2 | 24.99 | 2024-01-16 | |
||||||
|
| 5 | To Kill a Mockingbird | 1 | 16.99 | 2024-01-17 | |
||||||
|
|
||||||
|
Write a query that shows: |
||||||
|
- Total number of sales transactions |
||||||
|
- Total quantity of books sold |
||||||
|
- Average price per book |
||||||
|
- Total revenue (quantity * price) |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| total_transactions | total_books | avg_price | total_revenue | |
||||||
|
| ----------------- | ----------- | --------- | ------------- | |
||||||
|
| 5 | 9 | 17.99 | 161.91 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
COUNT(*) as total_transactions, |
||||||
|
SUM(quantity) as total_books, |
||||||
|
AVG(price) as avg_price, |
||||||
|
SUM(quantity * price) as total_revenue |
||||||
|
FROM book_sale; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
We use different aggregate functions to calculate each metric: |
||||||
|
|
||||||
|
```sql |
||||||
|
COUNT(*) -- Counts the total number of rows (sales transactions) |
||||||
|
``` |
||||||
|
|
||||||
|
```sql |
||||||
|
SUM(quantity) -- Adds up all quantities to get total books sold |
||||||
|
``` |
||||||
|
|
||||||
|
```sql |
||||||
|
AVG(price) -- Calculates the average price of books |
||||||
|
``` |
||||||
|
|
||||||
|
```sql |
||||||
|
SUM(quantity * price) -- Multiplies quantity by price for each sale and adds them up |
||||||
|
``` |
||||||
|
|
||||||
|
This simple query gives the bookstore owner a quick overview of their sales performance, showing: |
||||||
|
- They've had 5 sales transactions |
||||||
|
- Sold a total of 9 books |
||||||
|
- The average book price is $17.99 |
||||||
|
- Generated total revenue of $161.91 |
@ -0,0 +1,123 @@ |
|||||||
|
--- |
||||||
|
title: Category Insights |
||||||
|
description: Practice basic aggregation with book categories |
||||||
|
order: 91 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE category ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
name VARCHAR(100), |
||||||
|
display_section VARCHAR(50) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE book ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
category_id INT, |
||||||
|
price DECIMAL(10,2), |
||||||
|
in_stock INT |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO category (id, name, display_section) VALUES |
||||||
|
(1, 'Fiction', 'Main Floor'), |
||||||
|
(2, 'Science Fiction', 'Main Floor'), |
||||||
|
(3, 'Technical', 'Second Floor'), |
||||||
|
(4, 'History', 'Main Floor'); |
||||||
|
|
||||||
|
INSERT INTO book (id, title, category_id, price, in_stock) VALUES |
||||||
|
(1, 'The Last Hope', 1, 19.99, 5), |
||||||
|
(2, 'Stars Beyond', 2, 15.99, 3), |
||||||
|
(3, 'Python Basics', 3, 29.99, 10), |
||||||
|
(4, 'Ancient Rome', 4, 24.99, 4), |
||||||
|
(5, 'Summer Days', 1, 14.99, 2), |
||||||
|
(6, 'Space Wars', 2, 16.99, 3), |
||||||
|
(7, 'JavaScript 101', 3, 27.99, 8); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore manager wants a simple overview of their book categories to help with inventory management. |
||||||
|
|
||||||
|
Given the following data in table `category`: |
||||||
|
|
||||||
|
| id | name | display_section | |
||||||
|
| --- | --------------- | -------------- | |
||||||
|
| 1 | Fiction | Main Floor | |
||||||
|
| 2 | Science Fiction | Main Floor | |
||||||
|
| 3 | Technical | Second Floor | |
||||||
|
| 4 | History | Main Floor | |
||||||
|
|
||||||
|
And the following data in table `book`: |
||||||
|
|
||||||
|
| id | title | category_id | price | in_stock | |
||||||
|
| --- | -------------- | ----------- | ----- | -------- | |
||||||
|
| 1 | The Last Hope | 1 | 19.99 | 5 | |
||||||
|
| 2 | Stars Beyond | 2 | 15.99 | 3 | |
||||||
|
| 3 | Python Basics | 3 | 29.99 | 10 | |
||||||
|
| 4 | Ancient Rome | 4 | 24.99 | 4 | |
||||||
|
| 5 | Summer Days | 1 | 14.99 | 2 | |
||||||
|
| 6 | Space Wars | 2 | 16.99 | 3 | |
||||||
|
| 7 | JavaScript 101 | 3 | 27.99 | 8 | |
||||||
|
|
||||||
|
Write a query that shows for each category: |
||||||
|
- Category name |
||||||
|
- Number of books |
||||||
|
- Total books in stock |
||||||
|
- Average book price |
||||||
|
|
||||||
|
Order the results by the number of books in descending order. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| category_name | book_count | total_stock | avg_price | |
||||||
|
| -------------- | ---------- | ----------- | --------- | |
||||||
|
| Technical | 2 | 18 | 28.99 | |
||||||
|
| Science Fiction| 2 | 6 | 16.49 | |
||||||
|
| Fiction | 2 | 7 | 17.49 | |
||||||
|
| History | 1 | 4 | 24.99 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
c.name as category_name, |
||||||
|
COUNT(*) as book_count, |
||||||
|
SUM(b.in_stock) as total_stock, |
||||||
|
AVG(b.price) as avg_price |
||||||
|
FROM category c |
||||||
|
INNER JOIN book b ON c.id = b.category_id |
||||||
|
GROUP BY c.name |
||||||
|
ORDER BY book_count DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
We join the category and book tables: |
||||||
|
```sql |
||||||
|
FROM category c |
||||||
|
INNER JOIN book b ON c.id = b.category_id |
||||||
|
``` |
||||||
|
|
||||||
|
We calculate the aggregates for each category: |
||||||
|
```sql |
||||||
|
COUNT(*) -- Counts number of books |
||||||
|
SUM(b.in_stock) -- Adds up all books in stock |
||||||
|
AVG(b.price) -- Calculates average price |
||||||
|
``` |
||||||
|
|
||||||
|
We group by category name: |
||||||
|
```sql |
||||||
|
GROUP BY c.name |
||||||
|
``` |
||||||
|
|
||||||
|
Finally, we order by the book count: |
||||||
|
```sql |
||||||
|
ORDER BY book_count DESC |
||||||
|
``` |
||||||
|
|
||||||
|
This query helps the manager understand: |
||||||
|
- Which categories have the most titles |
||||||
|
- Total inventory by category |
||||||
|
- Average price point for each category |
@ -0,0 +1,96 @@ |
|||||||
|
--- |
||||||
|
title: Daily Sales Report |
||||||
|
description: Practice using GROUP BY with aggregate functions |
||||||
|
order: 95 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE daily_sale ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
sale_date DATE, |
||||||
|
book_title VARCHAR(255), |
||||||
|
quantity INT, |
||||||
|
price DECIMAL(10,2) |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO daily_sale (id, sale_date, book_title, quantity, price) |
||||||
|
VALUES |
||||||
|
(1, '2024-01-15', 'The Great Gatsby', 2, 19.99), |
||||||
|
(2, '2024-01-15', 'Pride and Prejudice', 1, 14.99), |
||||||
|
(3, '2024-01-15', '1984', 3, 12.99), |
||||||
|
(4, '2024-01-16', 'The Hobbit', 2, 24.99), |
||||||
|
(5, '2024-01-16', 'The Great Gatsby', 1, 19.99), |
||||||
|
(6, '2024-01-17', 'Pride and Prejudice', 2, 14.99), |
||||||
|
(7, '2024-01-17', '1984', 1, 12.99), |
||||||
|
(8, '2024-01-17', 'The Hobbit', 3, 24.99); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore manager wants to see how their sales are performing each day. They need a daily report showing: |
||||||
|
- The number of transactions per day |
||||||
|
- Total books sold per day |
||||||
|
- Total revenue per day |
||||||
|
|
||||||
|
Given the following data in table `daily_sale`: |
||||||
|
|
||||||
|
| id | sale_date | book_title | quantity | price | |
||||||
|
| --- | ---------- | ------------------ | -------- | ----- | |
||||||
|
| 1 | 2024-01-15 | The Great Gatsby | 2 | 19.99 | |
||||||
|
| 2 | 2024-01-15 | Pride and Prejudice| 1 | 14.99 | |
||||||
|
| 3 | 2024-01-15 | 1984 | 3 | 12.99 | |
||||||
|
| 4 | 2024-01-16 | The Hobbit | 2 | 24.99 | |
||||||
|
| 5 | 2024-01-16 | The Great Gatsby | 1 | 19.99 | |
||||||
|
| 6 | 2024-01-17 | Pride and Prejudice| 2 | 14.99 | |
||||||
|
| 7 | 2024-01-17 | 1984 | 1 | 12.99 | |
||||||
|
| 8 | 2024-01-17 | The Hobbit | 3 | 24.99 | |
||||||
|
|
||||||
|
Write a query that shows the daily sales metrics: |
||||||
|
- Date |
||||||
|
- Number of transactions that day |
||||||
|
- Total books sold that day |
||||||
|
- Total revenue for that day |
||||||
|
|
||||||
|
Order the results by date. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| sale_date | transactions | books_sold | daily_revenue | |
||||||
|
| ---------- | ------------ | ---------- | ------------- | |
||||||
|
| 2024-01-15 | 3 | 6 | 84.93 | |
||||||
|
| 2024-01-16 | 2 | 3 | 69.97 | |
||||||
|
| 2024-01-17 | 3 | 6 | 107.94 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
sale_date, |
||||||
|
COUNT(*) as transactions, |
||||||
|
SUM(quantity) as books_sold, |
||||||
|
SUM(quantity * price) as daily_revenue |
||||||
|
FROM daily_sale |
||||||
|
GROUP BY sale_date |
||||||
|
ORDER BY sale_date; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
First, we specify the columns we want to see: |
||||||
|
```sql |
||||||
|
sale_date, -- The date we're grouping by |
||||||
|
COUNT(*) as transactions, -- Count of sales for each date |
||||||
|
SUM(quantity) as books_sold, -- Total books sold each date |
||||||
|
SUM(quantity * price) as daily_revenue -- Total revenue each date |
||||||
|
``` |
||||||
|
|
||||||
|
We group the results by date to get daily totals: |
||||||
|
```sql |
||||||
|
GROUP BY sale_date |
||||||
|
``` |
||||||
|
|
||||||
|
Finally, we order the results by date: |
||||||
|
```sql |
||||||
|
ORDER BY sale_date |
||||||
|
``` |
@ -0,0 +1,125 @@ |
|||||||
|
--- |
||||||
|
title: Employee Performance |
||||||
|
description: Practice using self joins with aggregate functions |
||||||
|
order: 110 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE employee ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
name VARCHAR(255), |
||||||
|
manager_id INT, |
||||||
|
hire_date DATE |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE sale ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
employee_id INT, |
||||||
|
sale_date DATE, |
||||||
|
amount DECIMAL(10,2) |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO employee (id, name, manager_id, hire_date) VALUES |
||||||
|
(1, 'Sarah Johnson', NULL, '2023-01-15'), -- Store Manager |
||||||
|
(2, 'Mike Wilson', 1, '2023-02-01'), -- Reports to Sarah |
||||||
|
(3, 'Emily Brown', 1, '2023-02-15'), -- Reports to Sarah |
||||||
|
(4, 'Tom Davis', 2, '2023-03-01'), -- Reports to Mike |
||||||
|
(5, 'Lisa Miller', 2, '2023-03-15'), -- Reports to Mike |
||||||
|
(6, 'James Wilson', 3, '2023-04-01'); -- Reports to Emily |
||||||
|
|
||||||
|
INSERT INTO sale (id, employee_id, sale_date, amount) VALUES |
||||||
|
(1, 2, '2024-02-01', 150.00), |
||||||
|
(2, 2, '2024-02-02', 200.00), |
||||||
|
(3, 3, '2024-02-01', 300.00), |
||||||
|
(4, 4, '2024-02-02', 250.00), |
||||||
|
(5, 4, '2024-02-03', 175.00), |
||||||
|
(6, 5, '2024-02-01', 225.00), |
||||||
|
(7, 5, '2024-02-02', 125.00), |
||||||
|
(8, 6, '2024-02-03', 350.00); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore wants to analyze the sales performance of their employees and their teams. They need a report showing how each manager's team is performing. |
||||||
|
|
||||||
|
Given the following data in table `employee`: |
||||||
|
|
||||||
|
| id | name | manager_id | hire_date | |
||||||
|
| --- | -------------- | ---------- | ---------- | |
||||||
|
| 1 | Sarah Johnson | NULL | 2023-01-15 | |
||||||
|
| 2 | Mike Wilson | 1 | 2023-02-01 | |
||||||
|
| 3 | Emily Brown | 1 | 2023-02-15 | |
||||||
|
| 4 | Tom Davis | 2 | 2023-03-01 | |
||||||
|
| 5 | Lisa Miller | 2 | 2023-03-15 | |
||||||
|
| 6 | James Wilson | 3 | 2023-04-01 | |
||||||
|
|
||||||
|
And the following data in table `sale`: |
||||||
|
|
||||||
|
| id | employee_id | sale_date | amount | |
||||||
|
| --- | ----------- | ---------- | ------ | |
||||||
|
| 1 | 2 | 2024-02-01 | 150.00 | |
||||||
|
| 2 | 2 | 2024-02-02 | 200.00 | |
||||||
|
| 3 | 3 | 2024-02-01 | 300.00 | |
||||||
|
| 4 | 4 | 2024-02-02 | 250.00 | |
||||||
|
| 5 | 4 | 2024-02-03 | 175.00 | |
||||||
|
| 6 | 5 | 2024-02-01 | 225.00 | |
||||||
|
| 7 | 5 | 2024-02-02 | 125.00 | |
||||||
|
| 8 | 6 | 2024-02-03 | 350.00 | |
||||||
|
|
||||||
|
Write a query that shows for each manager: |
||||||
|
- Manager name |
||||||
|
- Number of employees they manage |
||||||
|
- Total sales by their team (including the manager's direct sales) |
||||||
|
- Average sale amount per team member |
||||||
|
|
||||||
|
Only include managers who have at least one employee reporting to them, and order the results by total team sales in descending order. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| manager_name | team_size | total_team_sales | avg_sale_per_member | |
||||||
|
| -------------- | --------- | ---------------- | ------------------ | |
||||||
|
| Sarah Johnson | 5 | 1775.00 | 355.00 | |
||||||
|
| Mike Wilson | 2 | 775.00 | 387.50 | |
||||||
|
| Emily Brown | 1 | 350.00 | 350.00 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
m.name as manager_name, |
||||||
|
COUNT(DISTINCT e.id) as team_size, |
||||||
|
SUM(s.amount) as total_team_sales, |
||||||
|
SUM(s.amount) / COUNT(DISTINCT e.id) as avg_sale_per_member |
||||||
|
FROM employee m |
||||||
|
INNER JOIN employee e ON e.manager_id = m.id |
||||||
|
INNER JOIN sale s ON s.employee_id = e.id |
||||||
|
GROUP BY m.id, m.name |
||||||
|
ORDER BY total_team_sales DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
First, we use a self-join to connect managers with their employees: |
||||||
|
```sql |
||||||
|
FROM employee m |
||||||
|
INNER JOIN employee e ON e.manager_id = m.id |
||||||
|
``` |
||||||
|
|
||||||
|
Then we join with the sales table to get sales data: |
||||||
|
```sql |
||||||
|
INNER JOIN sale s ON s.employee_id = e.id |
||||||
|
``` |
||||||
|
|
||||||
|
We calculate various metrics for each manager: |
||||||
|
```sql |
||||||
|
COUNT(DISTINCT e.id) -- Counts number of team members |
||||||
|
SUM(s.amount) -- Sums up all sales by the team |
||||||
|
SUM(s.amount) / COUNT(DISTINCT e.id) -- Calculates average sales per team member |
||||||
|
``` |
||||||
|
|
||||||
|
We group by manager and order by total sales: |
||||||
|
```sql |
||||||
|
GROUP BY m.id, m.name |
||||||
|
ORDER BY total_team_sales DESC |
||||||
|
``` |
@ -0,0 +1,132 @@ |
|||||||
|
--- |
||||||
|
title: High Value Publishers |
||||||
|
description: Practice using HAVING to filter aggregated data |
||||||
|
order: 98 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE publisher ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
name VARCHAR(255), |
||||||
|
country VARCHAR(100) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE book ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
publisher_id INT, |
||||||
|
price DECIMAL(10,2), |
||||||
|
stock_level INT |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO publisher (id, name, country) VALUES |
||||||
|
(1, 'Tech Books Inc', 'USA'), |
||||||
|
(2, 'Global Publishing', 'UK'), |
||||||
|
(3, 'Education Press', 'Canada'), |
||||||
|
(4, 'Digital Media Ltd', 'Australia'), |
||||||
|
(5, 'Research Books', 'Germany'); |
||||||
|
|
||||||
|
INSERT INTO book (id, title, publisher_id, price, stock_level) VALUES |
||||||
|
(1, 'Database Design', 1, 29.99, 25), |
||||||
|
(2, 'Advanced SQL', 1, 39.99, 15), |
||||||
|
(3, 'Web Development', 1, 34.99, 20), |
||||||
|
(4, 'Python Basics', 2, 24.99, 30), |
||||||
|
(5, 'Cloud Computing', 2, 49.99, 5), |
||||||
|
(6, 'Data Science', 3, 54.99, 20), |
||||||
|
(7, 'Machine Learning', 3, 59.99, 12), |
||||||
|
(8, 'Cybersecurity', 4, 45.99, 8), |
||||||
|
(9, 'Network Basics', 5, 19.99, 10); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore wants to identify their high-value publishers based on specific criteria. They want to find publishers who: |
||||||
|
- Have published more than 1 book |
||||||
|
- Have an average book price above $35 |
||||||
|
- Have more than 30 total books in stock |
||||||
|
|
||||||
|
Given the following data in table `publisher`: |
||||||
|
|
||||||
|
| id | name | country | |
||||||
|
| --- | ----------------- | --------- | |
||||||
|
| 1 | Tech Books Inc | USA | |
||||||
|
| 2 | Global Publishing | UK | |
||||||
|
| 3 | Education Press | Canada | |
||||||
|
| 4 | Digital Media Ltd | Australia | |
||||||
|
| 5 | Research Books | Germany | |
||||||
|
|
||||||
|
And the following data in table `book`: |
||||||
|
|
||||||
|
| id | title | publisher_id | price | stock_level | |
||||||
|
| --- | ---------------- | ------------ | ----- | ----------- | |
||||||
|
| 1 | Database Design | 1 | 29.99 | 25 | |
||||||
|
| 2 | Advanced SQL | 1 | 39.99 | 15 | |
||||||
|
| 3 | Web Development | 1 | 34.99 | 20 | |
||||||
|
| 4 | Python Basics | 2 | 24.99 | 30 | |
||||||
|
| 5 | Cloud Computing | 2 | 49.99 | 5 | |
||||||
|
| 6 | Data Science | 3 | 54.99 | 20 | |
||||||
|
| 7 | Machine Learning | 3 | 59.99 | 12 | |
||||||
|
| 8 | Cybersecurity | 4 | 45.99 | 8 | |
||||||
|
| 9 | Network Basics | 5 | 19.99 | 10 | |
||||||
|
|
||||||
|
Write a query that shows: |
||||||
|
- Publisher name |
||||||
|
- Number of books |
||||||
|
- Average book price |
||||||
|
- Total books in stock |
||||||
|
|
||||||
|
Only include publishers meeting ALL the criteria above, and order by average price descending. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| publisher_name | book_count | avg_price | total_stock | |
||||||
|
| --------------- | ---------- | --------- | ----------- | |
||||||
|
| Education Press | 2 | 57.49 | 32 | |
||||||
|
| Tech Books Inc | 3 | 34.99 | 60 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
p.name as publisher_name, |
||||||
|
COUNT(*) as book_count, |
||||||
|
AVG(b.price) as avg_price, |
||||||
|
SUM(b.stock_level) as total_stock |
||||||
|
FROM publisher p |
||||||
|
INNER JOIN book b ON p.id = b.publisher_id |
||||||
|
GROUP BY p.id, p.name |
||||||
|
HAVING |
||||||
|
COUNT(*) > 1 |
||||||
|
AND AVG(b.price) > 35 |
||||||
|
AND SUM(b.stock_level) > 30 |
||||||
|
ORDER BY avg_price DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
First, we join the tables: |
||||||
|
```sql |
||||||
|
FROM publisher p |
||||||
|
INNER JOIN book b ON p.id = b.publisher_id |
||||||
|
``` |
||||||
|
|
||||||
|
We calculate the required metrics: |
||||||
|
```sql |
||||||
|
COUNT(*) -- Number of books |
||||||
|
AVG(b.price) -- Average price |
||||||
|
SUM(b.stock_level) -- Total stock |
||||||
|
``` |
||||||
|
|
||||||
|
The key part is using HAVING to filter the groups: |
||||||
|
```sql |
||||||
|
HAVING |
||||||
|
COUNT(*) > 1 -- More than 1 book |
||||||
|
AND AVG(b.price) > 35 -- Average price above $35 |
||||||
|
AND SUM(b.stock_level) > 30 -- More than 30 total books in stock |
||||||
|
``` |
||||||
|
|
||||||
|
This query helps the bookstore identify: |
||||||
|
- Publishers with multiple books |
||||||
|
- Publishers with premium pricing |
||||||
|
- Publishers with significant inventory |
@ -0,0 +1,127 @@ |
|||||||
|
--- |
||||||
|
title: Premium Authors |
||||||
|
description: Practice using HAVING to find high-value authors |
||||||
|
order: 99 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE author ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
name VARCHAR(255), |
||||||
|
country VARCHAR(100) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE book ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
author_id INT, |
||||||
|
price DECIMAL(10,2), |
||||||
|
rating DECIMAL(2,1) |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO author (id, name, country) VALUES |
||||||
|
(1, 'John Smith', 'USA'), |
||||||
|
(2, 'Emma Wilson', 'UK'), |
||||||
|
(3, 'David Chen', 'China'), |
||||||
|
(4, 'Maria Garcia', 'Spain'), |
||||||
|
(5, 'James Brown', 'USA'); |
||||||
|
|
||||||
|
INSERT INTO book (id, title, author_id, price, rating) VALUES |
||||||
|
(1, 'SQL Mastery', 1, 45.99, 4.5), |
||||||
|
(2, 'Database Design', 1, 49.99, 4.8), |
||||||
|
(3, 'Python Basics', 2, 29.99, 4.2), |
||||||
|
(4, 'Web Development', 2, 34.99, 4.0), |
||||||
|
(5, 'Data Science', 2, 39.99, 4.6), |
||||||
|
(6, 'Machine Learning', 3, 54.99, 4.7), |
||||||
|
(7, 'AI Fundamentals', 3, 59.99, 4.9), |
||||||
|
(8, 'Cloud Computing', 4, 44.99, 4.3), |
||||||
|
(9, 'Basic Programming', 5, 24.99, 3.8); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore wants to identify their premium authors - those who consistently produce high-value, well-rated books. They want to find authors who: |
||||||
|
- Have written at least 2 books |
||||||
|
- Have an average book price above $40 |
||||||
|
- Have an average rating above 4.5 |
||||||
|
|
||||||
|
Given the following data in table `author`: |
||||||
|
|
||||||
|
| id | name | country | |
||||||
|
| --- | ------------ | ------- | |
||||||
|
| 1 | John Smith | USA | |
||||||
|
| 2 | Emma Wilson | UK | |
||||||
|
| 3 | David Chen | China | |
||||||
|
| 4 | Maria Garcia | Spain | |
||||||
|
| 5 | James Brown | USA | |
||||||
|
|
||||||
|
And the following data in table `book`: |
||||||
|
|
||||||
|
| id | title | author_id | price | rating | |
||||||
|
| --- | ----------------- | --------- | ----- | ------ | |
||||||
|
| 1 | SQL Mastery | 1 | 45.99 | 4.5 | |
||||||
|
| 2 | Database Design | 1 | 49.99 | 4.8 | |
||||||
|
| 3 | Python Basics | 2 | 29.99 | 4.2 | |
||||||
|
| 4 | Web Development | 2 | 34.99 | 4.0 | |
||||||
|
| 5 | Data Science | 2 | 39.99 | 4.6 | |
||||||
|
| 6 | Machine Learning | 3 | 54.99 | 4.7 | |
||||||
|
| 7 | AI Fundamentals | 3 | 59.99 | 4.9 | |
||||||
|
| 8 | Cloud Computing | 4 | 44.99 | 4.3 | |
||||||
|
| 9 | Basic Programming | 5 | 24.99 | 3.8 | |
||||||
|
|
||||||
|
Write a query that shows: |
||||||
|
- Author name |
||||||
|
- Number of books written |
||||||
|
- Average book price |
||||||
|
- Average book rating |
||||||
|
|
||||||
|
Only include authors meeting ALL the criteria above, and order by average rating descending. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| author_name | book_count | avg_price | avg_rating | |
||||||
|
| ----------- | ---------- | --------- | ---------- | |
||||||
|
| David Chen | 2 | 57.49 | 4.80 | |
||||||
|
| John Smith | 2 | 47.99 | 4.65 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
a.name as author_name, |
||||||
|
COUNT(*) as book_count, |
||||||
|
AVG(b.price) as avg_price, |
||||||
|
AVG(b.rating) as avg_rating |
||||||
|
FROM author a |
||||||
|
INNER JOIN book b ON a.id = b.author_id |
||||||
|
GROUP BY a.id, a.name |
||||||
|
HAVING |
||||||
|
COUNT(*) >= 2 |
||||||
|
AND AVG(b.price) > 40 |
||||||
|
AND AVG(b.rating) > 4.5 |
||||||
|
ORDER BY avg_rating DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
We join the author and book tables: |
||||||
|
```sql |
||||||
|
FROM author a |
||||||
|
INNER JOIN book b ON a.id = b.author_id |
||||||
|
``` |
||||||
|
|
||||||
|
We calculate the metrics for each author: |
||||||
|
```sql |
||||||
|
COUNT(*) -- Number of books written |
||||||
|
AVG(b.price) -- Average book price |
||||||
|
AVG(b.rating) -- Average book rating |
||||||
|
``` |
||||||
|
|
||||||
|
The key part is using HAVING to filter for premium authors: |
||||||
|
```sql |
||||||
|
HAVING |
||||||
|
COUNT(*) >= 2 -- At least 2 books |
||||||
|
AND AVG(b.price) > 40 -- Average price above $40 |
||||||
|
AND AVG(b.rating) > 4.5 -- Average rating above 4.5 |
||||||
|
``` |
@ -0,0 +1,124 @@ |
|||||||
|
--- |
||||||
|
title: Publisher Stats |
||||||
|
description: Practice basic aggregation with publisher data |
||||||
|
order: 96 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE publisher ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
name VARCHAR(255), |
||||||
|
country VARCHAR(100) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE book ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
publisher_id INT, |
||||||
|
pages INT, |
||||||
|
stock_level INT, |
||||||
|
price DECIMAL(10,2) |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO publisher (id, name, country) VALUES |
||||||
|
(1, 'Tech Books Inc', 'USA'), |
||||||
|
(2, 'Global Publishing', 'UK'), |
||||||
|
(3, 'Education Press', 'Canada'), |
||||||
|
(4, 'Digital Media Ltd', 'Australia'); |
||||||
|
|
||||||
|
INSERT INTO book (id, title, publisher_id, pages, stock_level, price) VALUES |
||||||
|
(1, 'Database Fundamentals', 1, 300, 25, 29.99), |
||||||
|
(2, 'Advanced SQL', 1, 400, 15, 39.99), |
||||||
|
(3, 'Web Development', 1, 350, 0, 34.99), |
||||||
|
(4, 'Python Mastery', 2, 450, 30, 44.99), |
||||||
|
(5, 'Cloud Computing', 2, 375, 5, 49.99), |
||||||
|
(6, 'Data Science', 3, 425, 20, 54.99), |
||||||
|
(7, 'Machine Learning', 3, 500, 12, 59.99), |
||||||
|
(8, 'Cybersecurity', 4, 350, 8, 45.99); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore wants to analyze their publishers' performance in terms of book variety, pricing, and stock levels. |
||||||
|
|
||||||
|
Given the following data in table `publisher`: |
||||||
|
|
||||||
|
| id | name | country | |
||||||
|
| --- | ----------------- | --------- | |
||||||
|
| 1 | Tech Books Inc | USA | |
||||||
|
| 2 | Global Publishing | UK | |
||||||
|
| 3 | Education Press | Canada | |
||||||
|
| 4 | Digital Media Ltd | Australia | |
||||||
|
|
||||||
|
And the following data in table `book`: |
||||||
|
|
||||||
|
| id | title | publisher_id | pages | stock_level | price | |
||||||
|
| --- | -------------------- | ------------ | ----- | ----------- | ----- | |
||||||
|
| 1 | Database Fundamentals| 1 | 300 | 25 | 29.99 | |
||||||
|
| 2 | Advanced SQL | 1 | 400 | 15 | 39.99 | |
||||||
|
| 3 | Web Development | 1 | 350 | 0 | 34.99 | |
||||||
|
| 4 | Python Mastery | 2 | 450 | 30 | 44.99 | |
||||||
|
| 5 | Cloud Computing | 2 | 375 | 5 | 49.99 | |
||||||
|
| 6 | Data Science | 3 | 425 | 20 | 54.99 | |
||||||
|
| 7 | Machine Learning | 3 | 500 | 12 | 59.99 | |
||||||
|
| 8 | Cybersecurity | 4 | 350 | 8 | 45.99 | |
||||||
|
|
||||||
|
Write a query that shows for each publisher: |
||||||
|
- Publisher name |
||||||
|
- Number of books published |
||||||
|
- Total books in stock |
||||||
|
- Average book price |
||||||
|
- Number of out-of-stock books (`stock_level = 0`) |
||||||
|
|
||||||
|
Only include publishers who have published at least one book, and order the results by number of books in descending order. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| publisher_name | book_count | total_stock | avg_price | out_of_stock | |
||||||
|
| ---------------- | ---------- | ----------- | --------- | ------------ | |
||||||
|
| Tech Books Inc | 3 | 40 | 34.99 | 1 | |
||||||
|
| Global Publishing| 2 | 35 | 47.49 | 0 | |
||||||
|
| Education Press | 2 | 32 | 57.49 | 0 | |
||||||
|
| Digital Media Ltd| 1 | 8 | 45.99 | 0 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
p.name as publisher_name, |
||||||
|
COUNT(*) as book_count, |
||||||
|
SUM(b.stock_level) as total_stock, |
||||||
|
AVG(b.price) as avg_price, |
||||||
|
COUNT(CASE WHEN b.stock_level = 0 THEN 1 END) as out_of_stock |
||||||
|
FROM publisher p |
||||||
|
INNER JOIN book b ON p.id = b.publisher_id |
||||||
|
GROUP BY p.id, p.name |
||||||
|
ORDER BY book_count DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
We join the publisher and book tables: |
||||||
|
```sql |
||||||
|
FROM publisher p |
||||||
|
INNER JOIN book b ON p.id = b.publisher_id |
||||||
|
``` |
||||||
|
|
||||||
|
We calculate various metrics for each publisher: |
||||||
|
```sql |
||||||
|
COUNT(*) -- Counts number of books |
||||||
|
SUM(b.stock_level) -- Adds up all books in stock |
||||||
|
AVG(b.price) -- Calculates average price |
||||||
|
COUNT(CASE WHEN b.stock_level = 0 THEN 1 END) -- Counts out-of-stock books |
||||||
|
``` |
||||||
|
|
||||||
|
We group by publisher: |
||||||
|
```sql |
||||||
|
GROUP BY p.id, p.name |
||||||
|
``` |
||||||
|
|
||||||
|
Finally, we order by the number of books: |
||||||
|
```sql |
||||||
|
ORDER BY book_count DESC |
||||||
|
``` |
@ -0,0 +1,145 @@ |
|||||||
|
--- |
||||||
|
title: Sales Analysis |
||||||
|
description: Practice using aggregate functions to analyze sales data |
||||||
|
order: 100 |
||||||
|
type: challenge |
||||||
|
setup: | |
||||||
|
```sql |
||||||
|
CREATE TABLE sale ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
sale_date DATE, |
||||||
|
customer_id INT, |
||||||
|
book_id INT, |
||||||
|
quantity INT, |
||||||
|
unit_price DECIMAL(10,2) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE book ( |
||||||
|
id INT PRIMARY KEY, |
||||||
|
title VARCHAR(255), |
||||||
|
category VARCHAR(100) |
||||||
|
); |
||||||
|
|
||||||
|
INSERT INTO book (id, title, category) |
||||||
|
VALUES |
||||||
|
(1, 'The Great Gatsby', 'Fiction'), |
||||||
|
(2, 'Data Science Basics', 'Technical'), |
||||||
|
(3, 'History of Time', 'Non-Fiction'), |
||||||
|
(4, 'Programming 101', 'Technical'), |
||||||
|
(5, 'Pride and Prejudice', 'Fiction'); |
||||||
|
|
||||||
|
INSERT INTO sale (id, sale_date, customer_id, book_id, quantity, unit_price) |
||||||
|
VALUES |
||||||
|
(1, '2024-01-15', 1, 1, 2, 15.99), |
||||||
|
(2, '2024-01-15', 2, 2, 1, 29.99), |
||||||
|
(3, '2024-01-15', 3, 3, 3, 19.99), |
||||||
|
(4, '2024-01-16', 4, 4, 1, 24.99), |
||||||
|
(5, '2024-01-16', 5, 5, 2, 12.99), |
||||||
|
(6, '2024-01-16', 1, 2, 1, 29.99), |
||||||
|
(7, '2024-01-17', 2, 3, 2, 19.99), |
||||||
|
(8, '2024-01-17', 3, 4, 1, 24.99), |
||||||
|
(9, '2024-01-17', 4, 5, 3, 12.99), |
||||||
|
(10, '2024-01-18', 5, 1, 1, 15.99); |
||||||
|
``` |
||||||
|
--- |
||||||
|
|
||||||
|
The bookstore manager wants to analyze their sales data to understand sales patterns and make inventory decisions. They need a comprehensive report that shows sales metrics by book category. |
||||||
|
|
||||||
|
Given the following data in table `book`: |
||||||
|
|
||||||
|
| id | title | category | |
||||||
|
| --- | ------------------- | ----------- | |
||||||
|
| 1 | The Great Gatsby | Fiction | |
||||||
|
| 2 | Data Science Basics | Technical | |
||||||
|
| 3 | History of Time | Non-Fiction | |
||||||
|
| 4 | Programming 101 | Technical | |
||||||
|
| 5 | Pride and Prejudice | Fiction | |
||||||
|
|
||||||
|
And the following data in table `sale`: |
||||||
|
|
||||||
|
| id | sale_date | customer_id | book_id | quantity | unit_price | |
||||||
|
| --- | ---------- | ----------- | ------- | -------- | ---------- | |
||||||
|
| 1 | 2024-01-15 | 1 | 1 | 2 | 15.99 | |
||||||
|
| 2 | 2024-01-15 | 2 | 2 | 1 | 29.99 | |
||||||
|
| 3 | 2024-01-15 | 3 | 3 | 3 | 19.99 | |
||||||
|
| 4 | 2024-01-16 | 4 | 4 | 1 | 24.99 | |
||||||
|
| 5 | 2024-01-16 | 5 | 5 | 2 | 12.99 | |
||||||
|
| 6 | 2024-01-16 | 1 | 2 | 1 | 29.99 | |
||||||
|
| 7 | 2024-01-17 | 2 | 3 | 2 | 19.99 | |
||||||
|
| 8 | 2024-01-17 | 3 | 4 | 1 | 24.99 | |
||||||
|
| 9 | 2024-01-17 | 4 | 5 | 3 | 12.99 | |
||||||
|
| 10 | 2024-01-18 | 5 | 1 | 1 | 15.99 | |
||||||
|
|
||||||
|
Write a query to generate a sales report showing the following metrics for each book category: |
||||||
|
|
||||||
|
- Total number of sales (count of transactions) |
||||||
|
- Total quantity of books sold |
||||||
|
- Total revenue (quantity * unit_price) |
||||||
|
- Average price per book |
||||||
|
- Maximum quantity in a single transaction |
||||||
|
|
||||||
|
Only include categories that have generated more than $50 in total revenue, and order the results by total revenue in descending order. |
||||||
|
|
||||||
|
## Expected Output |
||||||
|
|
||||||
|
| category | total_sales | total_quantity | total_revenue | avg_price | max_quantity | |
||||||
|
| ----------- | ----------- | -------------- | ------------- | --------- | ------------ | |
||||||
|
| Technical | 3 | 3 | 109.96 | 27.49 | 1 | |
||||||
|
| Fiction | 4 | 8 | 90.93 | 14.49 | 3 | |
||||||
|
| Non-Fiction | 2 | 5 | 99.95 | 19.99 | 3 | |
||||||
|
|
||||||
|
## Solution |
||||||
|
|
||||||
|
```sql |
||||||
|
SELECT |
||||||
|
b.category, |
||||||
|
COUNT(*) as total_sales, |
||||||
|
SUM(s.quantity) as total_quantity, |
||||||
|
SUM(s.quantity * s.unit_price) as total_revenue, |
||||||
|
AVG(s.unit_price) as avg_price, |
||||||
|
MAX(s.quantity) as max_quantity |
||||||
|
FROM sale s |
||||||
|
INNER JOIN book b ON s.book_id = b.id |
||||||
|
GROUP BY b.category |
||||||
|
HAVING SUM(s.quantity * s.unit_price) > 50 |
||||||
|
ORDER BY total_revenue DESC; |
||||||
|
``` |
||||||
|
|
||||||
|
### Explanation |
||||||
|
|
||||||
|
Let's break down how this query works: |
||||||
|
|
||||||
|
First, we join the `sale` and `book` tables to get category information for each sale: |
||||||
|
|
||||||
|
```sql |
||||||
|
FROM sale s |
||||||
|
INNER JOIN book b ON s.book_id = b.id |
||||||
|
``` |
||||||
|
|
||||||
|
We then group the results by category to calculate aggregates for each category: |
||||||
|
|
||||||
|
```sql |
||||||
|
GROUP BY b.category |
||||||
|
``` |
||||||
|
|
||||||
|
We use multiple aggregate functions to calculate different metrics: |
||||||
|
|
||||||
|
```sql |
||||||
|
COUNT(*) -- Counts number of sales transactions |
||||||
|
SUM(s.quantity) -- Sums up total books sold |
||||||
|
SUM(s.quantity * s.unit_price) -- Calculates total revenue |
||||||
|
AVG(s.unit_price) -- Calculates average price |
||||||
|
MAX(s.quantity) -- Finds maximum quantity in a single sale |
||||||
|
``` |
||||||
|
|
||||||
|
We filter out categories with low revenue using HAVING: |
||||||
|
|
||||||
|
```sql |
||||||
|
HAVING SUM(s.quantity * s.unit_price) > 50 |
||||||
|
``` |
||||||
|
|
||||||
|
Finally, we order the results by total revenue in descending order: |
||||||
|
|
||||||
|
```sql |
||||||
|
ORDER BY total_revenue DESC |
||||||
|
``` |
Loading…
Reference in new issue