Primary key and foreign key
In short: A primary key is the column that uniquely identifies each row of a table, and a foreign key is a column that holds the primary key of a row in another table.
Problem
Whose order is it?
In the lesson “The shop” we searched by eye for who placed order 60 and what was in it. The answer was spread across four tables: orders, customers, order_items and products.
Why does the shop not keep everything in one big table? And how does a table “know” which row in another table is its own?
The idea
Primary key
Almost every table in the shop has an id column. The exception, order_items, is in the note at the end of the lesson. The number is different for every row, never repeats and is never empty. A row can be found by it without any doubt:
Such a column is called a primary key. Names will not do: two customers can have the same name, and a name can change. The number stays.
SQLite tells you which column is the primary key. The pk column is 1 for it:
The idea
Foreign key
An order does not store the customer name. It keeps only their id, in the customer_id column:
customers
- PK
idinteger nametext *emailtext *citytextjoined_attext *
orders
- PK
idinteger - FK
customer_idinteger *→ customers ordered_attext *statustext *
orders.customer_id points to customers.id. A column that keeps the primary key of a row in another table is called a foreign key.
A table's links are shown by pragma_foreign_key_list:
One row, one link: from the customer_id column (from) to the id column (to) of the customers table.
So Maria's details (name, email) are stored once. If she changes her email, it is fixed in one row of customers, and her 12 orders still point to the same id.
Try it
The order lines
Which tables does order_items point to? Show its links.
Solution
SELECT * FROM pragma_foreign_key_list('order_items');SELECT * FROM pragma_foreign_key_list('order_items'). Two links: product_id points to products.id, and order_id to orders.id. One row of order_items says “this order contains this product”.
See it
Looking up by number
With WHERE we no longer search by eye. Who placed order 60? First the order:
customer_id is 1. Then the customer with that id:
Maria Ivanova. It works, but it takes two queries, and you carry the number 1 over by hand. For one order that is bearable. For a report of 60 orders with their customers' names it is not. The next lesson puts the two steps into one query with JOIN.
Try it
Whose review is it?
Review 13 has a rating of 1. Who wrote it? Show only the customer name.
Solution
SELECT customer_id FROM reviews WHERE id = 13;
SELECT name FROM customers WHERE id = 12;Two steps: SELECT customer_id FROM reviews WHERE id = 13 gives 12, and SELECT name FROM customers WHERE id = 12 gives Boris Mitev. The check looks at the last table.
Exercise
Two tasks
1. A review points to two things. Show the links of the reviews table.
The links of reviews:
Solution
SELECT * FROM pragma_foreign_key_list('reviews');SELECT * FROM pragma_foreign_key_list('reviews'). customer_id points to customers, and product_id to products: who wrote it and about which product.
2. The categories form a tree: “Kitchen” is a subcategory of something. The foreign key parent_id points to a row in the same categories table. Find the name of the parent category of “Kitchen”.
The parent category of “Kitchen”:
Solution
SELECT parent_id FROM categories WHERE name = 'Kitchen';
SELECT name FROM categories WHERE id = 2;SELECT parent_id FROM categories WHERE name = 'Kitchen' gives 2, and SELECT name FROM categories WHERE id = 2 gives “Home”. A table can point to itself. In the lesson on many tables you will do this in one query.
More precisely, if you are curious
A primary key can be made of several columns. In order_items it is the pair (order_id, product_id): pk is 1 and 2 for its parts.
A foreign key is also a rule: the database refuses an order for a customer who does not exist. In SQLite this rule is off by default and is turned on with PRAGMA foreign_keys = ON. Here in the course it is on. In PostgreSQL foreign keys are always enforced. You will see them at work in the module on changing data.
Test
Check yourself
Related lessons
Section titled "Related lessons"- Builds on: Why a database · SELECT: choosing columns · WHERE: filtering rows
- Continues in: JOIN: two tables in one query · LEFT JOIN: rows without a match too · Many tables, and a table joined to itself · INSERT: new rows
- Tasks on this topic: Joining tables