Foreign Keys
In lesson 1, you followed foreign keys by hand: the customer_id of an order is the id of a customer. A foreign key is a column whose values are the primary keys of another table. When you create a table, you mark it with REFERENCES, followed by the table and the column it points at. Notes of the shop's support about its customers, for example:
CREATE TABLE customer_notes (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers (id),
note TEXT NOT NULL
) STRICT;From now on, the database makes sure that every customer_id in the table is the id of a customer who exists. A note about customer 3 is fine; a note about customer 99, who doesn't exist, is refused:
INSERT INTO customer_notes (customer_id, note)
VALUES (3, 'Prefers puzzle games.');
INSERT INTO customer_notes (customer_id, note)
VALUES (99, 'Asked about a refund.');Error on line 4: FOREIGN KEY constraint failedUnlike the other messages, this one doesn't say which column is wrong, so you have to find the value that points nowhere yourself. NULL is allowed in a foreign key, unless the column has NOT NULL: it points at nothing at all, like the referred_by of a customer nobody recommended the shop to.
The check works the other way too. In the last lesson, you saw that a game with orders can't be deleted: the rows of order_items point at it. Thanks to that, no row ever points at something that isn't there. If you'd rather have the rows that point at a deleted row deleted with it, write ON DELETE CASCADE after REFERENCES customers (id). Use it carefully, only for rows that make no sense on their own.
A foreign key has the type of the column it points at, here INTEGER, and its name usually says where it points: the table in the singular and _id, as in customer_id or game_id. You may also meet a foreign key written after the last column, as FOREIGN KEY (customer_id) REFERENCES customers (id); it means the same.
SQLite checks foreign keys only when it's told to, with PRAGMA foreign_keys = ON. This course does that for you before every run; other databases check them always. And the new table won't appear in the Tables tab, which shows only the tables the shop starts with.
Typical mistake: a typo in the table after REFERENCES. CREATE TABLE doesn't check it, so the mistake shows only at the first INSERT:
CREATE TABLE customer_notes (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customer (id),
note TEXT NOT NULL
) STRICT;
INSERT INTO customer_notes (customer_id, note)
VALUES (3, 'Prefers puzzle games.');Error on line 7: no such table: main.customerInstructions
The shop starts selling add-ons (DLCs) for its games. Create a STRICT table dlcs with these columns, in this order:
id– an integer primary key,game_id– the game the add-on is for: a whole number, always filled in, and a foreign key to the tablegames,title– text, always filled in,price– a whole number, always filled in.
Insert three add-ons: Ice Caves for Dragon Forge for $10, Dragon Riders for Dragon Forge for $15, and Night Tracks for Turbo Karts for $5. Look up the IDs of the games in the Tables tab. Then show the whole table dlcs, sorted by id:
| id | game_id | title | price |
|---|---|---|---|
| 1 | 1 | Ice Caves | 10 |
| 2 | 1 | Dragon Riders | 15 |
| 3 | 14 | Night Tracks | 5 |
Add a query that shows each add-on with the title of its game, in the columns game (the title of the game), dlc (the title of the add-on) and price, sorted by price:
| game | dlc | price |
|---|---|---|
| Turbo Karts | Night Tracks | 5 |
| Dragon Forge | Ice Caves | 10 |
| Dragon Forge | Dragon Riders | 15 |
Start programming for free
6/10