2.3 Car-Racing Example, Tables
Normalized
entities are modeled as database tables. Entity relationships are modeled as joins between
participating tables. Tables team
, driver
, and
race
are used to implement the duality views that provide and support
the team, driver, and race JSON documents used by the car-racing application.
The normalized entities have no content overlap. But we need the database tables that implement the entities to overlap logically, in the sense of a table referring to some content that is stored in another table. To realize this we add columns that are linked to other tables using foreign-key constraints. It is these foreign-key relations among tables that implement their sharing of common content.
The tables used to define a duality view must satisfy these requirements (otherwise an error is raised when you try to create the view):
-
For a table underlying a duality view to be updatable indirectly, through the view (that is, by updating documents supported by the view), the individual rows of the table must be identifiable.
For this requirement, you define one or more columns, called identifying columns for the table, which together identify a row. Identifying columns are primary-key columns, identity columns, or columns with unique constraints or unique indexes.
Columns with unique constraints and columns with unique indexes are sometimes called unique-key columns. A unique key or a primary key is thus a set of one or more columns that uniquely identify a row in a table.
For the root table of a duality view, if one or more unique-key columns are used for this purpose, then at least one of them must, in addition, be marked
NOT NULL
. This prevents any ambiguity that could arise from using aNULL
able unique key or a unique key that has someNULL
columns.The identifying columns for the root table in a duality view correspond to the document-identifier field,
_id
, of the JSON documents that the view is designed to support — see Document-Identifier Field for Duality Views. -
Oracle recommends that you also define an index on each foreign-key column. References (links) between primary and foreign keys must be defined, but they need not be enforced.
Note:
Primary and unique indexes are generally created implicitly when you define primary-key and unique-key integrity constraints. But this is not guaranteed, and indexes can be dropped after their creation. It's up to you to ensure that the necessary indexes are present. See Creating Indexes in Oracle Database Administrator’s Guide.
In general, a value in a foreign-key column can be NULL
.
Besides the above requirements, if you want a foreign-key column to not be
NULL
able, then mark it as NOT NULL
in the table
definition.
There's only one identifying column for each of the tables used in the car-racing example, and it is a primary-key column. In this documentation we sometimes speak of primary, foreign, and unique keys as single-column keys, but keep in mind that they can in general be composite: composed of multiple columns.
In the car-racing example, entities team, driver, and race are implemented
by tables team
, driver
, and race
,
which have the following columns:
-
team
table:-
team_id
— primary key -
name
— unique key -
points
-
-
driver
table:-
driver_id
— primary key -
name
— unique key -
points
-
team_id
— foreign key that links to columnteam_id
of tableteam
-
-
race
table:-
race_id
— primary key -
name
— unique key (so the table has no duplicate rows: there can't be two races with the same name) -
laps
-
race_date
-
podium
-
The logic of the car-racing application mandates that there be only one team
with a given team name, only one driver with a given driver name, and only one race with
a given race name, so column name
of each of these tables is made a
unique key. (This in turn means that there is only one team document with a
given name
field value, only one driver document with a given
name
, and only one race document with a given
name
.)
Table driver
has an additional column,
team_id
, which is data that's logically shared with table
team
(it corresponds to document-identifier field
_id
of the team document). This sharing is defined by declaring the
column to be a foreign key in table driver
,
which links to (primary-key) column team_id
of table
team
. That link implements both the 1:1 relationship from driver to
team and the 1:N relationship from team to driver.
But what about the other sharing: the race information in a driver document that's shared with a race document, and the information in a race document that's shared with a driver document or with a team document?
That information sharing corresponds to the many-to-many (N:N) relationships
between entities driver and race. The database doesn't implement N:N relationships
directly. Instead, we need to add another table, called a mapping
table (or an associative table), to bridge the
relationship between tables driver
and race
. A mapping
table includes, as foreign keys, the primary-key columns of the two tables that it
associates.
An N:N entity relationship is equivalent to a 1:N relationship followed by a
1:1 relationship. We use this equivalence to implement an N:N entity relationship using
database tables, by adding mapping table driver_race_map
between
tables driver
and race
.
Figure 2-2 is equivalent to Figure 2-1. Intermediate entity d-r-map is added to expand each N:N relationship to a 1:N relationship followed by a 1:1 relationship.Foot 1
Figure 2-2 Car-Racing Example, Directed Entity-Relationship Diagram (2)

Description of "Figure 2-2 Car-Racing Example, Directed Entity-Relationship Diagram (2)"
Mapping table driver_race_map
implements
intermediate entity d-r-map. It has the following columns:
-
driver_race_map_id
— primary key -
race_id
— (1) foreign key that links to primary-key columnrace_id
of tablerace
and (2) unique key (so the table has no duplicate rows: there can't be two entries for the same driver for a particular race) -
driver_id
— foreign key that links to primary-key columndriver_id
of tabledriver
-
position
Together with the relations defined by their foreign-key and primary-key links, the car-racing tables form a dependency graph. This is shown in Figure 3-1.
Example 2-4 Creating the Car-Racing Tables
This example creates each table with a primary-key column, whose values
are automatically generated as a sequence of integers, and a unique-key column,
name
. This implicitly also creates unique indexes on the
primary-key columns. The example also creates foreign-key indexes.
Column podium
of table race
has data
type JSON
. Its content is flexible: it need not conform to any
particular structure or field types. Alternatively, its content could be made to
conform to (that is, validate against) a particular JSON schema.
CREATE TABLE team
(team_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
name VARCHAR2(255) NOT NULL UNIQUE,
points INTEGER NOT NULL,
CONSTRAINT team_pk PRIMARY KEY(team_id));
CREATE TABLE driver
(driver_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
name VARCHAR2(255) NOT NULL UNIQUE,
points INTEGER NOT NULL,
team_id INTEGER,
CONSTRAINT driver_pk PRIMARY KEY(driver_id),
CONSTRAINT driver_fk FOREIGN KEY(team_id) REFERENCES team(team_id));
CREATE TABLE race
(race_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
name VARCHAR2(255) NOT NULL UNIQUE,
laps INTEGER NOT NULL,
race_date DATE,
podium JSON,
CONSTRAINT race_pk PRIMARY KEY(race_id));
-- Mapping table, to bridge the tables DRIVER and RACE.
--
CREATE TABLE driver_race_map
(driver_race_map_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
race_id INTEGER NOT NULL,
driver_id INTEGER NOT NULL,
position INTEGER,
CONSTRAINT driver_race_map_uk UNIQUE (race_id, driver_id),
CONSTRAINT driver_race_map_pk PRIMARY KEY(driver_race_map_id),
CONSTRAINT driver_race_map_fk1 FOREIGN KEY(race_id)
REFERENCES race(race_id),
CONSTRAINT driver_race_map_fk2 FOREIGN KEY(driver_id)
REFERENCES driver(driver_id));
-- Create foreign-key indexes
--
CREATE INDEX driver_fk_idx ON driver (team_id);
CREATE INDEX driver_race_map_fk1_idx ON driver_race_map (race_id);
CREATE INDEX driver_race_map_fk2_idx ON driver_race_map (driver_id);
Note:
Primary-key, unique-key, and foreign-key integrity constraints must be defined for the tables that underlie duality views (or else an error is raised), but they need not be enforced.
In some cases you might know that the conditions for a given constraint
are satisfied, so you don't need to validate or enforce it. You might nevertheless
want the constraint to be present, to improve query performance. In that case, you
can put the constraint in the RELY
state, which asserts that
the constraint is believed to be satisfied. See RELY Constraints in a Data Warehouse in Oracle Database Data
Warehousing Guide.
You can also make a foreign key constraint DEFERRABLE
, which
means that the validity check is done at the end of a transaction. See Deferrable Constraints in Oracle Database
Concepts
Note:
The SQL data types allowed for a column in a table underlying a duality
view are BINARY_DOUBLE
, BINARY_FLOAT
,
BLOB
, BOOLEAN
, CHAR
,
CLOB
, DATE
, JSON
,
INTERVAL DAY TO SECOND
, INTERVAL YEAR TO
MONTH
, NCHAR
, NCLOB
,
NUMBER
, NVARCHAR2
, VARCHAR2
,
RAW
, TIMESTAMP
, TIMESTAMP WITH TIME
ZONE
, and VECTOR
. An error is raised if you specify
any other column data type.
Related Topics
See Also:
-
JSON Schema in Oracle Database JSON Developer’s Guide
-
CREATE TABLE in Oracle Database SQL Language Reference
Parent topic: Introduction To Car-Racing Duality Views Example
Footnote Legend
Footnote 1: In the notation used here, N does not represent a number; it's simply an abbreviation for "many", or more precisely, "one or more".