01

About this project

Designing a relational schema for an invoicing system and then evolving it. The migrations add a product catalogue, customer addresses, deliveries and a premium-customer flag. Each section below follows a step from the original exercise.

MySQL Schema design ALTER TABLE migrations Triggers
02

The walkthrough

The exercise step by step. The SQL is hidden by default. Use the toggle on each step to view the statements.

Q6

Initial schema

Three tables to start. Customer holds an identifier and a name. Invoice records which customer placed it, where, and when. InvoiceLine adds one row per item on each invoice.

Q7

Seed data

Two customers, three invoices and six line items, enough to exercise the schema.

Q8

Design flaws to address

The schema has two weaknesses. First, there is no current customer address, since the city can only be inferred from a customer's last invoice and that may be stale for infrequent buyers. Second, there is no product catalogue, so item prices live on InvoiceLine and the current price has to be inferred from the last sale, which is expensive and wrong for rarely-sold items.

Q10

Add a Product table

Rename the loose Item column to a proper foreign key ProductId. A new Product table now holds the description, price and weight for each item.

Q12

Store the current city and add deliveries

Add a City column to Customer, backfill it from the most recent invoice and then make it NOT NULL. A new Delivery table tracks shipment status, and each Invoice now links to its delivery.

Q14

Premium customer flag with a trigger

Mark a customer as Premium once they have more than two invoices. An AFTER INSERT trigger on Invoice recounts and updates the flag on every new insert.

Q15

Trigger test

Insert a third invoice for customer 1, and the trigger promotes them to Premium.

03

Playground

The final schema is loaded with the seed data already inserted. Write your own query or pick one from the samples below, then use Cmd/Ctrl + Enter to run.

SQL Editor
Loading database…
Run a query to see results.
04

Sample queries

A few queries that exercise the final schema with joins across all five tables.

SELECT Name, City, Premium FROM Customer;
SELECT
    Invoice.Id,
    Customer.Name,
    Invoice.Date,
    Delivery.Status
FROM
    Invoice
    INNER JOIN Customer ON Invoice.CustomerId = Customer.Id
    INNER JOIN Delivery ON Invoice.DeliveryId = Delivery.Id
ORDER BY
    Invoice.Date;
SELECT
    Invoice.Id AS Invoice,
    Customer.Name,
    ROUND(SUM(InvoiceLine.Quantity * InvoiceLine.Price), 2) AS Total
FROM
    Invoice
    INNER JOIN Customer ON Invoice.CustomerId = Customer.Id
    INNER JOIN InvoiceLine ON InvoiceLine.InvoiceId = Invoice.Id
GROUP BY
    Invoice.Id
ORDER BY
    Total DESC;
SELECT
    Product.Description,
    SUM(InvoiceLine.Quantity) AS Sold,
    ROUND(SUM(InvoiceLine.Quantity * InvoiceLine.Price), 2) AS Revenue
FROM
    InvoiceLine
    INNER JOIN Product ON InvoiceLine.ProductId = Product.Id
GROUP BY
    Product.Id
ORDER BY
    Sold DESC;