The logical model of a relational database is the collection all its tables.
For each table, we specify:
- A name.
- The column names.
- The primary and foreign key constraints.
👉 We don't specify the column types, nor do we specify any integrity constraints, except for the primary and foreign keys.
Derive a logical model from a conceptual model
Rules exist to derive a logical model from the conceptual model.
We explain these rules on the conceptual model shown in the figure below.
Rules for entities
- Each entity in the conceptual model becomes a table in the logical model.
- A table includes a column for each attribute of the corresponding entity.
- The primary key of a table consists of the columns that are derived from the underlined attributes of the corresponding entity. The underlined attributes in a conceptual model are those that uniquely identify an entity.
Back to our example
Since we have four entities, we obtain four tables.
👉 The underlined columns of a table form the primary key of the table.
segment | (seg_id, seg_color) |
point | (x, y, p_color) |
label | (label_id, label_text, font_size, font_color) |
polygon | (pol_id) |
Rules for one-to-many relationships
Each relationship has cardinalities (min, max)
for each entity involved in the relationship (see here for more details).
A one-to-many relationship is one with maximum cardinality 1 on one side and n
on the other side.
Given a one-to-many relationship, we change the logical model in the following way:
- In the table corresponding to the entity on the 1 side of the relationship, we create a column for each underlined attribute of the entity on the
n
side of the relationship. - The set of these new columns is a foreign key.
Back to our example
The two relationships has_endpoint
are one-to-many. Let's consider one of these relationships.
- We create in table
segment
(on the 1 side of the relationship) two new columnsx1
,y1
(corresponding to the two underlined attributes in the entity on then
side). {x1, y1}
is a foreign key referencing columns{x, y}
in tablepoint
.
We repeat the same logic with the second relationship has_endpoint
.
- We create in table
segment
(on the 1 side of the relationship) two new columnsx2
,y2
(corresponding to the two underlined attributes in the entity on then
side). {x2, y2}
is a foreign key referencing columns{x, y}
in tablepoint
.
We update the logical schema. The new elements are in bold.
👉 The notation T(a, b)
, used in the specification of the foreign keys below, denotes the columns a
, b
in table T
.
segment | (seg_id, seg_color, x1, y1, x2, y2) |
point | (x, y, p_color) |
label | (label_id, label_text, font_size, font_color) |
polygon | (pol_id) |
Foreign keys:
segment(x1, y1)
referencespoint(x, y)
segment(x2, y2)
referencespoint(x, y)
Rules for one-to-one relationships
A one-to-one relationship is one where the maximum cardinality is 1 on both sides. It is a special case of a one-to-many relationship.
Back to our example
Consider the relationship has_label
between segment
and label
.
We have two options:
1. We create a new column label_id
in table segment
.
2. We create a new column seg_id
in table label
.
If we go for the first option, we might have some NULL values in the column label_id
because a segment might have no label.
However, the second option would be worse.
In fact, if we followed the same logic for the other relationships has_label
(the one between point
and label
, and the one between polygon
and label
), we would end up with three columns in table label
: seg_id
, polygon_id
and point_id
. Since a label is attached to either a point, or a segment or a polygon, we would have
NULL values with this solution too. In fact, we would have more NULL values than with the first solution.
👉 Choose the option that minimizes the chances of having NULL values.
We update the logical schema. The new elements are in bold.
segment | (seg_id, seg_color, x1, y1, x2, y2, label_id) |
point | (x, y, p_color, label_id) |
label | (label_id, label_text, font_size, font_color) |
polygon | (pol_id, label_id) |
Foreign keys:
segment(x1, y1)
referencespoint(x, y)
segment(x2, y2)
referencespoint(x, y)
segment(label_id)
referenceslabel(label_id)
point(label_id)
referenceslabel(label_id)
polygon(label_id)
referenceslabel(label_id)
Rules for many-to-many relationships
A many-to-many relationship is one with maximum cardinality n
on both sides.
👉 A many-to-many relationship becomes a table in the logical model.
The columns of this new table include:
- All the underlined attributes of the two entities involved in the relationship. These attributes combined form the primary key of the new table.
- All attributes of the relationship.
Back to our example
The relationship has_side
is a many-to-many relationship. We create a new table side
(note that the name of a table is typically a proper noun) with the following columns: seg_id
(underlined attribute of entity segment
), pol_id
(underlined attribute of entity polygon
), index
(attribute of the relationship).
{seg_id, pol_id}
is the primary key of the tableside
.seg_id
andpol_id
are foreign keys, respectively referencing columnsseg_id
in tablesegment
andpol_id
in tablepolygon
.
We update the logical schema. The new elements are in bold.
segment | (seg_id, seg_color, x1, y1, x2, y2, label_id) |
point | (x, y, p_color, label_id) |
label | (label_id, label_text, font_size, font_color) |
polygon | (pol_id, label_id) |
side | (seg_id, pol_id, index) |
Foreign keys:
segment(x1, y1)
referencespoint(x, y)
segment(x2, y2)
referencespoint(x, y)
segment(label_id)
referenceslabel(label_id)
point(label_id)
referenceslabel(label_id)
polygon(label_id)
referenceslabel(label_id)
side(seg_id)
referencessegment(seg_id)
side(pol_id)
referencespolygon(pol_id)
👉 When a table has a composite primary key (one with many columns), it is possible, even recommended, to create a dummy column whose values uniquely identify a row in the table and is chosen as the primary key.
In our example, we can create a column side_id
in table side
and use it as a primary key.