From picture to tables
An ER (entity–relationship) diagram is how designers sketch a database: entities (rectangles), the relationships between them (diamonds, with cardinalities such as 1:N), and attributes (ovals, with keys underlined). A relational database stores only tables. A short list of rules turns one into the other, and it is a favourite exam question.
The mapping rules
| Rule | ER element | Becomes |
|---|---|---|
| 1 | Strong entity | A table with its simple attributes. The key becomes the primary key. A composite attribute is replaced by its parts. |
| 2 | Weak entity | A table with its attributes plus the owner’s key as a foreign key. Primary key = owner’s key + partial key. |
| 3 | 1:1 relationship | A foreign key in one of the two tables, preferably on the side with total participation. |
| 4 | 1:N relationship | A foreign key on the N side. |
| 5 | M:N relationship | A new table holding both keys (together the primary key) and the relationship’s attributes. |
| 6 | Multivalued attribute | A new table (owner’s key, value), with both columns in the primary key. |
A relationship’s own attributes travel with it: they go wherever its foreign key goes (rules 3 and 4) or into its table (rule 5).
Example 1: University
Diagram: Department (did, dname), Student (sid, name, address(street, city), {phone}), Course (cid, title, credits). Major links Department 1:N Student. Enrolls links Student M:N Course and has the attribute grade.
| Step | Result |
|---|---|
| Rule 1: Department, Student, Course | Department(did, dname), Student(sid, name, street, city), Course(cid, title, credits) |
| Rule 4: Major (1:N) | Student gets did → Department |
| Rule 5: Enrolls (M:N) | Enrolls(sid, cid, grade) |
| Rule 6: {phone} | Student_phone(sid, phone) |
Primary keys are in bold. In SQL:
CREATE TABLE Department (
did INTEGER PRIMARY KEY,
dname TEXT NOT NULL
);
CREATE TABLE Student (
sid INTEGER PRIMARY KEY,
name TEXT NOT NULL,
street TEXT, -- composite attribute address,
city TEXT, -- flattened into its parts
did INTEGER REFERENCES Department(did) -- 1:N Major: FK on the N side
);
CREATE TABLE Course (
cid TEXT PRIMARY KEY,
title TEXT NOT NULL,
credits INTEGER
);
CREATE TABLE Enrolls ( -- M:N: a table of its own
sid INTEGER REFERENCES Student(sid),
cid TEXT REFERENCES Course(cid),
grade TEXT,
PRIMARY KEY (sid, cid)
);
CREATE TABLE Student_phone ( -- multivalued attribute {phone}
sid INTEGER REFERENCES Student(sid),
phone TEXT,
PRIMARY KEY (sid, phone)
);
Example 2: Company (weak entity and 1:1)
Diagram: Employee (eid, name, salary), Department (dno, dname), Project (pno, pname) and the weak entity Dependent (partial key dep_name, relation), owned by Employee through the identifying relationship Has. Works_For links Department 1:N Employee. Manages links Employee 1:1 Department, with attribute start_date, and every department must have a manager. Works_On links Employee M:N Project, with attribute hours.
| Table | Why |
|---|---|
| Employee(eid, name, salary, dno) | rule 1, plus dno from Works_For (1:N) |
| Department(dno, dname, mgr_eid, start_date) | rule 1, plus Manages (1:1) on the total side |
| Project(pno, pname) | rule 1 |
| Dependent(eid, dep_name, relation) | rule 2: the owner’s key is part of the primary key |
| Works_On(eid, pno, hours) | rule 5 |
The foreign key for Manages is called mgr_eid. A plain eid would be confusing, and with several relationships to the same table, role names like this are essential.
Code
entities = {
'Department': {'key': ['did'], 'attrs': ['did', 'dname']},
'Student': {'key': ['sid'], 'attrs': ['sid', 'name', ('address', ['street', 'city'])], 'multi': ['phone']},
'Course': {'key': ['cid'], 'attrs': ['cid', 'title', 'credits']},
}
relationships = [ # (name, one side, many side, cardinality, attributes)
('Major', 'Department', 'Student', '1:N', []),
('Enrolls', 'Student', 'Course', 'M:N', ['grade']),
]
tables = {}
for name, e in entities.items(): # rule 1: entity -> table
cols = []
for a in e['attrs']:
cols += a[1] if isinstance(a, tuple) else [a] # flatten composite attributes
tables[name] = {'cols': cols, 'pk': e['key']}
for rel, one, many, card, attrs in relationships:
if card == '1:N': # rule 4: FK on the N side
tables[many]['cols'] += tables[one]['pk'] + attrs
elif card == 'M:N': # rule 5: a table of its own
keys = tables[one]['pk'] + tables[many]['pk']
tables[rel] = {'cols': keys + attrs, 'pk': keys}
for name, e in entities.items(): # rule 6: multivalued attributes
for m in e.get('multi', []):
keys = e['key'] + [m]
tables[f'{name}_{m}'] = {'cols': keys, 'pk': keys}
for name, t in tables.items(): # primary-key columns get a *
print(f"{name}({', '.join(c + '*' if c in t['pk'] else c for c in t['cols'])})")
# Department(did*, dname)
# Student(sid*, name, street, city, did)
# Course(cid*, title, credits)
# Enrolls(sid*, cid*, grade)
# Student_phone(sid*, phone*)
After mapping
The tables above are a good start, and they are usually already in a high normal form. Still, check them against their functional dependencies and normalize if needed. Foreign keys are what joins follow to bring the data back together.
Common mistakes
- Putting the 1:N foreign key on the 1 side. A department can’t store a list of employees in one column.
- Using foreign keys for M:N. It needs its own table.
- Repeating columns for a multivalued attribute (phone1, phone2). Make a separate table.
- Forgetting the owner’s key in a weak entity’s primary key. The partial key alone is not unique.
- Forgetting the relationship’s attributes. grade belongs in Enrolls, not in Student or Course.
Complexity at a glance
| Case / operation | Time | Why |
|---|---|---|
| Entities, strong or weak | 1 table each | |
| 1:1 and 1:N relationships | no new table | A foreign key column in an existing table. |
| M:N relationships and multivalued attributes | 1 new table each |
Quick check
Test yourself — pick an answer to see if you got it.
1. In a 1:N relationship (one Department has many Employees), where does the foreign key go?
Each employee has exactly one department, so one column in Employee is enough. In Department it would need many values.
2. How is an M:N relationship such as Enrolls(Student, Course) mapped?
Enrolls(sid, cid, grade) with primary key (sid, cid). Each row is one student taking one course.
3. How is a multivalued attribute {phone} of Student mapped?
A cell holds one value (first normal form). Extra columns would put a limit on the number of phones and leave many NULLs.
4. Dependent is a weak entity with partial key dep_name, owned by Employee (key eid). What is the primary key of the Dependent table?
Two employees can each have a dependent with the same name, so dep_name is unique only within one owner.
5. Manages is a 1:1 relationship between Employee and Department, and every department has a manager. Where is the foreign key best placed?
In Employee it would be NULL for every employee who isn't a manager.