Thuta Learning
ProjectsData & Databasesbeginner

Bookstore Project - Part 3: Reports & Cleanup

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Apply Bookstore Project - Part 3: Reports & Cleanup in a real project
  • Write the code yourself and run it
  • Build out a whole project step by step

Let's think this through for a moment

Parts 1 and 2 covered building the tables and writing search/join queries — this Part 3 is the final stage of the project, where we'll produce summary reports the way a business owner would want to see them. We'll use GROUP BY along with SUM() and COUNT() to calculate how many books each author has written and how much each customer has spent. We'll use HAVING to filter down to only the authors who've written more than 2 books. Finally, we'll handle data maintenance tasks like updating prices, fixing stock, and deleting old orders, then add an index on a frequently searched column to close out the project.

Let's build it for real

First, work out how many books each author has written with COUNT() + GROUP BY AuthorID, then filter with HAVING COUNT(*) >= 2. Next, find how much each customer has spent in total (SUM of Quantity * Price) with GROUP BY CustomerID. Then, fix the Stock of 'Fantastic Beasts' — currently 0 — to 15 using UPDATE. If there's order data older than 2025, clean it up with DELETE FROM Orders WHERE OrderDate < '2026-01-01' (this is for the mock data). Finally, add a CREATE INDEX on the Books.Title column to boost search speed.

Code example

sql
-- Authors who wrote 2 or more books
SELECT Authors.AuthorName, COUNT(Books.BookID) AS BookCount
FROM Authors
INNER JOIN Books ON Authors.AuthorID = Books.AuthorID
GROUP BY Authors.AuthorName
HAVING COUNT(Books.BookID) >= 2;

-- Total spending per customer
SELECT Customers.CustomerName, SUM(Orders.Quantity * Books.Price) AS TotalSpent
FROM Orders
INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
INNER JOIN Books ON Orders.BookID = Books.BookID
GROUP BY Customers.CustomerName
ORDER BY TotalSpent DESC;

-- Restock a book
UPDATE Books SET Stock = 15 WHERE Title = 'Fantastic Beasts';

-- Clean up old order data
DELETE FROM Orders WHERE OrderDate < '2026-01-01';

-- Speed up title search
CREATE INDEX idx_book_title ON Books(Title);
You should see
The author report will show Murakami as having written more than 2 books, the customer spending report will list how much each customer has spent in order, and the stock update plus index will apply without errors.

5-minute try-it

Try producing the average book price per author using AVG() + GROUP BY AuthorID — give yourself 5 minutes to try it.

A quick word of caution

Before running DELETE or UPDATE statements on production data, test the WHERE condition with SELECT first — get the condition wrong and you could wipe out all your data.

Easy traps

  • Wanting to filter GROUP BY results and mistakenly applying WHERE directly on an aggregate function instead of HAVING (writing WHERE COUNT(*) ... triggers an error)
  • Forgetting to add a WHERE condition on DELETE FROM Orders and accidentally deleting all the order data in the table

Now try it yourself

Try producing the average book price per author using AVG() + GROUP BY AuthorID — give yourself 5 minutes to try it.

You'll know it worked when: The author report will show Murakami as having written more than 2 books, the customer spending report will list how much each customer has spent in order, and the stock update plus index will apply without errors.

Bookstore Project - Part 3: Reports & Cleanup | Thuta Learning