3.1 Creating Car-Racing Duality Views Using SQL
Team, driver, and race duality views for the car-racing application are created using SQL.
The SQL statements here that define the car-racing duality views use a
simplified syntax which makes use of the JSON
-type constructor
function, JSON
, as shorthand for using SQL/JSON generation
functions to construct (generate) JSON objects and arrays. JSON
{
…}
is simple syntax for using function
json_object
, and JSON
[
…]
is simple syntax for using function
json_array
or json_arrayagg
.
Occurrences of JSON {
…}
and JSON
[
…]
that are embedded within other such occurrences can be
abbreviated as just {
…}
and
[
…]
, it being understood that they are part of an
enclosing JSON generation function.
The arguments to generation function json_object
are
definitions of individual JSON-object members: a field name, such as
points
, followed by a colon (:
) or keyword
IS
, followed by the defining field value (for example,
110
) — 'points' : 110
or 'points' IS
110
. Note that the JSON field names are enclosed with single-quote
characters ('
).
Some of the field values are defined directly as column values from
the top-level table for the view: table driver
(alias
d
) for view driver_dv
, table race
(alias r
) for view race_dv
, and table
team
(alias t
) for view team_dv
.
For example: 'name' : d.name
, for view driver_dv
defines the value of field name
as the value of column
name
of the driver
table.
Other field values are defined using a subquery
(SELECT
...) that selects data from one of the other tables. That
data is implicitly joined, to form the view data.
Some of the subqueries use the syntax JSON
{
…}
, which defines a JSON object with
fields defined by the definitions enclosed by the braces ({
,
}
). For example, JSON {'_id' : r.race_id, 'name' :
r.name}
defines a JSON object with fields _id
and
name
, defined by the values of columns race_id
and
name
, respectively, from table r
(race
).
Other subqueries use the syntax JSON
[
…]
, which defines a JSON array whose
elements are the values that the subquery returns, in the order they are returned. For
example, [ SELECT JSON {…} FROM driver WHERE ... ]
defines a JSON array
whose elements are selected from table driver
where the given
WHERE
condition holds.
Duality views driver_dv
and race_dv
each
nest data from the mapping table driver_race_map
. Two versions of each
of these views are defined, one of which includes a nested object and the other of
which, defined using keyword UNNEST
, flattens that nested object
to just include its fields directly. For view driver_dv
the nested
object is the value of field teamInfo
. For view
race_dv
the nested object is the value of field
driverInfo
. (If you like, you can use keyword
NEST
to make explicit the default behavior of
nesting.)
In most of this documentation, the car-racing examples use the view and document versions without these nested objects.
Nesting is the default behavior for fields from tables other than the root
table. Unnesting is the default behavior for fields from the root table. You can use
keyword NEST
if you want to make the default behavior explicit —
see Example 9-1 for an example. Note that you cannot nest the document
identifier field, _id
, which corresponds to the identifying columns of
the root table; an error is raised if you try.
Example 3-1 Creating Duality View TEAM_DV Using SQL
This example creates a duality view where the team objects look like this
— they contain a field driver
whose value is an array of
nested objects that specify the drivers on the team:
{"_id" : 301, "name" : "Red Bull", "points" : 0, "driver" : [...]}
(The view created is the same as that created using GraphQL in Example 3-6.)
CREATE JSON RELATIONAL DUALITY VIEW team_dv AS
SELECT JSON {'_id' : t.team_id,
'name' : t.name,
'points' : t.points,
'driver' :
[ SELECT JSON {'driverId' : d.driver_id,
'name' : d.name,
'points' : d.points WITH NOCHECK}
FROM driver d WITH INSERT UPDATE
WHERE d.team_id = t.team_id ]}
FROM team t WITH INSERT UPDATE DELETE;
Example 3-2 Creating Duality View DRIVER_DV, With Nested Team Information Using SQL
This example creates a duality view where the driver objects look like
this — they contain a field teamInfo
whose value is a nested
object with fields teamId
and (team) name
:
{"_id" : 101,
"name" : "Max Verstappen",
"points" : 0,
"teamInfo" : {"teamId" : 103, "name" : "Red Bull"},
"race" : [...]}
CREATE JSON RELATIONAL DUALITY VIEW driver_dv AS
SELECT JSON {'_id' : d.driver_id,
'name' : d.name,
'points' : d.points,
'teamInfo' :
(SELECT JSON {'teamId' : t.team_id,
'name' : t.name WITH NOCHECK}
FROM team t WITH NOINSERT NOUPDATE NODELETE
WHERE t.team_id = d.team_id),
'race' :
[ SELECT JSON {'driverRaceMapId' : drm.driver_race_map_id,
'raceInfo' :
(SELECT JSON {'raceId' : r.race_id,
'name' : r.name}
FROM race r WITH NOINSERT NOUPDATE NODELETE
WHERE r.race_id = drm.race_id),
'finalPosition' : drm.position}
FROM driver_race_map drm WITH INSERT UPDATE NODELETE
WHERE drm.driver_id = d.driver_id ]}
FROM driver d WITH INSERT UPDATE DELETE;
Example 3-3 Creating Duality View DRIVER_DV, With Unnested Team Information Using SQL
This example creates a duality view where the driver objects look like
this — they don't contain a field teamInfo
whose value is a nested
object with fields teamId
and name
. Instead, the
data from table team is incorporated at the top level, with the team name as field
team
.
{"_id" : 101,
"name" : "Max Verstappen",
"points" : 0,
"teamId" : 103,
"team" : "Red Bull",
"race" : [...]}
Instead of using 'teamInfo' :
to define top-level field
teamInfo
with an object value resulting from the subquery of
table team
, the view definition precedes that subquery with keyword
UNNEST
, and it uses the data from column name
as the value of field team
. In all other respects, this view
definition is identical to that of Example 3-2.
(The view created is the same as that created using GraphQL in Example 3-7.)
CREATE JSON RELATIONAL DUALITY VIEW driver_dv AS
SELECT JSON {'_id' : d.driver_id,
'name' : d.name,
'points' : d.points,
UNNEST
(SELECT JSON {'teamId' : t.team_id,
'team' : t.name WITH NOCHECK}
FROM team t WITH NOINSERT NOUPDATE NODELETE
WHERE t.team_id = d.team_id),
'race' :
[ SELECT JSON {'driverRaceMapId' : drm.driver_race_map_id,
UNNEST
(SELECT JSON {'raceId' : r.race_id,
'name' : r.name}
FROM race r WITH NOINSERT NOUPDATE NODELETE
WHERE r.race_id = drm.race_id),
'finalPosition' : drm.position}
FROM driver_race_map drm WITH INSERT UPDATE NODELETE
WHERE drm.driver_id = d.driver_id ]}
FROM driver d WITH INSERT UPDATE DELETE;
Note that if for some reason you wanted fields (other than
_id
) from the root table, driver
, to be in a
nested object, you could do that. For example, this code would nest fields
name
and points
in a
driverInfo
object. You could optionally use keyword
NEST
before field driverInfo
, to
make the default behavior of nesting more explicit.
CREATE JSON RELATIONAL DUALITY VIEW driver_dv AS
SELECT JSON {'_id' : d.driver_id,
'driverInfo' : {'name' : d.name,
'points' : d.points},
UNNEST (SELECT JSON {...}),
'race' : ...}
FROM driver d;
Example 3-4 Creating Duality View RACE_DV, With Nested Driver Information Using SQL
This example creates a duality view where the objects that are the
elements of array result
look like this — they contain a field
driverInfo
whose value is a nested object with fields
driverId
and name
:
{"driverRaceMapId" : 3,
"position" : 1,
"driverInfo" : {"driverId" : 103, "name" : "Charles Leclerc"}}
CREATE JSON RELATIONAL DUALITY VIEW race_dv AS
SELECT JSON {'_id' : r.race_id,
'name' : r.name,
'laps' : r.laps WITH NOUPDATE,
'date' : r.race_date,
'podium' : r.podium WITH NOCHECK,
'result' :
[ SELECT JSON {'driverRaceMapId' : drm.driver_race_map_id,
'position' : drm.position,
'driverInfo' :
(SELECT JSON {'driverId' : d.driver_id,
'name' : d.name}
FROM driver d WITH NOINSERT UPDATE NODELETE
WHERE d.driver_id = drm.driver_id)}
FROM driver_race_map drm WITH INSERT UPDATE DELETE
WHERE drm.race_id = r.race_id ]}
FROM race r WITH INSERT UPDATE DELETE;
Example 3-5 Creating Duality View RACE_DV, With Unnested Driver Information Using SQL
This example creates a duality view where the objects that are the
elements of array result
look like this — they don't contain a
field driverInfo
whose value is a nested object with fields
driverId
and name
:
{"driverId" : 103, "name" : "Charles Leclerc", "position" : 1}
Instead of using 'driverInfo' :
to define top-level
field driverInfo
with an object value resulting from the subquery
of table driver
, the view definition precedes that subquery with
keyword UNNEST
. In all other respects, this view definition is
identical to that of Example 3-4.
(The view created is the same as that created using GraphQL in Example 3-8.)
CREATE JSON RELATIONAL DUALITY VIEW race_dv AS
SELECT JSON {'_id' : r.race_id,
'name' : r.name,
'laps' : r.laps WITH NOUPDATE,
'date' : r.race_date,
'podium' : r.podium WITH NOCHECK,
'result' :
[ SELECT JSON {'driverRaceMapId' : drm.driver_race_map_id,
'position' : drm.position,
UNNEST
(SELECT JSON {'driverId' : d.driver_id,
'name' : d.name}
FROM driver d WITH NOINSERT UPDATE NODELETE
WHERE d.driver_id = drm.driver_id)}
FROM driver_race_map drm WITH INSERT UPDATE DELETE
WHERE drm.race_id = r.race_id ]}
FROM race r WITH INSERT UPDATE DELETE;
See Also:
CREATE JSON RELATIONAL DUALITY VIEW in Oracle Database SQL Language Reference
Parent topic: Creating Duality Views