DDM Unit-5
DDM Unit-5
–Subtypes and super types –user-defined routines –Collection types –Object Query
Language; No-SQL: CAP theorem –Document-based: MongoDB data model and CRUD
operations; Column-based: Hbase data model and CRUD operations.
Step 1. Create an ODL class for each EER entity type or subclass. The type of the ODL
class should include all the attributes of the EER class. Multivalued attributes are
typically declared by using the set, bag, or list constructors.
If the values of the multivalued attribute for an object should be ordered, the list
constructor is chosen; if duplicates are allowed, the bag constructor should be chosen;
otherwise, the set constructor is chosen. Composite attributes are mapped into a tuple
constructor (by using a struct declaration in ODL).
Declare an extent for each class, and specify any key attributes as keys of the extent.
(This is possible only if an extent facility and key constraint declarations are available in
the ODBMS.)
Step 2. Add relationship properties or reference attributes for each binary relationship
into the ODL classes that participate in the relationship. These may be created in one or
both directions.
If a binary relationship is represented by references in both directions, declare the
references to be relationship properties that are inverses of one another, if such a
facility exists. If a binary relationship is represented by a reference in only one direction,
declare the reference to be an attribute in the referencing class whose type is the
referenced class name.
Depending on the cardinality ratio of the binary relationship, the relationship properties
or reference attributes may be single-valued or collection types. They will be single-
valued for binary relationships in the 1:1 or N:1 direction; they are collection types (set-
valued or list-valued) for relationships in the 1: N or M: N direction. An alternative way to
map binary M: N relationships is discussed in step 7.
If relationship attributes exist, a tuple constructor (struct) can be used to create a
structure of the form < reference, relationship attributes >, which may be included
instead of the reference attribute. However, this does not allow the use of the inverse
1
constraint. Additionally, if this choice is represented in both directions, the attribute
values will be represented twice, creating redundancy.
This implicitly uses a tuple constructor at the top level of the type declaration, but in
general, the tuple constructor is not explicitly shown in the ODL class declarations.
Further analysis of the application domain is needed to decide which constructor to use
because this information is not available from the EER schema.
The ODL standard provides for the explicit definition of inverse relationships. Some
ODBMS products may not provide this support; in such cases, programmers must
maintain every relationship explicitly by coding the methods that update the objects
appropriately. The decision whether to use set or list is not available from the EER
schema and must be determined
Object and Object-Relational Databases
Step 3. Include appropriate operations for each class. These are not available from the
EER schema and must be added to the database design by referring to the origi- nal
requirements.
A constructor method should include program code that checks any constraints that
must hold when a new object is created. A destructor method should check any
constraints that may be violated when an object is deleted. Other methods should
include any further constraint checks that are relevant.
Step 4. An ODL class that corresponds to a subclass in the EER schema inherits (via
extends) the type and methods of its superclass in the ODL schema. Its specific
(noninherited) attributes, relationship references, and operations are specified, as
discussed in steps 1, 2, and 3.
Step 5. Weak entity types can be mapped in the same way as regular entity types.
An alternative mapping is possible for weak entity types that do not participate in any
relationships except their identifying relationship; these can be mapped as though they
were composite multivalued attributes of the owner entity type, by using the set < struct
< ... >> or list < struct < ... >> constructors. The attributes of the weak entity are included
in the struct < ... > construct, which corresponds to a tuple constructor. Attributes are
mapped as discussed in steps 1 and 2.
Step 6. Categories (union types) in an EER schema are difficult to map to ODL. It is
possible to create a mapping similar to the EER-to-relational mapping by declaring a
class to represent the category and defining 1:1 relationship between the category and
each of its superclasses. Another option is to use a union type, if it is available.
Step 7. An n-ary relationship with degree n > 2 can be mapped into a separate class,
with appropriate references to each participating class.
These references are based on mapping a 1: N relationship from each class that
2
represents a participating entity type to the class that represents the n-ary relationship.
An M: N binary relationship, especially if it contains relationship attributes, may also use
this mapping option, if desired.
5.2 Object identifier
An object identifier (OID) is an unambiguous, long-term name for any type of object or
entity.
The OID mechanism finds application in diverse scenarios, particularly in security, and is
endorsed by the International Telecommunication Union (ITU), the Internet Engineering
Task Force (IETF), and ISO.
What is an OID?
An object identifier (OID) is an extensively used identification mechanism jointly
developed by ITU-T and ISO/IEC for naming any type of object, concept or "thing" with a
globally unambiguous name which requires a persistent name (long life-time). It is not
intended to be used for transient naming. OIDs, once allocated, should not be re-used
for a different object/thing.
It is based on a hierarchical name structure based on the "OID tree". This naming
structure uses a sequence of names, of which the first name identifies a top-level
"node" in the OID tree, and the next provides further identification of arcs leading to sub-
nodes beneath the top-level, and so on to any depth.
A critical feature of this identification mechanism is that it makes OIDs available to a
great many organizations and specifications for their own use (including countries, ITU-
T Recommendations, ISO and IEC International Standards, specifications from national,
regional or international organizations, etc.).
How are OIDs allocated and what is a registration authority?
At each node, including the root, there is a requirement for some organization or
standard to be responsible for allocating arcs to sub-nodes and recording that
allocation (together with the organization the subordinate node has been allocated to),
not necessarily publicly. This activity is called a Registration Authority (RA).
In the OID tree, RAs are generally responsible only for allocation of sub-arcs to other
RAs that then control their own sub-nodes. In general, the RA for a sub-node operates
independently in allocating further sub-arcs to other organizations, but can be
3
constrained by rules imposed by its superior, should the superior so wish.
The registration tree is indeed managed in a completely decentralized way (a node gives
full power to its children).
The registration tree is defined and managed following the ITU-T X.660 & X.670
Recommendation series (or the ISO/IEC 9834 series of International Standards)
What is an OID repository?
Initially, it was left for each Registration Authority (RA)in the hierarchy to maintain its
own record of allocation beneath that RA, and to keep those allocations private if it so
chose. There was never any policing of this. An RA in the hierarchy was its own master
and operated autonomously.
In the early 1990s Orange developed software for their internal use which was generic
enough to provide a publicly available repository of OID allocations.
Information on OIDs is often buried inside the databases (perhaps sometimes paper)
maintained by an immense number of RAs. The information can be hard to access and
is sometimes private. Today this OID repository is regarded as the easiest way to
access a large amount of the publicly available information on OIDs: Many OIDs are
recorded but it does not contain all existing OIDs.
This OID repository is not an official Registration Authority, so any OID described on this
web site has to be officially allocated by the RA of its parent OID. The accuracy and
completeness of this OID repository rely on crowdsourcing, i.e., each user is welcome to
contribute data.
4
The required syntax for a <reference type> specification is as follows.
<reference type>:: =
REF (<UDT name>)
[ SCOPE <Table name> [reference scope check] ]
<reference scope check> ::=
REFERENCES ARE [NOT] CHECKED
[ ON DELETE
5
CREATE TABLE Table_1 (
column_1 SMALLINT,
column_2 REF(my_udt) SCOPE Table_2);
If you omit the SCOPE clause, the scope defaults to the Table that owns the Column
you’re defining.
If your REF specification with a SCOPE clause is part of a <Field definition>, it must
include this <reference scope checks>: REFERENCES ARE [NOT] CHECKED ON DELETE
NO ACTION.
If a REF specification with a SCOPE clause is part of a <Column definition>, it must
include a <reference scope checks> with or without the optional ON DELETE sub-clause.
The <reference scope check> clause may not be used under any other circumstances.
A <reference type> is a subtype of a <data type> if (a) both are <reference type>s and (b)
the UDT referenced by the first <reference type> is a subtype of the UDT referenced by
the second <reference type>.
If you want to restrict your code to Core SQL, don’t use the REF <data type>.
Reference Operations
A <reference type> is compatible with, and comparable to, all other <reference type>s of
the same referenced type – that is, <reference type>s are mutually comparable and
mutually assignable if they are based on the same UDT.
CAST
In SQL, CAST is a scalar operator that converts a given scalar value to a given scalar
<data type>. CAST, howver, can´t be used with <reference type>s. To cast REF values,
you´ll have to use a user-defined cast.
It isn’t, of course, possible to convert the values of every <data type> into the values of
every other <data type>. You can cast a <reference type> source to a UDT target and to
any SQL predefined <data type> target (except for <collection type>s and <row type>s)
provided that a user-defined cast exist for this purpose and your current
<AuthorizationID> has the EXECUTE Privilege on that user-defined cast. When you cast
a <reference type> to any legal target, your DBMS incokes the user-defined cast. When
you cast a <reference type> to any legal target, your DBMS invokes the user-defined
cast routine´s argument. The cast result in the value returned by the user-defined cast.
Assignment
In SQL, when a <reference type> is assigned to a <reference type> target, the
assignment is straightforward – however, assignment is possible only if your source’s
UDT is a subtype of the UDT of your target.
6
[Obscure Rule] Since only SQL accepts null values, if your source is NULL, then your
target’s value is not changed. Instead, your DBMS will set its indicator parameter to -1,
to indicate that an assignment of the null value was attempted. If your target doesn’t
have an indicator parameter, the assignment will fail: your DBMS will return the
SQLSTATE error 22002 "data exception-null value, no indicator parameter". Going the
other way, there are two ways to assign a null value to an SQL-data target. Within SQL,
you can use the <keyword> NULL in an INSERT or an UPDATE statement to indicate that
the target should be set to NULL; that is, if your source is NULL, your DBMS will set your
target to vNULL``. Outside of SQL, if your source has an indicator parameter that is set
to -1, your DBMS will set your target to NULL (regardless of the value of the source). (An
indicator parameter with a value less than -1 will cause an error: your DBMS will return
the SQLSTATE error 22010 "data exception-invalid indicator parameter value".) We’ll talk
more about indicator parameters in our chapters on SQL binding styles.
Comparison
SQL provides only two scalar comparison operators – = and <> – to perform operations
on <reference type>s. Both will be familiar; there are equivalent operators in other
computer languages. Two REF values are comparable if they’re both based on the same
UDT. If either of the comparands are NULL, the result of the operation is UNKNOWN.
Other Operations
With SQL, you have several other operations that you can perform on <reference type>s.
Scalar functions
SQL provides two scalar functions that operate on or return a <reference type>: the
<dereference operation> and the <reference resolution>.
<dereference operation>
The required syntax for a <dereference operation> is as follows.
<dereference operation>:: = reference_argument -> <Attribute name>
The <dereference operation> operates on two operands — the first must evaluate to a
<reference type> that has a non-empty scope and the second must be the name of an
Attribute of the <reference type>’s UDT.
The <dereference operation> allows you to access a Column of the row identified by a
REF value; it returns a result whose <data type> is the <data type> of <Attribute name>
and whose value is the value of the system-generated Column of the Table in the
<reference type>’s scope (where the system-generated Column is equal to
reference_argument). That is, given a REF value, the <dereference operation> returns
the value at the site referenced by that REF value. If the REF value doesn’t identify a site
(perhaps because the site it once identified has been destroyed), the <dereference
operation> returns NULL.
7
If you want to restrict your code to Core SQL, don’t use the <dereference operation>.
<reference resolutions>
The required syntax for a <dereference operation> is as follows.
<dereference operation>:: = reference_argument -> <Attribute name>
DEREF operates on any expression that evaluates to a <reference type> that has a non-
empty scope. It returns the value referenced by a REF value. Your current
<AuthorizationID> must have the SELECT WITH HIERARCHY Privilege on
reference_argument's scope Table.
If you want to restrict your code to Core SQL, don’t use DEREF.
Set Functions
SQL provides three set functions that operate on a <reference type>: COUNT and
GROUPING. Since none of these operate exclusively with REF arguments, we won’t
discuss them here; look for them in our chapter on set functions.
Predicates
In addition to the comparison operators, SQL provides eight other predicates that
operate on <reference type>s: the <between predicate>, the <in predicate>, the <null
predicate>, the <exists predicate>, the <unique predicate>, the <match predicate>, the
<quantified predicate> and the <distinct predicate>. Each will return a boolean value:
either TRUE, FALSE or UNKNOWN. Since none of them operates strictly on <reference
type>s, we won’t discuss them here. Look for them in our chapters on search conditions.
8
The required syntax for a <row type> specification is as follows.
<row type> ::= ROW (<Field definition> [ {,<Field definition>}... ])
<Field definition> ::= <Field name> {<data type> | <Domain name>}
[ <reference scope check> ]
[ COLLATE <Collation name> ]
A <row type> specification defines a row of data: it consists of a sequence of one or
more parenthesized {<Field name>,<data type>} pairs, known as Fields. The degree of a
row is the number of Fields it contains. A value of a row consists of one value for each
of its Fields, while a value of a Field is a value of the Field’s <data type>. Each Field in a
row must have a unique name.
Example of a <row type> specification:
ROW (field_1 INT, field_2 DATE, field_3 INTERVAL (4) YEAR)
A <Field name> identifies a Field and is either a <regular identifier> or a <delimited
identifier> that is unique (for all Fields and Columns) within the Table it belongs to. You
can define a Field’s <data type> either by putting a <data type> specification after <Field
name> or by putting a <Domain name> after the <Field name>. The <data type> of a
Field can be any type other than a <reference type> – in particular, it can itself be a <row
type>.
Example, of a <row type> specification;
It defines a row with one Field (called field_1) whose defined <data type> is DATE:
ROW (field_1 DATE)
[Obscure Rule] If the <data type> of a Field is CHAR, VARCHAR or CLOB, the Character
set that the Field’s values must belong to is determined as follows:
If the <Field definition> contains a <data type> specification that includes a
CHARACTER SET clause, the Field’s Character set is the Character set named.
Your current <AuthorizationID> must have the USAGE Privilege on that Character
set.
If the <Field definition> does not include a <data type> specification, but the Field
is based on a Domain whose definition includes a CHARACTER SET clause, the
Field’s Character set is the Character set named.
If the <Field definition> does not include any CHARACTER SET clause at all –
either through a <data type> specification or through a Domain definition – the
Field’s Character set is the Character set named in the DEFAULT CHARACTER
SET clause of the CREATE SCHEMA statement that defines the Schema that the
Field belongs to.
9
For example, the effect of these two SQL statements:
CREATE SCHEMA bob AUTHORIZATION bob
DEFAULT CHARACTER SET INFORMATION_SCHEMA.LATIN1;
CREATE TABLE Table_1 (
column_1 ROW(
field_1 CHAR(10),
field_2 INT));
is to create a Table in Schema bob. The Table has a Column with a ROW <data type>,
containing two Fields.
The character string Field’s set of valid values are fixed length character strings, exactly
10 characters long, all of whose characters must be found in the
INFORMATION_SCHEMA.LATIN1 Character set – the Schema’s default Character set.
The effect of these two SQL statements:
CREATE SCHEMA bob AUTHORIZATION bob
DEFAULT CHARACTER SET INFORMATION_SCHEMA.LATIN1;
CREATE TABLE Table_1 (
column_1 ROW(
field_1 CHAR(10) CHARACTER SET INFORMATION_SCHEMA.SQL_CHARACTER,
field_2 INT));
is to create the same Table with one difference: this time, the character string Field’s
values must consist only of characters found in the
INFORMATION_SCHEMA.SQL_CHARACTER Character set – the explicit Character set
specification in CREATE TABLE constrains the Field’s set of values. The Schema’s
default Character set does not.
[Obscure Rule] If the <data type> of a Field is CHAR, VARCHAR, CLOB, NCHAR, NCHAR
VARYING or NCLOB, and your <Field definition> does not include a COLLATE clause, the
Field has a coercibility attribute of COERCIBLE – but if your <Field definition> includes a
COLLATE clause, the Field has a coercibility attribute of IMPLICIT. In either case, the
Field’s default Collation is determined as follows:
If the <Field definition> includes a COLLATE clause, the Field’s default Collation is
the Collation named. Your current <Authorization ID> must have the USAGE
Privilege on that Collation.
If the <Field definition> does not include a COLLATE clause, but does contain a
10
<data type> specification that includes a COLLATE clause, the Field’s default
Collation is the Collation named. Your current <Authorization ID> must have the
USAGE Privilege on that Collation.
If the <Field definition> does not include a COLLATE clause, but the Field is based
on a Domain whose definition includes a COLLATE clause, the Field’s default
Collation is the Collation named.
If the <Field definition> does not include any COLLATE clause at all – either
explicitly, through a <data type> specification or through a Domain definition –
the Field’s default Collation is the default Collation of the Field’s Character set.
[Obscure Rule] If the <data type> of a Field is REF(UDT), your current <AuthorizationID>
must have the USAGE Privilege on that UDT. If the <data type> of a Field includes REF
with a <scope clause>, your <Field definition> must also include this <reference scope
check> clause: REFERENCES ARE [NOT] CHECKED ON DELETE NO ACTION – to
indicate whether references are to be checked or not. Do not add a <reference scope
check> clause under any other circumstances.
If a Field is defined with REFERENCES ARE CHECKED, and a <scope clause> is
included in the <Field definition>, then there is an implied DEFERRABLE INITIALLY
IMMEDIATE Constraint on the Field. This Constraint checks that the Field´s
values are also found in the corresponding Field of the system-generated Column
of the Table named in the <scope clause>.
If the <data type> of a Field in a row is a UDT, then the current <AuthorizationID>
must have the USAGE Privilege on that UDT.
A <row type> is a subtype of a <data type> if (a) both are <row type>s with the
same degree and (b) for every pair of corresponding <Field definition>s, the
<Field name>s are the same and the <data type> of the Field in the first <row
type> is a supertype of the <data type> of the Field in the second <row type>.
<row reference>
A <row reference> returns a row. The required syntax for a <row reference> is as follows.
<row reference> ::= ROW {<Table name> | <query name> | <Correlation name>}
A row of data values belonging to a Table (or a query result, which is also a Table) is
also considered to be a <row type>.
In a Table, each Column of a data row corresponds to a Field of the <row type>: the
Column and Field have the same ordinal positions in the Table and <row type>,
respectively.
A <row reference> allows you to access a specific row of a Table or a query result. Here
is an example of a <row reference> that would return a row of a Table named TABLE_1:
11
ROW(Table_1)
<Field reference>
A <Field reference> returns a Field of a row. The required syntax for a <Field reference>
is as follows.
<Field reference> ::= row_argument.<Field name>
A <Field reference> allows you to access a specific Field of a row. It operates on two
arguments: the first must evaluate to a <row type> and the second must be the name of
a Field belonging to that row.
If the value of row_argument is NULL, then the specified Field is also NULL.
If row_argument has a non-null value, the value of the Field reference is the value of the
specified Field in row_argument. Here is an example of a <Field reference> that would
return the value of a Field named FIELD_1 that belongs to a row of TABLE_1:
ROW(Table_1).field_1
<row value constructor>
An <row value constructor> is used to construct a row of data. The required syntax for a
<row value constructor> is as follows.
<row value constructor> ::= element_expression |
[ ROW ] (element_expression [ {,element_expression}... ]) |
( <query expression> )
element_expression ::=
element_expression |
NULL |
ARRAY[] |
ARRAY??(??) |
DEFAULT
A <row value constructor> allows you to assign values to the Fields of a row, using
either a list of element_expressions of the result of a subquery. An element_expression
may be any expression that evaluates to a scalar value with a <data type> that is
assignable to the corresponding Field’s <data type>. A subquery – ( <query expression> )
– is discussed in our chapter on complex queries.
The result is a row whose n-th Field value is the value of the n-th element_expression
(or whose value is the value of the subquery) you specify. If your element_expression is
12
NULL, the corresponding Field is assigned the null value. If your element_expression is
ARRAY [] or ARRAY??(??), the corresponding Field is assigned an empty array. If your
element_expression is DEFAULT, the corresponding Field is assigned its default value.
Here is an example of a <row value constructor>:
ROW ('hello',567, DATE '1994-07-15’, NULL, DEFAULT, ARRAY [])
This example constructs a row with six Fields. The first Field has a character string
value of 'hello', the second has a numeric value of 567, the third has a date value of
'1994-07-15', the fourth has a null value, the fifth has a value that is the fifth Field’s
default value and the sixth has a value that is an empty array. This <row value
constructor> would be valid for this <row type> specification:
ROW (field_1 CHAR (5),
field_2 SMALLINT,
field_3 DATE,
field_4 BIT (4),
field_5 domains_1,
field_6 INT ARRAY [4])
A <row value constructor> serves the same purpose for a row as a <literal> does for a
predefined <data type>. It has the same format as the <row type>’s ROW () – but
instead of a series of <Field definition>s inside the size delimiters, it contains comma-
delimited values of the correct <data type> for each Field. For example, if your <row
type> specification is:
ROW (field_1 INT, field_2 CHAR (5), field_3 BIT (4))
a valid <row value constructor> would be:
ROW (20,'hello’, B'1011')
If you construct a row with a subquery, the row takes on the <data type> of the
subquery’s result. An empty subquery result constructs a one-Field row whose value is
NULL. A non-empty subquery result constructs a one-Field row whose value is the
subquery result.
If you want to restrict your code to Core SQL, (a) don’t use the ROW <data type> or <row
reference>s and <Field reference>s and, when using a <row value constructor>, (b) don’t
use ARRAY[] or ARRAY??(??) as an element_expression,(c) don’t construct a row with
more than one Field,(d) don’t use the ROW <keyword> in front of your
element_expression, and (e) don’t use a subquery to construct your row.
Row Operations
13
A row is compatible with, and comparable to, any row with compatible Fields – that is,
rows are mutually comparable and mutually assignable only if they have the same
number of Fields and each corresponding pair of Fields are mutually comparable and
mutually assignable. Rows may not be directly compared with, or directly assigned to,
any other <data type> class, though implicit type conversions of their Fields can occur in
expressions, SELECTs, INSERTs, DELETEs and UPDATEs. Explicit row type conversions
are not possible.
Assignment
In SQL, when a <row type> is assigned to a <row type> target, the assignment is done
one Field at a time – that is, the source’s first Field value is assigned to the target’s first
Field, the source’s second Field value is assigned to the target’s second Field, and so on.
Assignment of a <row type> to another <row type> is possible only if (a) both <row
type>s have the same number of Fields and (b) each corresponding pair of Fields have
<data type>s that are mutually assignable.
[Obscure Rule] Since only SQL accepts null values, if your source is NULL, then your
target’s value is not changed. Instead, your DBMS will set its indicator parameter to -1,
to indicate that an assignment of the null value was attempted.
If your target doesn’t have an indicator parameter, the assignment will fail: your DBMS
will return the SQLSTATE error 22002 "data exception-null value, no indicator parameter".
Going the other way, there are two ways to assign a null value to an SQL-data target.
Within SQL, you can use the <keyword> NULL in an INSERT or an UPDATE statement to
indicate that the target should be set to NULL; that is, if your source is NULL, your DBMS
will set your target to NULL.
Outside of SQL, if your source has an indicator parameter that is set to -1, your DBMS
will set your target to NULL (regardless of the value of the source). (An indicator
parameter with a value less than -1 will cause an error: your DBMS will return the
SQLSTATE error 22010 "data exception-invalid indicator parameter value".) We’ll talk
more about indicator parameters in our chapters on SQL binding styles.
Comparison
SQL provides the usual scalar comparison operators – = and <> and < and <= and > and
>= – to perform operations on rows. All of them will be familiar; there are equivalent
operators in other computer languages. Two rows are comparable if (a) both have the
same number of Fields and (b) each corresponding pair of Fields have <data type>s that
are mutually comparable.
Comparison is between pairs of Fields in corresponding ordinal positions – that is, the
first Field of the first row is compared to the first Field of the second row, the second
Field of the first row is compared to the second Field of the second row, an so on. If
either comparand is NULL the result of the operation is UNKNOWN.
14
The result of a <row type> comparison depends on two things: (a) the comparison
operator and (b) whether any Field is NULL. The order of comparison is:
If the comparison operator is = or <>: First the Field pairs which don´t include NULLs,
then the pairs which do.
If the comparison operator is anything other than = or <>: Field pairs from left to right.
Comparison stops when the result is unequal or UNKNOWN, or when there are no more
Fields. The result of the row comparison is the result of the last Field pair comparison.
Here are the possibilities.
If the comparison operator is =. The row comparison is (a) TRUE if the comparison is
TRUE for every pair of Fields, (b) FALSE if any non-null pair is not equal, and (c)
UNKNOWN if at least one Field is NULL and all non-null pairs are equal. For example:
ROW (1,1,1) = ROW (1,1,1) -- returns TRUE
ROW (1,1,1) = ROW (1,2,1) -- returns FALSE
ROW (1, NULL,1) = ROW (2,2,1) -- returns FALSE
ROW (1, NULL,1) = ROW (1,2,1) -- returns UNKNOWN
Comparison operator is <>. The row comparison is (a) TRUE if any non-null pair is not
equal, (b) FALSE if the comparison is FALSE for every pair of Fields, and (c) UNKNOWN
if at least one Field is NULL and all non-null pairs are equal. For example:
ROW (1,1,1) <> ROW (1,2,1) -- returns TRUE
ROW (1, NULL,2) <> ROW (2,2,1) -- returns TRUE
ROW (2,2,1) <> ROW (2,2,1) -- returns FALSE
ROW (1, NULL,1) <> ROW (1,2,1) -- returns UNKNOWN
Comparison operator is anything other than = or <>.
The row comparison is
(a) TRUE if the comparison is TRUE for at least one pair of Field and every pair before
the TRUE result is equal,
(b) FALSE uf the comparison is FALSE for at least one pair of Fields and every pair
before the FALSE result is equal, and
(c) UNKNOWN if the comparison is UNKNWON for at least one pair of Fields and every
pair before the UNKNOWN result is equal. Comparison stops as soon as any of these
results (TRUE, FALSE, or UNKNOWN) is established. For example:
ROW (1,1,1) < ROW (1,2,1) -- returns TRUE
15
ROW (1, NULL,1) < ROW (2, NULL,0) -- returns TRUE
ROW (1,1,1) < ROW (1,1,1) -- returns FALSE
ROW (3, NULL,1) < ROW (2, NULL,0) -- returns FALSE
ROW (2, NULL,1) < ROW (1,2,0) -- returns UNKNOWN
ROW (NULL,1,1) < ROW (2,1,0) -- returns UNKNOWN
SQL also provides three quantifiers – ALL, SOME, ANY – which you can use along with a
comparison operator to compare a row value with the collection of values returned by a
<table subquery>. Place the quantifier after the comparison operator, immediately
before the <table subquery>. For example:
SELECT row_column
FROM Table_1
WHERE row_column < ALL (
SELECT row_column
FROM Table_2);
ALL returns TRUE either (a) if the collection is an empty set (i.e.: if it contains zero rows)
or (b) if the comparison operator returns TRUE for every value in the collection. ALL
returns FALSE if the comparison operator returns FALSE for at least one value in the
collection.
SOME and ANY are synonyms. They return TRUE if the comparison operator returns
TRUE for at least one value in the collection. They return FALSE either (a) if the
collection is an empty set or (b) if the comparison operator returns FALSE for every
value in the collection. The search condition = ANY (collection) is equivalent to “IN
(collection)``
5.5 UDTs
A UDT is defined by a descriptor that contains twelve pieces of information:
1. The <UDT name>, qualified by the <Schema name> of the Schema it belongs to.
2. Whether the UDT is ordered.
3. The UDT’s ordering form: either EQUALS, FULL or NONE.
4. The UDT’s ordering category: either RELATIVE, HASH or STATE.
5. The <specific routine designator> that identifies the UDT’s ordering function.
6. If the UDT is a direct subtype of one or more other UDTs, then the names of
16
those UDTs.
7. If the UDT is a distinct type, then the descriptor of the <data type> it’s based on;
otherwise an Attribute descriptor for each of the UDT’s Attributes.
8. The UDT’s degree: the number of its Attributes.
9. Whether the UDT is instantiable or not instantiable.
10. Whether the UDT is final or not final.
11. The UDT’s Transform descriptor.
12. If the UDT’s definition includes a method signature list, a descriptor for each
method signature named.
To create a UDT, use the CREATE TYPE statement (either as a stand-alone SQL
statement or within a CREATE SCHEMA statement). CREATE TYPE specifies the
enclosing Schema, names the UDT and identifies the UDT’s set of valid values.
To destroy a UDT, use the DROP TYPE statement. None of SQL3’s UDT syntax is Core
SQL, so if you want to restrict your code to Core SQL, don’t use UDTs.
UDT Names
A <UDT name> identifies a UDT. The required syntax for a <UDT name> is:
<UDT name> ::= [ <Schema name>. ] unqualified name
A <UDT name> is a <regular identifier> or a <delimited identifier> that is unique (for all
Domains and UDTs) within the Schema it belongs to. The <Schema name> which
qualifies a <UDT name> names the Schema that the UDT belongs to and can either be
explicitly stated, or a default will be supplied by your DBMS as follows:
17
NOT FINAL -- this is a mandatory Finality Clause
METHOD profit () RETURNS DECIMAL (9,2); -- profit is a method, defined later
This CREATE TYPE statement results in a UDT named BOOK_UDT. The components of
the UDT are three attributes (named TITLE, BUYING_PRICE and SELLING_PRICE) and
one method (named PROFIT).
The three name-and-data-type pairs title CHAR (40) and buying_price DECIMAL (9,2)
and selling_price DECIMAL (9,2) are the UDT’s Attribute definitions.
The words NOT FINAL matter only for subtyping, which we’ll get to later. Briefly,
though, if a UDT definition doesn’t include an UNDER clause, the finality clause must
specify NOT FINAL.
The clause METHOD profit () RETURNS DECIMAL (9,2) is a teaser. Like an Attribute, a
“method” is a component of a UDT. However, this method – PROFIT – is actually a
declaration that a function named PROFIT exists.
This function isn’t defined further in the UDT definition – there is a separate SQL
statement for defining functions: CREATE METHOD. All we can see at this stage is that
PROFIT has a name and a (predefined) data type>, just as regular Attributes do. Some
people would call PROFIT a “derived Attribute”.
18
Customers can pay by cash, by check, or by credit card.
All payments have some common attributes: payment date, payment amount, and so
on.
But only credit cards would have a “card number” attribute.
And for credit card and check payments, we may need to know which CUSTOMER
made the payment, while this is not needed for cash payments
Should we create a single PAYMENT entity or three separate entities CASH, CHECK,
and CREDIT CARD?
And what happens if in the future we introduce a fourth method of payment?
Subdivide an Entity
Sometimes it makes sense to subdivide an entity into subtypes.
This may be the case when a group of instances has special properties, such as
attributes or relationships that exist only for that group.
In this case, the entity is called a “supertype” and each group is called a “subtype”.
Subtype Characteristics
A subtype:
Inherits all attributes of the supertype
Inherits all relationships of the supertype
Usually has its own attributes or relationships
Is drawn within the supertype
Never exists alone
May have subtypes of its own
19
Supertype Example
EXAM is a supertype of QUIZ, MIDTERM, and FINAL.
The subtypes have several attributes in common.
These common attributes are listed at the supertype level.
20