Beginner: asking questions · Databases and the relational model · topic 3 of 62 · 35 min
Keys and relationships
Explanation
Why keys?
Two customers can share a name. Two Ravi Kumars in Delhi is not unusual. To point at exactly one row you need a value that never repeats. That value is a key, and keys are what let tables link to each other. This linking is the "relational" in relational database, an idea introduced by E. F. Codd at IBM in 1970.
Primary key
A primary key is a column (or a group of columns) whose value is unique for every row and never empty. A table has at most one primary key. In SHOP, customers.id, products.id and orders.id are primary keys. Order 104 means one order and nothing else.
Natural and surrogate keys
A natural key is a value from the real world that is already unique: a vehicle registration number, a bank IFSC code, a train number. A surrogate key is a number the database makes up only to be the key, like id 1, 2, 3.
- Natural keys mean something, but they can change (people change email addresses and phone numbers), and some are private. An Aadhaar number should never be a key that is copied into many tables.
- Surrogate keys never change and are small and fast. Most apps use them, and keep natural values in normal columns with a UNIQUE rule.
Composite keys
Sometimes one column is not enough. In order_items, an order can have many products and a product can appear in many orders, but the pair (order_id, product_id) appears only once. So the primary key is both columns together. A key made of more than one column is a composite key.
SELECT order_id, product_id, qty, price FROM order_items WHERE order_id = 101;
-- 101 | 1 | 2 | 650
-- 101 | 2 | 3 | 160Foreign keys
A foreign key is a column whose values must match a primary key in another table. orders.customer_id is a foreign key that points to customers.id. Instead of copying Asha's name and city into every order, the order stores her id, 1. Her details live in one place, so changing her city is one update, not fifty.
SELECT id, order_date, status FROM orders WHERE customer_id = 1;
-- 101 | 2025-01-05 | Delivered
-- 103 | 2025-02-14 | Delivered
-- 108 | 2025-04-02 | PlacedThree kinds of relationship
| Kind | Meaning | Example | How it is built |
|---|---|---|---|
| One-to-one | Each row on one side matches at most one row on the other | A user and their profile settings | A foreign key that is also UNIQUE |
| One-to-many | One row on one side, many on the other | One customer has many orders | A foreign key on the "many" side (orders.customer_id) |
| Many-to-many | Many on both sides | Orders and products | A junction table (order_items) with two foreign keys |
A junction table (also called a link or bridge table) sits between two tables and holds one row per pairing. order_items says "order 101 contains product 1" and can also store details of that pairing, like qty and the price paid.
An ER diagram in words
An ER (entity-relationship) diagram is a drawing of tables as boxes and relationships as lines. You can also write it in words:
customers (id PK) 1 ──< many orders (id PK, customer_id FK)
orders (id PK) 1 ──< many order_items (order_id FK, product_id FK; PK = both)
products (id PK) 1 ──< many order_items
employees (id PK) 1 ──< many employees (manager_id FK) -- a table can point to itselfReferential integrity, and the SQLite switch
Referential integrity means every foreign key value points to a row that really exists. An order for customer 99, when there is no customer 99, is an orphan row. The database can block orphans for you, but SQLite does this only after you switch it on, once per connection.
PRAGMA foreign_keys = ON;
INSERT INTO orders VALUES (109, 99, '2025-04-10', 'Placed');
-- Error: FOREIGN KEY constraint failedCommon mistakes
- Forgetting PRAGMA foreign_keys = ON in SQLite, then finding orphan rows months later. Turn it on whenever your app opens a connection.
- Storing many ids in one column, like products = '1,5,7'. You cannot join or check such a list. Use a junction table with one row per pair.
- Using a name as the key. Names repeat and change. Use an id, and keep the name in its own column.
- Giving the foreign key a different type from the key it points to (TEXT vs INTEGER). Keep the types the same.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Keys and relationships · 1/7
Two customers can have the same name. To point at exactly one row, we need keys.
Prefer a video by a teacher? Find free videos on “primary key foreign key one to many many to many junction table explained” on YouTube ↗
In real life: Courses and students at a college
A college portal has students and courses. One student takes many courses, and one course has many students, so it is many-to-many. The portal adds an enrolments table with student_id and course_id (the pair is the primary key) plus the semester and grade. A query on enrolments can list every course of one student, or every student of one course.
CREATE TABLE enrolments (
student_id INTEGER REFERENCES students(id),
course_id INTEGER REFERENCES courses(id),
semester TEXT,
grade TEXT,
PRIMARY KEY (student_id, course_id)
);Practice (0/4 done)
customer_id in orders is a foreign key to customers.id. Show the orders of customer 2 (Ravi Kumar). Return the columns id, order_date and status. Use WHERE customer_id = 2.
order_items is a junction table between orders and products. Which orders contain product 2 (Toor Dal)? Return order_id and qty from order_items for product_id 2.
SQLite does not enforce foreign keys until you switch them on. Write two statements: first turn foreign key checks on, then ask SQLite whether they are on with PRAGMA foreign_keys; (it returns 1 for on, 0 for off).
Draw the SHOP database on paper (or in a notes app) as an ER diagram: one box per table (customers, products, orders, order_items) with its columns. Mark each primary key (PK) and foreign key (FK), draw the lines between tables, and label each line one-to-many or many-to-many.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- CREATE TABLE and constraintsDatabases and the relational model · same module
- Designing the data modelFull-Stack Development · Planning an app
- Modelling data: entities and relationshipsSchema design and normalisation
- Joins: combining tablesBackend Development · SQL in depth
- Indexes: making queries fastBackend Development · SQL in depth
- Why joins, and INNER JOINJOINs
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is a foreign key?
Answer: A column whose values must match a primary key in another (or the same) table
A foreign key links a row to a row in another table, like orders.customer_id to customers.id.
One student takes many courses, and one course has many students. How do you model this?
Answer: Add a junction table with student_id and course_id
Many-to-many needs a junction table with one row per pair.
In SHOP, why is the primary key of order_items (order_id, product_id)?
Answer: Because the pair is unique, while each column alone repeats
An order has many products and a product is in many orders, but each pair appears once.
In SQLite, foreign keys are declared but you can still insert an order for customer 99, who does not exist. Why?
Answer: Foreign key checks are off until PRAGMA foreign_keys = ON
SQLite enforces foreign keys only after the PRAGMA, once per connection.
Which is the best primary key for a customers table?
Answer: A surrogate id such as 1, 2, 3
Names repeat, cities repeat, and Aadhaar is private. A made-up id is safe and never changes.
What is a primary key?Related
Answer: A column whose value is unique for each row, used to identify it
A primary key (usually id) identifies exactly one row, so other tables can point to it.
A patient may see the same doctor many times. Why is PRIMARY KEY (patient_id, doctor_id) a bad key for appointments?Related
Answer: The pair repeats, so a second visit would be rejected
A pair key allows each pair only once. Use an id, and add the start time to tell visits apart.
In SQLite, what is the difference between INTEGER PRIMARY KEY and INTEGER PRIMARY KEY AUTOINCREMENT?Related
Answer: AUTOINCREMENT never reuses an id, even after deletes
Both fill in ids. Without AUTOINCREMENT, the id of a deleted last row can be used again.
Why is a customer's city stored in a customers table instead of on every order row?Related
Answer: So it is stored once and a change happens in one place
Storing a fact once avoids copies that can disagree. Orders refer to the customer by id.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Databases and the relational model” before its exam: CREATE TABLE and constraints, The SQL language and your tools.
- Module 1 exam: Databases and the relational model · 15 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, SELECT: filtering and sorting. 62 topics left in the course before the final exam.