Expert: design, speed and engines · Schema design and normalisation · topic 42 of 62 · 35 min
Modelling data: entities and relationships
Explanation
Why model before you build?
In module 1 you met keys and the three kinds of relationship. Now you use them to design a database from scratch. Changing a design on paper costs nothing. Changing it after a year, when the tables hold lakhs of rows and ten programs read them, takes migrations, testing and late nights. A few hours of modelling saves weeks later.
A data model is a description of the things your app must remember and how they connect. It has three parts:
- Entity: a kind of thing you store many of, such as Student, Course or Doctor. Each entity usually becomes a table.
- Attribute: one detail of an entity, such as a student's name or a course's fee. Attributes become columns.
- Relationship: how entities connect, such as "a student enrols in a course". Relationships become foreign keys or junction tables.
From requirements to a model
Start from plain sentences written with the people who will use the app. A simple trick is to underline the nouns and the verbs. Nouns that have their own details are entities; small nouns that only describe something are attributes; verbs are relationships.
| Requirement sentence | What it gives you |
|---|---|
| "A coaching institute has students. We record each student's name, phone and city." | Entity Student with attributes name, phone, city |
| "Each course has a code, a title and a fee." | Entity Course with code, title, fee |
| "A student can join many courses, and a course has many students." | A many-to-many relationship: enrols |
| "For each enrolment we keep the batch and the date of joining." | Attributes of the relationship itself, so they live in the junction table |
| "Each course has exactly one teacher; a teacher can teach several courses." | Entity Teacher, one-to-many to Course |
Cardinality and optionality
Cardinality is the "how many" of a relationship: one or many on each side. Optionality says whether a link must exist at all: a course may have zero students in its first week, but an enrolment must always point to one student. Ask two questions for each side: "at least how many?" (zero or one) and "at most how many?" (one or many).
Crow's foot notation, in words
The most common way to draw an ER (entity-relationship) diagram is crow's foot notation. Tables are boxes and relationships are lines. The end of each line shows cardinality: a three-pronged fork that looks like a crow's foot means "many", a short bar means "one", and a small circle means "zero", so the link is optional.
| Line end | Read it as |
|---|---|
| Bar and bar ( || ) | Exactly one |
| Circle and bar ( o| ) | Zero or one |
| Bar and crow's foot ( |< ) | One or many |
| Circle and crow's foot ( o< ) | Zero or many |
teachers ||------o< courses one teacher teaches zero or many courses
students ||------o< enrolments one student has zero or many enrolments
courses ||------o< enrolments one course has zero or many enrolments
enrolments: student_id FK, course_id FK, batch, joined_on; PK (student_id, course_id)Many-to-many becomes a junction table
A relational table cannot hold "many" on both sides, so every many-to-many relationship becomes a junction table with two foreign keys. Notice that the relationship often has its own attributes: the batch and the joining date belong to neither the student nor the course, but to the enrolment. When a relationship gathers many attributes, it is really an entity of its own, and that is fine.
SELECT c.code, c.title
FROM enrolments e
JOIN courses c ON c.id = e.course_id
WHERE e.student_id = 3;
-- CS102 | Databases
-- MA101 | StatisticsChoosing keys on purpose
A candidate key is any column, or set of columns, that could identify a row: for a course both id and code are unique. You pick one as the primary key and protect the others with UNIQUE. Most teams use a surrogate id as the primary key and keep natural values such as a course code, a PAN or an email under a UNIQUE rule.
- A junction table can use the pair as its primary key, PRIMARY KEY (student_id, course_id), which also blocks the same student joining the same course twice.
- If the same pair may appear more than once (a patient sees the same doctor many times), the pair is not unique. Give the table its own id, and add the date to make each row distinct.
- A one-to-one relationship is a foreign key with UNIQUE on it; an optional one-to-many relationship is a foreign key that allows NULL.
Common mistakes
- Jumping straight to CREATE TABLE. Fix: write the requirement sentences and a rough ER diagram first, and show them to a real user.
- Putting relationship details on the wrong table, such as a grade column in students. Fix: ask "whose detail is this?"; a grade belongs to one student in one course, so it goes in the junction table.
- Making a junction table's pair the primary key when repeats are real (repeat appointments). Fix: use an id plus the date.
- Modelling a list as columns: course1, course2, course3. Fix: one row per pair in a junction table. Topic 2 explains why.
- Forgetting optionality. Fix: decide NOT NULL or nullable for every foreign key, from the "at least how many?" question.
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
Modelling data: entities and relationships · 1/7
In this module we design databases ourselves. First step: turn plain requirements into a model before writing any SQL.
Prefer a video by a teacher? Find free videos on “er diagram crow's foot notation tutorial entity relationship modelling” on YouTube ↗
In real life: A clinic appointment system
A small clinic chain wants online booking. The requirements give entities Patient, Doctor, Clinic and Appointment. A doctor works at one clinic; a patient can book many appointments with many doctors over the years, and the same patient may see the same doctor again next month. So Appointment is its own table with an id, patient_id, doctor_id, a start time and a status, rather than a pair-keyed junction table. Hospital and clinic software across India is built on models like this.
CREATE TABLE appointments (
id INTEGER PRIMARY KEY,
patient_id INTEGER NOT NULL REFERENCES patients(id),
doctor_id INTEGER NOT NULL REFERENCES doctors(id),
starts_at TEXT NOT NULL, -- UTC, 'YYYY-MM-DD HH:MM:SS'
status TEXT NOT NULL DEFAULT 'Booked',
UNIQUE (doctor_id, starts_at) -- a doctor cannot be double-booked
);Practice (0/3 done)
The college database has students, courses and the junction table enrolments (student_id, course_id, semester). Return the name of every student enrolled in the course titled 'Databases', sorted by name (one column: name).
The tables students and courses exist, but there is no junction table yet. 1) Create enrolments with student_id (INTEGER NOT NULL, references students(id)), course_id (INTEGER NOT NULL, references courses(id)) and PRIMARY KEY (student_id, course_id). 2) Insert these pairs (student_id, course_id): (1, 2), (2, 2), (2, 3), (4, 1), (5, 2). 3) Return every course with how many students joined it, including courses with none: columns title and students, sorted by title.
Model a small public library (or, if you prefer, a clinic). Requirements: members borrow books; a book title can have several physical copies; a member can borrow many copies over time and the same copy many times; each loan has a borrow date, a due date and a return date (empty until returned); books have one or more authors. Write the entities, their attributes, the relationships with cardinality in crow's foot words, and the primary key of every table.
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
- Normalisation: 1NF, 2NF, 3NF and BCNFSchema design and normalisation · same module
- Denormalisation, OLTP and OLAPSchema design and normalisation · same module
- Data types, naming and good habitsSchema design and normalisation · same module
- Designing the data modelFull-Stack Development · Planning an app
- Normalisation and table designBackend Development · SQL in depth
- Entity Framework Core: databases with C#C# and .NET · Web APIs with ASP.NET Core and EF Core
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.
In "a patient books an appointment with a doctor", what is most likely an attribute rather than an entity?
Answer: The appointment start time
The start time only describes an appointment, so it is a column. Patient, Doctor and Appointment each have their own details.
In crow's foot notation, what does a line end drawn as a circle with a crow's foot (o<) mean?
Answer: Zero or many
The circle means zero is allowed, and the fork means many.
Students and courses are many-to-many, and each enrolment has a grade. Where does the grade column go?
Answer: In the enrolments junction table
A grade belongs to one student in one course, which is exactly one row of the junction table.
A patient may see the same doctor many times. Why is PRIMARY KEY (patient_id, doctor_id) a bad key for appointments?
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.
courses has both id and a unique code like CS101. What is the usual design?
Answer: Use id as the primary key and put a UNIQUE rule on code
Both are candidate keys. A surrogate id is the stable key; UNIQUE still protects the natural value.
In the Notes app, why is user_id stored in the notes table?Related
Answer: It is a foreign key that says which user owns the note
One user has many notes, so each note row records its owner with a foreign key pointing to users.id.
One student takes many courses, and one course has many students. How do you model this?Related
Answer: Add a junction table with student_id and course_id
Many-to-many needs a junction table with one row per pair.
When is a schema design really finished?Related
Answer: When the important business questions can be answered with clear queries on sample data
Testing with real reports finds missing columns and awkward relationships early.
Students take many courses and courses have many students. How do you model this?Related
Answer: Add a junction table enrollments(student_id, course_id)
Many-to-many needs a junction table with a foreign key to each side.
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
- 4 more topics in “Schema design and normalisation” before its exam: Normalisation: 1NF, 2NF, 3NF and BCNF, Denormalisation, OLTP and OLAP, Data types, naming and good habits, Design project: an online store.
- Module 9 exam: Schema design and normalisation · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Indexes, query plans and views. 62 topics left in the course before the final exam.