10 Registering Application Data Usage with the Database
This chapter details how you can use centralized database-centric entities called application data usage domains and annotations to register information about the intended application data usage.
Oracle Database 23c introduces a centralized, database-centric approach to handling intended data usage information using application usage domains and annotations. You can add usage domains and annotations centrally in the database to register data usage intent, which is then accessible to various applications and tools.
See Also:
-
Oracle Database Concepts for information about Application Usage Domains and Application Usage Annotations.
-
Oracle Database SQL Language Reference for the syntactic and semantic information about usage domains and annotations.
10.1 Application Usage Domains
This section explains how you can use application usage domains (hereinafter "usage domains") in your applications.
Topics:
10.1.1 Overview of Usage Domains
Usage domains are lightweight usage specifiers with the optional database-side enforcement that applications can use to centrally document intended data usage. As a high-level dictionary object, a usage domain includes built-in usage properties associated with table columns, such as the default value, check constraints, collations, display and order formats, and annotations. Using centralized domain information, applications can standardize operations without depending on application-level metadata. For example, you can use usage domains to mask credit card numbers or to format phone numbers and currency values.
As a database object, a usage domain belongs to a schema and provides a common column definition without modifying the underlying column data type. A usage domain encapsulates some common characteristics of a table column into a reusable object that can be reused on other table columns without having to repeat these characteristics.
For example, a schema may have many tables with columns that hold email
addresses, such as billing emails, invoice emails, and customer contact emails. Email
addresses have a special format because they require the "@" sign. You can define a
usage domain for the email address using a check constraint such as regexp_like
(email_dom, '^(\S+)\@(\S+)\.(\S+)$')
, and associate the domain with other
email columns to have your application display the associated column's email addresses
with the standard "@" sign prior to the domain name. Likewise, you may want to
standardize display formats for vehicle license plates, which may require hyphens to
separate the number from the other information. Using a usage domain, you can show the
license information as "ABC-123" even when the license column has a varchar2(6) data
type.
Benefits of using a usage domain include: improved data quality because it enables you to handle values consistently across applications; reduced coding because you can reuse a column's properties and constraints across your application; and consistency and clarity in operations because applications can inquire about these usage domains to understand what data they are operating against.
See Also:
Oracle Database Concepts for more information about Application Usage Domains.
10.1.2 Usage Domain Types and When to Use Them
There are three different types of domains: single-column, multi-column, and flexible domains.
Single-column Usage Domains
A single-column usage domain is created for one column, and is used when you want to make a column usage definition consistent throughout your application. For example, you can create a single-column domain for email addresses, postal codes, or vehicle numbers.
Unless prefixed with multi-column or flexible, a "usage domain" or "domain" means a single-column usage domain for the purposes of this document.
Multi-column Usage Domains
A multi-column usage domain creates column usage definitions for multiple columns under a single domain. A multi-column usage domain is ideal when you have logical entities spanning across two or more table columns. For example, you can use a multi-column usage domain to represent an address.
Flexible Usage Domains
A flexible usage domain is a domain that dynamically selects from a set of single-column or multi-column usage domains based on a discriminant column's values. A flexible domain assigns a specific domain (also known as a constituent domain) to a set of value columns based on a mapping expression composed from one or more discriminant columns.
In addition to these usage domain types, you can also use built-in usage domains directly on table columns. Some examples are email_d, ssn_d, and credit_card_number_d.
See Also:
-
Oracle Database Concepts for more information about types of Application Usage Domains.
10.1.3 Privileges Required for Usage Domains
To work with usage domains, you require the following privileges:
Note:
The Database Administrator (DBA) role includes all the following privileges.
DDL Privilege | Action |
---|---|
CREATE DOMAIN |
You can create a domain in your own schema. The RESOURCE and DB_DEVELOPER_ROLE roles include the CREATE DOMAIN privilege. |
CREATE ANY DOMAIN |
You can create a domain in any schema. |
ALTER ANY DOMAIN |
You can alter a domain in any schema. |
DROP ANY DOMAIN |
You can drop a domain in any schema. |
EXECUTE ANY DOMAIN |
You can reference or use a domain in any schema. To explicitly grant execute privileges to a user on a domain in any schema, use the following code:
|
10.1.4 Using a Single-column Usage Domain
This section explains how you can create, associate, alter, disassociate, and drop a single-column usage domain (hereinafter "usage domain" or "domain").
10.1.4.1 Creating a Usage Domain
You can define a usage domain that encapsulates a set of optional properties and constraints to represent common values, such as email addresses and credit card numbers.
The following are some examples of creating usage domains, where a domain is based on the properties of a table column, such as default value, constraints, annotations, or display and order expressions.
Example 10-1 Creating a Usage Domain for Hourly Wages
A Human Resource Application (HRA) creates many tables for different companies. Most companies have a column that stores hourly wages. The HRA can create a usage domain for the hourly wages columns as follows:
CREATE DOMAIN HourlyWages AS NUMBER
DEFAULT ON NULL 15
CONSTRAINT MinimalWage CHECK (HourlyWages > = 7 AND HourlyWages <=1000) ENABLE
DISPLAY TO_CHAR(HourlyWages, '$999.99') ORDER ( -1*HourlyWages )
ANNOTATIONS (properties '{"Purpose": "Wages", "Applicability": "USA", "Industry": {"Sales", "Manufacturing"} }');
Example 10-2 Creating a Usage Domain for Surrogate Keys
If you want to annotate surrogate key columns in your database application and maintain standard meta-data for such columns, create a domain similar to the following:
CREATE DOMAIN surrogate_id AS INTEGER
STRICT
NOT NULL
ANNOTATIONS ( primary_key, mandatory, operations '["insert", "delete"]' );
Example 10-3 Creating a Usage Domain for Birth Dates
The following is a usage domain that ensures that all columns with birth dates are "date only" and displays the age in years.
CREATE DOMAIN birth_date AS DATE
CONSTRAINT birth_date_only_c check ( birth_date = trunc ( birth_date ) )
DISPLAY FLOOR ( months_between ( sysdate, birth_date ) / 12 ) || ' years'
ANNOTATIONS ( sensitive 'PII Data', operations '["insert", "update"]' );
Example 10-4 Creating a Usage Domain for Default Date and Time Values
You can create a usage domain for date and time values to ensure that the inserts are in a standard format.
CREATE DOMAIN insert_timestamp AS
TIMESTAMP WITH LOCAL TIME ZONE
DEFAULT ON NULL systimestamp;
Example 10-5 Creating a Usage Domain for Positive Heights
The following usage domain ensures that people have positive heights and the heights are sorted in a descending order.
CREATE DOMAIN height AS NUMBER
CONSTRAINT positive_height_c CHECK ( value > 0 )
ORDER value * -1
ANNOTATIONS ( operations '["insert", "update"]' );
Example 10-6 Creating a Usage Domain for Positive Weights
The following usage domain ensures that people have positive weights.
CREATE DOMAIN weight AS NUMBER
CONSTRAINT positive_weight_c CHECK ( value > 0 )
ANNOTATIONS ( operations '["insert", "update"]' );
Example 10-7 Defining a Domain with Multiple Check Constraints
You can define a usage domain for email addresses, similar to the one in
the following example, which also has multiple CHECK
constraints.
CREATE SEQUENCE IF NOT EXISTS email_seq;
CREATE DOMAIN email AS VARCHAR2(100)
DEFAULT ON NULL email_seq.NEXTVAL || '@domain.com'
CONSTRAINT email_c CHECK (REGEXP_LIKE (email, '^(\S+)\@(\S+)\.(\S+)$'))
CONSTRAINT email_max_len_c CHECK (LENGTH(email) <=100) DEFERRABLE INITIALLY DEFERRED
DISPLAY '---' || SUBSTR(email, INSTR(email, '@') + 1);
Any column of VARCHAR2(L [BYTE|CHAR])
data type that
satisfies both constraints can be associated with the domain. The INITIALLY
DEFERRED
clause delays validation of the constraint
email_max_len_c
values until commit time.
Example 10-8 JSON Schema Validation
A domain can also be used for reusable JSON schema validation, as in the following example.
CREATE DOMAIN department_json_doc AS JSON
CONSTRAINT CHECK (
department_json_doc IS JSON VALIDATE USING '{
"type": "object",
"properties": {
"departmentName": { "type": "string" },
"employees": { "type": "array" }
},
"required" : [ "departmentName", "employees" ],
"additionalProperties": false
}' );
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information on creating a usage domain: CREATE DOMAIN
10.1.4.2 Associating Usage Domains with Columns at Table Creation
After defining a usage domain, you can associate the domain with new table columns when creating a table or associate it with existing columns in an existing table. Associating a usage domain with a column explicitly applies the domain's optional properties and constraints to the column.
You can use the CREATE TABLE
DDL to associate a usage domain
with a newly created column. The following examples show how you can associate a usage
domain with columns in a new table. These examples use the usage domains created in the
earlier examples.
Example 10-9 Associating
HourlyWages
Usage Domain at Table Creation
Using the HourlyWages
domain, the HRA can create
multiple tables where wage columns have the same domain characteristics.
CREATE TABLE employee (
name VARCHAR2(100),
id NUMBER,
wage NUMBER DOMAIN HourlyWages);
CREATE TABLE wage (
name VARCHAR2(100),
id NUMBER,
wage NUMBER DOMAIN HourlyWages,
gross_pay NUMBER,
deductions NUMBER,
net_pay NUMBER);
Example 10-10 Associating the surrogate_id
Usage Domain at Table
Creation
When you associate a strict usage domain such as
surrogate_id
with columns, ensure that the associated columns
have the same data type as the domain. A strict domain also requires that the column
length, scale, and precision match with the domain.
The following code fails with ORA-11517: the column data type
does not match the domain column
because you are trying to link a
NUMBER
data type column with a
INTEGER/NUMBER(*,0)
data type domain.
CREATE TABLE orders (
order_id NUMBER DOMAIN surrogate_id,
customer_id NUMBER,
order_datetime TIMESTAMP WITH LOCAL TIME ZONE
DEFAULT SYSTIMESTAMP);
To ensure that the association works, you can use the
NUMBER(*,0)
column data type to associate with the
surrogate_id
usage domain (INTEGER ==
NUMBER(*,0)
).
CREATE TABLE orders (
order_id NUMBER(*,0) DOMAIN surrogate_id,
customer_id NUMBER,
order_datetime TIMESTAMP WITH LOCAL TIME ZONE
DEFAULT SYSTIMESTAMP);
Example 10-11 Associating the
surrogate_id
, birth_date
,
height
, and weight
Usage Domains at Table
Creation
The DOMAIN
keyword is optional. You can see in the
following example that the birth_date
domain is associated with
date_of_birth
column without the DOMAIN
keyword. The example also shows that you can define a more precise data type for the
columns with regards to the precision and scale than what is in the domain. The
height_in_cm
and weight_in_kg
columns have
their associated domain data type as NUMBER
whereas the column data
type has precision and scale values, such as NUMBER(4,1)
.
CREATE TABLE people (
person_id DOMAIN surrogate_id
GENERATED BY DEFAULT AS IDENTITY
PRIMARY KEY,
full_name VARCHAR2(256),
date_of_birth birth_date,
height_in_cm NUMBER(4, 1) DOMAIN height,
weight_in_kg NUMBER(6, 3) DOMAIN weight);
Example 10-12 Associating the department_json_doc
Usage Domain at Table
Creation
CREATE TABLE departments (
department_id INTEGER PRIMARY KEY,
department_doc JSON DOMAIN department_json_doc);
Guidelines
-
When associating a domain with a column, you can specify the domain name in addition to the column's data type, in which case the column's data type is used, provided that the domain data type is compatible with the column's data type.
-
When associating a domain with a column, you can specify a domain name instead of the column's data type, in which case the domain data type is used for the column, wherein the
DOMAIN
keyword is optional. -
If a domain is defined as
STRICT
, the domain's data type, scale, and precision must match the column's data type, scale, and precision. -
If a domain is not defined as
STRICT
, you can associate a domain of any length with a column of any length. For instance, you can associate a domain ofVARCHAR2(10)
with anyVARCHAR2
column.
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information about creating a usage domain: CREATE DOMAIN
-
Specifying a Data Type for a Domain for information about column and domain data types
10.1.4.2.1 Using DML on Columns Associated with Usage Domains
The following are some examples of DML statements that you can use on the newly created table columns with associated usage domains.
Example 10-13 Using DML Statements on the
people
table
The following INSERT
commands insert data into the
people
table columns, while verifying that the check constraint
specified in the associated domain is not violated.
INSERT INTO people
VALUES ( 1, 'Sally Squirell', date'1981-01-01', 180.1, 61 );
INSERT INTO people
VALUES ( 2, 'Brian Badger', date'2016-12-31', 120.4, 27.181 );
The following INSERT
command fails because
height
is specified as a negative number, and hence the
associated check constraint is violated.
INSERT INTO people
VALUES ( 3, 'Fergal Fox', date'2023-04-12', -99, 1 );
The output is:
ORA-11534: check constraint (HR.SYS_C009232) due to domain constraint HR.POSITIVE_HEIGHT_C of domain HR.HEIGHT violated
You can use the associated domains to display data with the heights sorted in a descending order and also view the corresponding age and weight.
SELECT full_name, DOMAIN_DISPLAY ( date_of_birth ) age,
height_in_cm, weight_in_kg
FROM people
ORDER BY DOMAIN_ORDER ( height_in_cm );
See Also:
SQL Functions for Usage Domains for details about domain functions, such as
DOMAIN_DISPLAY
and DOMAIN_ORDER
.
The output is:
FULL_NAME AGE HEIGHT_IN_CM WEIGHT_IN_KG
-------------------- ---------- ------------ ------------
Sally Squirell 42 years 180.1 61
Brian Badger 6 years 120.4 27.181
You can describe the people
table to see the data type
definition and the referenced domain information.
DESC people;
The output is:
Name Null? Type
---------------------- -------- ----------------------------------------
PERSON_ID NOT NULL NUMBER(38) HR.SURROGATE_ID
FULL_NAME VARCHAR2(256)
DATE_OF_BIRTH DATE HR.BIRTH_DATE
HEIGHT_IN_CM NUMBER(4,1) HR.HEIGHT
WEIGHT_IN_KG NUMBER(6,3) HR.WEIGHT
The following SELECT
command enables you to view the
column annotations that are inherited from the associated domains.
SELECT column_name, annotation_name, annotation_value
FROM user_annotations_usage
WHERE object_name = 'PEOPLE';
The output is:
COLUMN_NAME ANNOTATION_NAME ANNOTATION_VALUE
-------------------- -------------------- --------------------
PERSON_ID PRIMARY_KEY <null>
PERSON_ID MANDATORY <null>
PERSON_ID OPERATIONS ["insert", "delete"]
DATE_OF_BIRTH OPERATIONS ["insert", "update"]
DATE_OF_BIRTH SENSITIVE PII Data
HEIGHT_IN_CM OPERATIONS ["insert", "update"]
WEIGHT_IN_KG OPERATIONS ["insert", "update"]
Example 10-14 Using DML Statements on the departments
table with JSON
data
The following INSERT
command on the
departments
table succeeds because it includes all the JSON
attributes in the department_json_doc
domain.
INSERT INTO departments
VALUES ( 1, '{
"departmentName" : "Accounting",
"employees" : [
{"empName":"William"},
{"empName":"Shelley"}
]
}');
The following INSERT
command fails with ORA-40875: JSON
schema validation error - missing employees attribute
because the
employees
attribute is missing.
INSERT INTO departments
VALUES ( 2, '{
"departmentName" : "Finance"
}');
The following INSERT
command fails with
ORA-40875: JSON schema validation error - extra manager
attribute
because the manager
attribute is not found
in the associated department_json_doc
usage domain.
INSERT INTO departments
VALUES ( 3, '{
"departmentName" : "Executive",
"employees" : [
{"empName":"Lex"},
{"empName":"Neena"}
],
"manager" : {"empName":"Lex"}
}');
10.1.4.3 Associating Usage Domains with Existing or New Columns
You can use the ALTER TABLE
DDL with the MODIFY
or
ADD
clause to associate a usage domain with an existing or a newly
added column.
Example 10-15 Associating a Usage Domain with a Newly Created Column
For a newly created customers
table:
CREATE TABLE customers (
cust_id NUMBER,
cust_email VARCHAR2(100));
You can use ADD
to add a new column:
cust_new_email
and associate it with the email
domain.
ALTER TABLE customers
ADD (cust_new_email VARCHAR2(100) DOMAIN email);
Example 10-16 Associating the email Usage Domain with an Existing Column
You can use MODIFY
to modify an existing column:
cust_email
and associate it with the email
domain.
ALTER TABLE customers
MODIFY (cust_email VARCHAR2(100) DOMAIN email);
You can also add a usage domain to a column using the ALTER TABLE
... MODIFY
statement. In the following example, the
orders
table column, namely order_datetime
and
the insert_timestamp
domain have different defaults. The
insert_timestamp
domain has the DEFAULT
with
ON NULL
clause, which is missing in the
order_datetime
column. Therefore, when you try to associate the
domain with the column, you get an error ORA-11501: The column default does
not match the domain default of the column
.
ALTER TABLE orders
MODIFY order_datetime DOMAIN insert_timestamp;
To overcome the default mismatch, specify a column default clause that matches the domain default.
ALTER TABLE orders
MODIFY order_datetime DOMAIN insert_timestamp
DEFAULT ON NULL systimestamp;
Example 10-17 Querying to View Associated Domains
SELECT constraint_name, search_condition_vc, domain_constraint_name
FROM user_constraints
JOIN user_cons_columns
USING ( constraint_name, table_name )
WHERE table_name = 'PEOPLE'
AND constraint_type = 'C'
AND column_name = 'WEIGHT_IN_KG';
The output is:
CONSTRAINT_NAME SEARCH_CONDITION_VC DOMAIN_CONSTRAINT_NAME
-------------------- ------------------------------ --------------------------
SYS_C008493 "WEIGHT_IN_KG">0 POSITIVE_WEIGHT_C
Guidelines
-
The
DOMAIN
keyword is optional for theALTER TABLE .. ADD
statement if a domain only is specified for the newly added column. -
The
DOMAIN
keyword is mandatory for theALTER TABLE .. MODIFY
statement. -
The column data type should be compatible with the domain data type.
-
If a domain has default expression or collation, it should match the associated column's default expression and collation.
-
If the associated column already has a domain associated with it, an error is returned.
10.1.4.4 Altering a Usage Domain
You can alter a usage domain for its display expression, order expression, and
annotation. The following ALTER DOMAIN
DDL statements are
supported.
Example 10-18 Removing the Order Expression from a Domain
The height
usage domain definition has
the order expression as VALUE
, so to remove the order expression,
you must drop the order expression.
ALTER DOMAIN height DROP
ORDER;
Example 10-19 Adding a Display Expression to a Usage Domain
To add a display expression to the height
usage domain,
use the following ALTER
command.
ALTER DOMAIN height
ADD DISPLAY round ( value ) || ' cm';
Example 10-20 Changing the Display Expression of
the birth_date
Domain
To change the display expression of the birth_date
domain to years
and months, use the following ALTER
command.
ALTER DOMAIN birth_date
MODIFY DISPLAY
FLOOR ( months_between ( sysdate, birth_date ) / 12 ) || ' years ' ||
MOD ( FLOOR ( months_between ( sysdate, birth_date ) ), 12 ) || ' months';
Example 10-21 Querying the
people
table for the Altered birth_date
,
height
, and weight
Domains
COLUMN age FORMAT A20
SELECT full_name, DOMAIN_DISPLAY ( date_of_birth ) age,
DOMAIN_DISPLAY ( height_in_cm ) height_in_cm, weight_in_kg
FROM people
ORDER BY DOMAIN_ORDER ( height_in_cm );
See Also:
SQL Functions for Usage Domains for details about domain functions, such as
DOMAIN_DISPLAY
and DOMAIN_ORDER
.
The output is:
FULL_NAME AGE HEIGHT_IN_CM WEIGHT_IN_KG
-------------------- -------------------- ------------- ------------
Sally Squirell 42 years 5 months 180 cm 61
Brian Badger 6 years 5 months 120 cm 27.181
Example 10-22 Changing the Annotations on a Usage Domain
The following code adds the annotations for the height
usage domain.
ALTER DOMAIN height
ANNOTATIONS (
operations '["insert", "update", "sort"]',
sensitive 'Private data');
Example 10-23 Querying the Dictionary Views for the Annotation Changes
COLUMN annotation_value FORMAT A40
SELECT column_name, annotation_name, annotation_value
FROM user_annotations_usage
WHERE object_name = 'PEOPLE';
The output is:
COLUMN_NAME ANNOTATION_NAME ANNOTATION_VALUE
-------------------- -------------------- ----------------------------------------
PERSON_ID PRIMARY_KEY <null>
PERSON_ID MANDATORY <null>
PERSON_ID OPERATIONS ["insert", "delete"]
DATE_OF_BIRTH SENSITIVE PII Data
DATE_OF_BIRTH OPERATIONS ["insert", "update"]
HEIGHT_IN_CM OPERATIONS ["insert", "update"]
HEIGHT_IN_CM OPERATIONS ["insert", "update", "sort"]
HEIGHT_IN_CM SENSITIVE Private data
WEIGHT_IN_KG OPERATIONS ["insert", "update"]
Guidelines
-
You can alter the display expression of a domain only if the domain is not constituent in a flexible domain.
-
You can alter the order expression of a domain only if the domain is not constituent in a flexible domain.
-
You can alter only domain-level annotations.
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information about altering a usage domain: ALTER DOMAIN.
-
Viewing Domain Information for the usage domain dictionary views
10.1.4.5 Disassociating a Usage Domain from a Column
You can use the ALTER TABLE
DDL with the
DROP
clause to disassociate a usage domain from a column.
Example 10-24 Disassociating a Usage Domain from a Column
To drop the associated domain from the cust_email
column
of the customers
table:
ALTER TABLE customers MODIFY ( cust_email ) DROP DOMAIN;
To drop the domain but keep the domain's constraint:
ALTER TABLE customers MODIFY ( cust_email ) DROP DOMAIN PRESERVE CONSTRAINTS;
Example 10-25 Disassociating a Usage Domain from a Column
The following code removes the domain association of the
height
domain from the height_in_cm
column in
the people
table, while preserving the constraint.
ALTER TABLE people
MODIFY ( height_in_cm ) DROP DOMAIN PRESERVE CONSTRAINTS;
Example 10-26 Querying the Columns with Disassociated Usage Domain
The SELECT
query on the user_constraints
dictionary
table reveals the changes.
SELECT constraint_name, search_condition_vc, domain_constraint_name
FROM user_constraints
JOIN user_cons_columns
USING ( constraint_name, table_name )
WHERE table_name = 'PEOPLE'
AND constraint_type = 'C';
The output is:
CONSTRAINT_NAME SEARCH_CONDITION_VC DOMAIN_CONSTRAINT_NAME
-------------------- ---------------------------------------- ------------------------------
SYS_C009491 "DATE_OF_BIRTH"=TRUNC("DATE_OF_BIRTH") BIRTH_DATE_ONLY_C
SYS_C009494 "WEIGHT_IN_KG">0 POSITIVE_WEIGHT_C
SYS_C009489 "PERSON_ID" IS NOT NULL <null>
SYS_C009490 "HEIGHT_IN_CM">0 <null>
Example 10-27 Re-adding the Removed height
Domain
The following code re-adds the removed height
domain to
the height_in_cm
column in the people
table.
ALTER TABLE people
MODIFY ( height_in_cm ) ADD DOMAIN height;
Example 10-28 Querying the Re-added Domain
A duplicate height_in_cm > 0
constraint is created
with the re-added height
domain.
SELECT constraint_name, search_condition_vc, domain_constraint_name
FROM user_constraints
JOIN user_cons_columns
USING ( constraint_name, table_name )
WHERE table_name = 'PEOPLE'
AND constraint_type = 'C'
ORDER BY search_condition_vc;
The output is:
CONSTRAINT_NAME SEARCH_CONDITION_VC DOMAIN_CONSTRAINT_NAME
-------------------- ---------------------------------------- ------------------------------
SYS_C009491 "DATE_OF_BIRTH"=TRUNC("DATE_OF_BIRTH") BIRTH_DATE_ONLY_C
SYS_C009495 "HEIGHT_IN_CM">0 POSITIVE_HEIGHT_C
SYS_C009490 "HEIGHT_IN_CM">0 <null>
SYS_C009489 "PERSON_ID" IS NOT NULL <null>
SYS_C009494 "WEIGHT_IN_KG">0 POSITIVE_WEIGHT_C
Guidelines
On dropping the domain for a column, the following are preserved by default:
-
The domain's collation.
-
The non-domain constraint that is added to the column.
The domain's default value is not preserved. It is only kept if the default is explicitly applied to the column.
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information about altering a usage domain: ALTER DOMAIN.
-
Viewing Domain Information for the usage domain dictionary views
10.1.4.6 Dropping a Usage Domain
You can drop a usage domain. See Oracle Database SQL Language Reference for more information about dropping a domain.
Example 10-29 Dropping a Usage Domain
The following customers
table has one of its column
associated with the email
domain:
CREATE TABLE customers ( cust_id NUMBER, cust_email VARCHAR2(100) DOMAIN email);
The following DROP
command returns an error because the
customers
table has the cust_email
column
associated with email
domain.
DROP DOMAIN email;
The following DROP
command succeeds:
DROP DOMAIN email FORCE;
The cust_email
column is disassociated from the
email
domain and all statements mentioning the
email
domain are invalidated.
Example 10-30 Dropping a Domain but Preserving the Constraint
The following DROP
command succeeds but preserves the
default and constraint expressions.
DROP DOMAIN email FORCE PRESERVE;
The cust_email
column retains the default ON
NULL email_seq.NEXTVAL || '@domain.com'
and preserves the constraint
after replacing the domain name in the constraint with the column name:
CONSTRAINT email_c CHECK (REGEXP_LIKE (cust_email,
'^(\S+)\@(\S+)\.(\S+)$'))
.
Guidelines
-
To drop a domain that is referenced in a flexible domain, use
DROP DOMAIN
with theFORCE
option. -
If the domain is not associated with any table column and the domain is not constituent in a flexible domain, the domain is dropped. If the usage domain is in use, the
DROP
statement fails. -
If the domain is associated with any table column, you must use the
FORCE
option to drop the domain. Using theFORCE
option also:-
Removes the default expression, if only domain default is set.
-
Preserves the column default expression, if both domain and column defaults are set.
-
Removes the domain annotation from all associated columns.
-
Preserves the collation of any domain associated columns.
-
Invalidates all SQL dependent statements in the cursor cache.
-
Preserves the constraints on any domain associated columns, if
FORCE PRESERVE
is used.
-
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information about dropping a usage domain: DROP DOMAIN.
10.1.4.6.1 About Drop Domain and Recycle Bin
The dropped tables are placed in the recycle bin. To drop a domain
associated with tables in the recycle bin, you must use the FORCE
option with the DROP
command.
You can restore the dropped tables that are in the recycle bin to the
before-the-drop position using the FLASHBACK TABLE
command. If a table
is restored to the before-the-drop position (using FLASHBACK TABLE TO BEFORE
DROP
) after the associated domain has been dropped, then the table has the
same default, collation, nullability, and constraints as was there before the drop,
except that none of these attributes would be marked as being inherited from the
domain.
Example 10-31 Dropping a Usage Domain Associated with a Dropped Table
The following DROP
command tries to remove the
weight
domain that is associated with the
weight_in_kg
column of the people
table.
DROP DOMAIN weight;
The command returns the following error output:
ORA-11502: The domain WEIGHT to be dropped has dependent objects.
If you drop the people
table, and then drop the weight
domain, it returns an error because the table is still in the recycle bin.
DROP TABLE people;
DROP DOMAIN weight;
The command returns the following error output:
ORA-11502: The domain WEIGHT to be dropped has dependent objects.
Removing the people
table from the recycle bin
permanently, and then running the DROP
command on the
weight
domain, drops the weight
domain.
PURGE TABLE people;
DROP DOMAIN weight;
Guidelines
Here are some points to note when dropping domains that are associated with dropped tables (tables in recycle bin):
-
While a table is in the recycle bin, the
ALTER
command on the table is not allowed. -
If a table with a domain association is in the recycle bin, the associated domain cannot be dropped and the
DROP DOMAIN
command fails. -
When the
DROP DOMAIN FORCE
andDROP DOMAIN FORCE PRESERVE
commands are used, the tables in the recycle bin are disassociated from the domain. The database uses theFORCE PRESERVE
semantics for tables in the recycle bin, even if you only specifyFORCE
. -
If you want to drop the domain that is associated with a table in the recycle bin, you can use the
PURGE TABLE
command to remove a table from the recycle bin and run theDROP DOMAIN
command to drop the domain.
10.1.5 Using a Multi-column Usage Domain
This section explains how you can create, associate, alter, disassociate, and drop a multi-column usage domain.
10.1.5.1 Creating a Multi-column Usage Domain
You can use a multi-column usage domain to group logical entities that span across table columns, such as addresses.
Example 10-32 Creating a Multi-column Usage Domain for Addresses
You can create a multi-column usage domain called "US_city" with three columns for address entries, as follows:
CREATE DOMAIN US_city AS (
name AS VARCHAR2(30) ANNOTATIONS (Address),
state AS VARCHAR2(2) ANNOTATIONS (Address),
zip AS NUMBER ANNOTATIONS (Address)
)
CONSTRAINT City_CK CHECK(state in ('CA','AZ','TX') and zip < 100000)
DISPLAY name||', '|| state ||', '||TO_CHAR(zip)
ORDER state||', '||TO_CHAR(zip)||', '||name
ANNOTATIONS (Title 'Domain Annotation');
Example 10-33 Creating a Multi-column Usage Domain for Currency
The following code creates a multi-column usage domain called
currency
that displays monetary values as an amount in a given
currency, and the currency codes. The display is sorted by value (low to high), and
then by the currency code.
CREATE DOMAIN currency AS (
amount AS NUMBER,
iso_currency_code AS CHAR(3 CHAR)
)
DISPLAY iso_currency_code || TO_CHAR ( amount, '999,999,990.00' )
ORDER TO_CHAR ( amount, '999,999,990.00' ) || iso_currency_code;
Guidelines
-
You can have the same data types for the individual columns in a multi-column usage domain as a single-column usage domain.
-
For a multi-column usage domain, a column must not overlap between different domains. For example, on a table T(TC1, TC2, TC3, TC4), domains D1(C1, C2) and D2(C1, C2) cannot be associated as D1(TC1, TC2) and D2(TC2, TC3).
-
Multiple ordered subsets of columns in the same table can be associated with the same domain. For example, domain D1 can be associated as D1(TC1, TC2) and D1(TC3, TC4).
-
Unlike tables that can have at most one
LONG
column, domains can have multiple columns ofLONG
data type. Such domains would be useful for evaluating check conditions involving multipleLONG
columns using theDOMAIN_CHECK
operator.
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information on creating a usage domain: CREATE DOMAIN
10.1.5.2 Associating a Multi-column Usage Domain at Table Creation
You can use the CREATE TABLE
DDL statement to associate a
multi-column usage domain with a newly created column.
Example 10-34 Associating the US_city
Domain with Multiple Columns
You can create a customer
table and associate the
US_city
domain with the table's three columns.
CREATE TABLE customer( cust_id NUMBER, cust_name VARCHAR2(30), city_name VARCHAR2(30), state VARCHAR2(2), zip NUMBER, DOMAIN US_city(city_name, state, zip));
The following example returns an error because CITY
and
STATE
columns are overlapped between domains.
CREATE TABLE customer( cust_id NUMBER, cust_name VARCHAR2(30), city_name VARCHAR2(30), state VARCHAR2(2), zip NUMBER, DOMAIN US_city(city_name, state, zip), DOMAIN US_city(cust_name, state, zip));
The following example also returns an error because the
CITY_NAME
column is repeated.
CREATE TABLE customer( cust_id NUMBER, cust_name VARCHAR2(30), city_name VARCHAR2(30), state VARCHAR2(2), zip NUMBER, DOMAIN US_city(city_name, city_name, zip));
Example 10-35 Associating the
currency
Domain with Multiple Columns
You can create an order_items
table with its
total_paid
and currency_code
columns
associated with the currency
domain.
CREATE TABLE order_items (
order_id INTEGER, product_id INTEGER,
total_paid NUMBER(10, 2), currency_code char (3 CHAR ),
DOMAIN currency ( total_paid, currency_code ));
Guidelines
-
The column names that are passed as the actual parameters to the domain must be unique.
-
Domain columns can be associated with table columns with a different name.
-
The
DOMAIN
keyword is mandatory.
10.1.5.2.1 Using DML on Columns Associated with Multi-column Domains
The following are some examples of DML statements that you can use on the newly created table columns with associated multi-column usage domains.
Example 10-36 Using DML Commands on the Associated Columns
Inserting values and querying the table display the results based on the
currency
domain display and order expressions.
INSERT INTO order_items
VALUES (1, 1, 9.99, 'USD'),
(2, 2, 8.99, 'GBP'),
(3, 3, 8.99, 'EUR'),
(4, 4, 1399, 'JPY'),
(5, 5, 825, 'INR');
SELECT order_id, product_id,
DOMAIN_DISPLAY ( total_paid, currency_code ) amount_paid
FROM order_items
ORDER BY DOMAIN_ORDER ( total_paid, currency_code );
See Also:
SQL Functions for Usage Domains for details about domain functions, such as
DOMAIN_DISPLAY
and DOMAIN_ORDER
.
The output is:
ORDER_ID PRODUCT_ID AMOUNT_PAID
---------- ---------- ------------------
3 3 EUR 8.99
2 2 GBP 8.99
1 1 USD 9.99
5 5 INR 825.00
4 4 JPY 1,399.00
10.1.5.3 Associating a Multi-column Usage Domain with Existing Columns
You can use the ALTER TABLE
DDL statement with the
MODIFY
or ADD
clause to associate a
multi-column usage domain with an existing column or a newly added column in an
existing table.
Example 10-37 Associating a Multi-column Usage Domain with Existing Columns
The following example applies the US_city
domain to the
three columns of the customer
table.
ALTER TABLE customer MODIFY (city_name, state, zip) ADD DOMAIN US_city;
Note:
The DOMAIN
keyword is mandatory for the
ALTER TABLE .. MODIFY
statement.
10.1.5.4 Altering a Multi-column Usage Domain
You can alter a multi-column usage domain just as you can alter a single-column usage
domain. In a multi-column usage domain, you can change the DISPLAY
and
ORDER
properties. For multi-column domains, altering annotations at
the column-level is currently not supported but you can alter the object-level
annotations.
Example 10-38 Altering Display and Order Expressions for a Multi-column Usage Domain
The following ALTER
statement changes the display expression of the
currency
domain. The current display expression shows the
currency code and then the currency value. The altered display expression shows the
currency value and then the currency code.
ALTER DOMAIN currency
MODIFY DISPLAY TO_CHAR ( amount, '999,990.00' ) || '-' || iso_currency_code;
The following ALTER
statement changes the order expression of the
currency
domain. The current order expression sorts by the
currency value and then by the currency code. The altered order expression sorts by
the currency code and then by the currency value.
ALTER DOMAIN currency
MODIFY ORDER iso_currency_code || TO_CHAR ( amount, '999,990.00' );
Example 10-39 Querying the Table Associated with the Altered Multi-column Domain
SELECT order_id, product_id,
DOMAIN_DISPLAY ( total_paid, currency_code ) amount_paid
FROM order_items
ORDER BY DOMAIN_ORDER ( total_paid, currency_code );
The output is:
ORDER_ID PRODUCT_ID AMOUNT_PAID
----------- ------------- ---------------
3 3 8.99-EUR
2 2 8.99-GBP
5 5 825.00-INR
4 4 1,399.00-JPY
1 1 9.99-USD
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information about altering a usage domain: ALTER DOMAIN.
10.1.5.5 Disassociating a Multi-column Usage Domain from a Column
You can use the ALTER TABLE
DDL statement with the
DROP
clause to disassociate a multi-column usage domain from a
column.
Example 10-40 Examples of Disassociating a Multi-column Usage Domain
The following ALTER TABLE
command drops the
US_City
domain from the city_name
,
state
and zip
columns of the
customer
table.
ALTER TABLE customer
MODIFY(city_name, state, zip) DROP DOMAIN;
If a table T with columns (c1, c2, c3) is associated with domain D and another set of columns (c4, c5, c6) is also associated with the domain D, you can drop the domain for all the columns:
ALTER TABLE T
MODIFY (c1, c2, c6, c5, c4, c3) DROP DOMAIN;
You cannot drop only a subset of the columns that are associated with a multi-column domain. For example, for table T, dropping only c1 and c2 columns, returns an error:
ALTER TABLE T
MODIFY (c1, c2) DROP DOMAIN;
Example 10-41 More Examples of Disassociating a Multi-column Usage Domain
The following code removes the currency
domain from the
total_paid
and currency_code
columns of the
order_items
table.
ALTER TABLE order_items
MODIFY ( total_paid, currency_code ) DROP DOMAIN;
Guidelines
-
There can be multiple ordered subsets of columns in the same table that are associated with the same domain. The removing multi-column domain syntax must specify the list of associated columns to be dissociated.
-
Domain name cannot be specified.
-
You cannot specify other options for
ALTER TABLE ..MODIFY
withALTER TABLE ..DROP DOMAIN
.
10.1.5.6 Dropping a Multi-column Usage Domain
To drop a multi-column usage domain, use the same syntax as used for a single-column usage domain.
Guidelines
-
To drop a domain that is referenced in a flexible domain, use
DROP DOMAIN
with theFORCE
option.
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information about dropping a usage domain: DROP DOMAIN
-
Dropping a Usage Domain for more information about dropping a usage domain.
10.1.6 Using a Flexible Usage Domain
This section explains how you can create, associate, disassociate, and drop a flexible usage domain.
Note:
You cannot alter a flexible usage domain but as an alternative, you can
disassociate the flexible domain from the tables, DROP
the domain,
recreate the domain, and re-associate it with the tables.
10.1.6.1 Creating a Flexible Usage Domain
You can create a flexible usage domain that references other non-flexible domains (single and multi-column usage domains) and enables you to apply one of them to table columns depending on the context of the data. For example, you can create multi-column domains to validate address formats for each country. Table columns can only belong to one domain. So, to enable the database to use the address domain corresponding to each country for each row, create a flexible domain over the country domains. Associate columns with the flexible domain using the country as the discriminant column. Each row can then apply the address rules for the corresponding country domain.
Example 10-42 Creating a Flexible Usage Domain for Temperature Readings
The following code creates a flexible usage domain called
temperature
from three domains, namely
celcius
, fahrenheit
, and kelvin
.
The domains that are created for each temperature scale have appropriate absolute
zero checks and display expressions. There is no ELSE
clause in the
flexible domain, so you can insert values for other temperature units, and
temperature values for such temperature units are unconstrained.
CREATE DOMAIN celcius AS NUMBER
CONSTRAINT abs_zero_c_c CHECK ( celcius >= -273.15 )
DISPLAY celcius || ' °C';
CREATE DOMAIN fahrenheit AS NUMBER
CONSTRAINT abs_zero_f_c CHECK ( fahrenheit >= -459.67 )
DISPLAY fahrenheit || ' °F';
CREATE DOMAIN kelvin AS NUMBER
CONSTRAINT abs_zero_k_c CHECK ( kelvin >= 0 )
DISPLAY kelvin || ' K';
The following code creates a flexible domain that selects which domain to use based on the temperature units.
CREATE FLEXIBLE DOMAIN temperature (
temp
) CHOOSE DOMAIN USING ( units char(1) )
FROM (
CASE units
WHEN 'C' THEN celcius ( temp )
WHEN 'F' THEN fahrenheit ( temp )
WHEN 'K' THEN kelvin ( temp )
END);
Example 10-43 Creating a Flexible Usage Domain for Addresses
The following code creates multi-column usage domains to represent United States and United Kingdom (British) addresses, and a default address domain for other countries.
/* US addresses */
CREATE DOMAIN us_address AS (
line_1 AS VARCHAR2(255 CHAR) NOT NULL,
town AS VARCHAR2(255 CHAR) NOT NULL,
state AS VARCHAR2(255 CHAR) NOT NULL,
zipcode AS VARCHAR2(10 CHAR) NOT NULL
) CONSTRAINT us_address_c check (
REGEXP_LIKE ( zipcode, '^[0-9]{5}(-[0-9]{4}){0,1}$' ));
/* British addresses */
CREATE DOMAIN gb_address AS (
street AS VARCHAR2(255 CHAR) NOT NULL,
locality AS VARCHAR2(255 CHAR),
town AS VARCHAR2(255 CHAR) NOT NULL,
postcode AS VARCHAR2(10 CHAR) NOT NULL
) CONSTRAINT gb_postcode_c check (
REGEXP_LIKE (
postcode, '^[A-Z]{1,2}[0-9][A-Z]{0,1} [0-9][A-Z]{2}$' ));
/* Default address */
CREATE DOMAIN global_address AS (
line_1 AS VARCHAR2(255) NOT NULL,
line_2 AS VARCHAR2(255),
line_3 AS VARCHAR2(255),
line_4 AS VARCHAR2(255),
postcode AS VARCHAR2(10));
The following code creates a flexible domain that selects which multi-column address domain to use based on the country code.
CREATE FLEXIBLE DOMAIN address (
line_1, line_2, line_3, line_4,
postal_code
)
CHOOSE DOMAIN USING ( country_code VARCHAR2(2 char) )
FROM (
CASE country_code
WHEN 'GB' THEN gb_address ( line_1, line_2, line_3, postal_code )
WHEN 'US' THEN us_address ( line_1, line_2, line_3, postal_code )
ELSE global_address ( line_1, line_2, line_3, line_4, postal_code )
END);
Note:
To create a flexible domain, you must have the EXECUTE
privilege
on each constituent domain.
See Also:
Oracle Database SQL Language Reference for the syntactic and semantic information about creating a usage domain: CREATE DOMAIN
10.1.6.2 Associating a Flexible Usage Domain at Table Creation
You can use the CREATE TABLE
DDL to associate a flexible
usage domain with a set of columns that are newly created by the new table. To add a
flexible domain to a set of columns, specify the list of columns to be associated with
the domain (in the domain column order), followed with the list of columns to be used as
the discriminant (in discriminant column order in the flexible domain).
Example 10-44 Associating the
temperature
Flexible Domain with New Table Columns
Create a sensor_readings
table using the
temperature
flexible domain, while specifying the discriminant
column with the USING
keyword.
CREATE TABLE sensor_readings (
sensor_id integer, reading_timestamp TIMESTAMP,
temperature_reading NUMBER,
temperature_units CHAR(1 CHAR),
DOMAIN temperature ( temperature_reading )
USING ( temperature_units ));
Example 10-45 Associating the address
Flexible Domain with New Table
Columns
The following code creates a new table called addresses
and associates its columns with the address
flexible domain.
CREATE TABLE addresses (
line_1 VARCHAR2(255) NOT NULL,
line_2 VARCHAR2(255),
line_3 VARCHAR2(255),
line_4 VARCHAR2(255),
country_code VARCHAR2(2 CHAR) NOT NULL,
postal_code VARCHAR2(10 CHAR),
DOMAIN address (
line_1, line_2, line_3, line_4, postal_code)
USING ( country_code ));
Note:
The DOMAIN
and USING
keywords are
mandatory when associating flexible domains.
10.1.6.2.1 Using DML on Columns Associated with Flexible Domains
The following are some examples of DML statements on the newly created table columns that have associated flexible usage domains.
Example 10-46 Using DML Commands on Columns
Associated with the temperature
Flexible Domain
INSERT INTO sensor_readings
VALUES ( 1, timestamp'2023-06-08 12:00:00', 21.1, 'C' ),
( 1, timestamp'2023-06-08 12:05:00', 21.2, 'C' ),
( 1, timestamp'2023-06-08 12:10:00', 20.9, 'C' ),
( 2, timestamp'2023-06-08 12:00:00', 68.5, 'F' ),
( 2, timestamp'2023-06-08 12:05:00', 68.1, 'F' ),
( 2, timestamp'2023-06-08 12:10:00', 68.9, 'F' ),
( 3, timestamp'2023-06-08 12:00:00', 290.23, 'K' ),
( 3, timestamp'2023-06-08 12:05:00', 289.96, 'K' ),
( 3, timestamp'2023-06-08 12:10:00', 289.65, 'K' ),
( 4, timestamp'2023-06-08 12:00:00', 528.15, 'R' ),
( 4, timestamp'2023-06-08 12:05:00', 528.42, 'R' ),
( 4, timestamp'2023-06-08 12:10:00', 527.99, 'R' );
SELECT sensor_id, reading_timestamp,
DOMAIN_DISPLAY ( temperature_reading, temperature_units ) temp
FROM sensor_readings;
See Also:
SQL Functions for Usage Domains for details about domain functions, such as
DOMAIN_DISPLAY
and DOMAIN_ORDER
.
The output is:
SENSOR_ID READING_TIMESTAMP TEMP
---------- ------------------------------ -------------------------------------------
1 08-JUN-2023 12.00.00.000000000 21.1 °C
1 08-JUN-2023 12.05.00.000000000 21.2 °C
1 08-JUN-2023 12.10.00.000000000 20.9 °C
2 08-JUN-2023 12.00.00.000000000 68.5 °F
2 08-JUN-2023 12.05.00.000000000 68.1 °F
2 08-JUN-2023 12.10.00.000000000 68.9 °F
3 08-JUN-2023 12.00.00.000000000 290.23 K
3 08-JUN-2023 12.05.00.000000000 289.96 K
3 08-JUN-2023 12.10.00.000000000 289.65 K
4 08-JUN-2023 12.00.00.000000000 <null>
4 08-JUN-2023 12.05.00.000000000 <null>
4 08-JUN-2023 12.10.00.000000000 <null>
Example 10-47 Out-of-bounds Constraint Errors
The following values are out-of-bounds constraint errors for their respective temperature scales.
INSERT INTO sensor_readings
VALUES ( 1, timestamp'2023-06-08 12:15:00', -400, 'C' );
INSERT INTO sensor_readings
VALUES ( 2, timestamp'2023-06-08 12:15:00', -999, 'F' );
INSERT INTO sensor_readings
VALUES ( 3, timestamp'2023-06-08 12:15:00', -1, 'K' );
Example 10-48 Using DML on Columns Associated
with the address
Flexible Domain
-- Great Britian
INSERT INTO addresses ( line_1, line_3, country_code, postal_code )
VALUES ( '10 Big street', 'London', 'GB', 'N1 2LA' );
-- United States
INSERT INTO addresses ( line_1, line_2, line_3, country_code, postal_code )
VALUES ( '10 another road', 'Las Vegas', 'NV', 'US', '87654-3210' );
-- Tuvalu
INSERT INTO addresses ( line_1, country_code )
VALUES ( '10 Main street', 'TV' );
SELECT * FROM addresses;
The output is:
LINE_1 LINE_2 LINE_3 LINE_4 COUNTRY_CODE POSTAL_CODE
------------------ ------------ --------- --------- --------------- -----------
10 Big street <null> London <null> GB N1 2LA
10 another road Las Vegas NV <null> US 87654-3210
10 Main street <null> <null> <null> TV <null>
The following INSERT
command returns an error because
it tries to insert UK address with US zip code.
INSERT INTO addresses ( line_1, line_3, country_code, postal_code )
VALUES ( '10 Big street', 'London', 'GB', '12345-6789' );
ORA-11534: check constraint (schema.SYS_C0010286) due to domain constraint schema.SYS_DOMAIN_C00639 of domain schema.ADDRESS violated
The following INSERT
command returns an error because it
tries to insert US address without values for the state.
INSERT INTO addresses ( line_1, line_2, country_code, postal_code )
VALUES ( '10 another road', 'Las Vegas', 'US', '87654-3210' );
ORA-11534: check constraint (schema.SYS_C0010289) due to domain constraint schema.SYS_DOMAIN_C00636 of domain schema.ADDRESS violated
10.1.6.3 Associating a Flexible Domain with Existing Columns
You can use the ALTER TABLE
DDL with the
MODIFY
or ADD
clauses to associate a flexible
usage domain with an existing column or a newly added column in an existing table.
Example 10-49
The following code creates a new table called
temp_sensor_readings
.
CREATE TABLE temp_sensor_readings (
sensor_id integer, reading_timestamp TIMESTAMP,
temperature_reading NUMBER,
temperature_units CHAR(1 CHAR));
The following code associates the temperature
flexible
domain with an existing column called temperature_reading
.
ALTER TABLE temp_sensor_readings
MODIFY (temperature_reading, temperature_units)
ADD DOMAIN temperature;
Guidelines
-
The
DOMAIN
keyword is mandatory when associating flexible domains. -
The
USING
keyword is mandatory forALTER TABLE .. ADD
statement. -
You cannot have the same column associated with multiple flexible domains, whether as a domain column or as a discriminant column.
-
You cannot have the column associated with the same domain, but with a different column positioning.
10.1.6.4 Disassociating a Flexible Usage Domain from Columns
You can use the ALTER TABLE
DDL with the
DROP
clause to disassociate a flexible usage domain from a
column.
Example 10-50
The following code drops the temperature
domain from
the temp_sensor_readings
table.
ALTER TABLE temp_sensor_readings
MODIFY (temperature_reading, temperature_units) DROP DOMAIN;
Guidelines
-
The domain name is not required because the database knows which columns are associated with which domains and one column can only be associated with one domain.
-
You cannot specify other options for
ALTER TABLE ..MODIFY
withALTER TABLE ..DROP DOMAIN
.
10.1.6.5 Dropping a Flexible Usage Domain
To drop a flexible usage domain, use the same syntax as used for a single-column usage domain.
Guidelines
-
To drop a domain that is referenced in a flexible domain, use
DROP DOMAIN
with theFORCE
option. Doing this also drops the flexible domain. -
To drop a flexible domain in the
FORCE
mode, you must have privileges to drop the constituent flexible domains.
See Also:
-
Oracle Database SQL Language Reference for the syntactic and semantic information about dropping a usage domain: DROP DOMAIN.
-
Dropping a Usage Domain for more information about dropping a usage domain.
10.1.7 Specifying a Data Type for a Domain
A domain data type can be one of Oracle data types. However, a qualified domain name must not collide with the qualified user-defined data types, or with Oracle built-in types.
If a column is associated with a domain, and the column data type is not specified, then the domain data type is used for the associated column as the default data type. If the associated column already has a data type, the column's data type is used.
If the domain data type is defined as non-STRICT
, the
associated column's data type only needs to be compatible with the domain data type,
meaning that their data type must be the same, but the length, precision, and scale can
be different. For instance, for a non-strict domain, you can associate a domain of
VARCHAR2(10)
with any VARCHAR2
column.
If the domain data type is defined as STRICT
, the associated
column's data type must be compatible with the domain data type and also match the
length, precision, and scale of the domain data type.
Example 10-51 Associating Columns with Domain Data Type
The following example creates a year_of_birth
domain
and a email_dom
domain and associates the domains with columns to
show the compatibility of domain and column data types.
DROP DOMAIN IF EXISTS year_of_birth;
CREATE DOMAIN year_of_birth AS NUMBER(4)
CONSTRAINT CHECK ( (TRUNC(year_of_birth) = year_of_birth) AND (year_of_birth >= 1900) );
DROP DOMAIN IF EXISTS email_dom;
CREATE DOMAIN email_dom AS VARCHAR2(100)
CONSTRAINT email_chk check (REGEXP_LIKE (email_dom, '^(\S+)\@(\S+)\.(\S+)$'));
DROP TABLE IF EXISTS newcustomers PURGE;
CREATE TABLE newcustomers (
cust_Id NUMBER,
cust_year_of_birth NUMBER(6) DOMAIN year_of_birth,
cust_hq_email VARCHAR2(50),
cust_office_email VARCHAR2(100),
cust_rep_email VARCHAR2(100));
DESC newcustomers;
The output is:
Name Null? Type
----------------------------- -------- ----------------------------
CUST_ID NUMBER
CUST_YEAR_OF_BIRTH NUMBER(6) SH.YEAR_OF_BIRTH
CUST_HQ_EMAIL VARCHAR2(50)
CUST_OFFICE_EMAIL VARCHAR2(100)
CUST_REP_EMAIL VARCHAR2(200)
The cust_year_of_birth
column is defined as an Oracle
data type: Number
, and also associated with the
year_of_birth
domain, so the column's data type is assigned to
the column. The cust_year_of_birth
column inherits all the
properties defined in the year_of_birth
domain, such as constraint,
display, and ordering properties.
The following example creates a ukcustomers
table with a
column associated with the year_of_birth
domain, but without the
column's data type:
CREATE TABLE ukcustomers (
cust_Id NUMBER,
cust_year_of_birth DOMAIN year_of_birth);
DESC ukcustomers;
The output is:
Name Null? Type
------------------------------ -------- ----------------------------
CUST_ID NUMBER
CUST_YEAR_OF_BIRTH NUMBER(4) SH.YEAR_OF_BIRTH
Here, the cust_year_of_birth
column is assigned the
domain's data type, which is NUMBER(4)
.
In the following example, the DOMAIN
keyword is
omitted.
CREATE TABLE incustomers (
cust_id NUMBER,
cust_year_of_birth year_of_birth);
DESC incustomers;
The output is:
Name Null? Type
----------------------------- -------- ----------------------------
CUST_ID NUMBER
CUST_YEAR_OF_BIRTH NUMBER(4) SH.YEAR_OF_BIRTH
In the column definition clause, the domain clause must either replace the data type clause, or immediately follow it.
If a domain column data type is not defined as STRICT
,
you can associate a domain to any column with the same data type, irrespective of
the column length.
The following ALTER
commands succeed because the domain
and column data type has the same data type and the column lengths are not checked
for non-STRICT
domains.
ALTER TABLE newcustomers
MODIFY cust_hq_email DOMAIN email_dom;
ALTER TABLE newcustomers
MODIFY cust_office_email DOMAIN email_dom;
ALTER TABLE newcustomers
MODIFY cust_rep_email DOMAIN email_dom;
If a domain column data type is defined as STRICT
, the
domain association works only when the column and the domain have the same data type
and their lengths also match.
DROP DOMAIN IF EXISTS email_dom;
CREATE DOMAIN email_dom AS VARCHAR2(100) STRICT
CONSTRAINT email_chk check (REGEXP_LIKE (email_dom, '^(\S+)\@(\S+)\.(\S+)$'));
The following ALTER
command succeeds.
ALTER TABLE newcustomers
MODIFY cust_office_email DOMAIN email_dom;
The following ALTER
commands fail because the column length and the
domain length do not match.
ALTER TABLE newcustomers
MODIFY cust_hq_email DOMAIN email_dom;
ALTER TABLE newcustomers
MODIFY cust_rep_email DOMAIN email_dom;
Table Column Data Type to non-STRICT
Domain Column Data Type
Compatibility
STRICT
domains.
-
NUMBER
,NUMER(p)
,NUMBER(p, s)
,NUMERIC
,NUMERIC(p)
,NUMERIC(p, s)
,DECIMAL
,DECIMAL(p)
,DEC
,DEC(p)
,INTEGER
,INT
,SMALLINT
,FLOAT
,FLOAT(p)
,REAL
,DOUBLE_PRECISION
-
CHAR(L)
,CHAR(L CHAR)
,CHAR(L BYTE)
,CHARACTER(L CHAR)
,CHARACTER(L BYTE)
,CHARACTER(L)
-
NCHAR(L)
,NATIONAL CHARACTER(L)
,NATIONAL CHAR (L)
-
VARCHAR2(L)
,VARCHAR2(L CHAR)
,VARCHAR2(L BYTE),
CHAR VARYING(L CHAR)
,CHAR VARYING(L BYTE)
,CHAR VARYING(L),
CHARACTER VARYING(L CHAR)
,CHARACTER VARYING(L BYTE)
,CHARACTER VARYING(L)
-
NVARCHAR2(L)
,NATIONAL CHAR VARYING (L)
,NATIONAL CHARACTER VARYING (L)
-
TIMESTAMP
,TIMESTAMP(p)
-
TIMESTAMP WITH TIME ZONE
,TIMESTAMP(p) WITH TIME ZONE
-
TIMESTAMP WITH LOCAL TIME ZONE
,TIMESTAMP(p) WITH LOCAL TIME ZONE
-
INTERVAL YEAR TO MONTH
,INTERVAL YEAR(p) TO MONTH
-
INTERVAL DAY TO SECOND
,INTERVAL DAY(p) TO SECOND
,INTERVAL DAY TO SECOND(s)
,INTERVAL DAY(p) TO SECOND(s)
-
ROWID
,UROWID
,UROWID(p)
-
RAW(p)
,RAW(p)
Table Column Data Type to STRICT
Domain Column Data Type
Compatibility
Each of the following points lists the compatible types. You can
associate any table column with a domain column that has a compatible type. The
table and domain columns must have an exact match for length, precision, and scale
for STRICT
domains.
-
NUMBER(*)
,NUMBER
-
NUMBER(p, 0)
,NUMERIC(p)
,NUMERIC(p, 0)
,DECIMAL(p)
,DEC(p)
, provided the table column data type and the domain column data type have the same precision. -
NUMBER(p, s)
,NUMERIC(p, s)
,DECIMAL(p, s)
,DEC(p, s)
, provided the table column data type and the domain column data type have the same precision and scale. -
NUMBER(*,0)
,NUMERIC(*)
,NUMERIC(*,0)
,DEC(*)
,DEC(*,0)
,DECIMAL(*)
,DECIMAL(*,0)
,INTEGER
,INT
,SMALLINT
-
FLOAT(63)
,REAL
-
FLOAT
,FLOAT(126)
,DOUBLE PRECISION
-
CHAR(L CHAR)
,CHAR(L BYTE)
,CHARACTER (L)
, provided the size in bytes is the same for the column data type and domain column data type. For example,CHAR (4 BYTE)
can be associated with aSTRICT
domain column ofCHAR(1 CHAR)
if 1 character takes 4 bytes. -
NCHAR(L)
,NATIONAL CHARACTER(L)
,NATIONAL CHAR (L)
, provided the size in bytes is the same for the column data type and domain column data type. -
VARCHAR2(L CHAR)
,VARCHAR2(L BYTE)
,CHARACTER VARYING (L)
,CHAR VARYING(L)
, provided the size in bytes is the same for the column data type and domain column data type. -
NVARCHAR2(L)
,NATIONAL CHAR VARYING (L)
,NATIONAL CHARACTER VARYING (L)
, provided the size in bytes is the same for the column data type and domain column data type. -
TIMESTAMP
,TIMESTAMP(6)
-
TIMESTAMP WITH TIME ZONE
,TIMESTAMP(6) WITH TIME ZONE
-
TIMESTAMP WITH LOCAL TIME ZONE
,TIMESTAMP(6) WITH LOCAL TIME ZONE
-
INTERVAL YEAR TO MONTH
,INTERVAL YEAR(2) TO MONTH
-
INTERVAL DAY TO SECOND
,INTERVAL DAY(2) TO SECOND
,INTERVAL DAY TO SECOND(6)
,INTERVAL DAY(2) TO SECOND(6)
-
ROWID
,UROWID(10)
-
UROWID
,UROWID(4000)
,ROWID(4000)
Table Column Data Type to Domain Column Data Type Compatibility
The following column data types are only compatible with an equivalent
domain column data type. For example, a DATE
column type can be
associated only with a DATE
domain column type.
-
BINARY_FLOAT
-
BINARY_DOUBLE
-
DATE
-
BLOB
-
CLOB
-
NCLOB
-
BFILE
-
LONG
-
LONG RAW
-
JSON
Rules of Associating Table Column and Usage Domain Based on Data Type
For a domain's data type of VARCHAR2(L [CHAR|BYTE])
,
let L-bytes be the maximum length in bytes corresponding to L, given that the
National Language Support (NLS) setting has the session-level length semantics value
in NLS_LENGTH_SEMANTICS
as BYTE
.
The following rules apply when you associate a column with the domain:
-
If the domain is defined as non-
STRICT
, the domain can be associated with columns of data typeVARCHAR2(x)
for any x-bytes. For non-STRICT
domains, L and x can be different. -
If the domain is defined as
STRICT
, the domain can be associated with columns of data typeVARCHAR2(x)
for any x-bytes = L-bytes. ForSTRICT
domains, L and x must be the same number of bytes, even after converting L|xCHAR
toBYTES
, if needed.
For instance, if a domain data type specification is VARCHAR2
STRICT
, and if MAX_STRING_SIZE
is
STANDARD
, then the domain can associate with columns of
VARCHAR2(L BYTE)
data type, where L = 4000. If the current NLS
settings in the session are such that at most 2 bytes are needed to represent a
character, then a column of VARCHAR2(2000 CHAR)
data type can be
associated with the domain. If MAX_STRING_SEMANTICS
is changed to
EXTENDED
, then columns of data type: VARCHAR2(L
BYTE)
for L = 32767 or VARCHAR2(16383 CHAR)
can be
associated with the domain.
Similar rules apply to NVARCHAR2(L)
, CHAR(L
[CHAR|BYTE])
, and NCHAR(L)
.
10.1.8 Changing the Usage Domain Properties
As your application evolves, column definitions may need to change, and with that the properties of the associated usage domains must also change. At the time of altering a domain, you can only alter the annotations, display expression, and order expression for domains. The following suggests ways to change the other domain properties.
You can use these examples as a means to get started, or to build
upon and adapt them to your specific data and business requirements. The
first example is a manual method and the next one is an online method using
the dbms_redefinition
package.
Example 10-52 Changing the Domain Properties Manually
Suppose that you want to change the string length of an email domain field from 100 to 200. To make that change, you must complete the following steps:
-
Alter the associated column's string length to 200.
-
Drop the current domain associated with the column.
-
Create a new domain with the email string length as 200.
-
Re-associate columns associated with the current domain with the new domain.
If the current domain definition and column association are as follows:
CREATE DOMAIN email_dom AS VARCHAR2(100) CONSTRAINT email_chk CHECK (regexp_like (email_dom, '^(\S+)\@(\S+)\.(\S+)$')); CREATE TABLE t1 ( id NUMBER, email DOMAIN email_dom );
To view the list of columns associated with the domain:
SELECT table_name, column_name FROM user_tab_columns WHERE domain_name = 'EMAIL_DOM'; TABLE_NAME COLUMN_NAME ---------------------- ------------------- T1 EMAIL
Alter the t1 table to change the email column with string size as 200:
ALTER TABLE t1 modify email varchar2(200);
Drop the domain with the FORCE PRESERVE
option:
DROP DOMAIN email_dom FORCE PRESERVE;
Then, create a new domain with the email string size as 200:
CREATE DOMAIN email_dom AS VARCHAR2(200) CONSTRAINT email_chk CHECK (regexp_like (email_dom, '^(\S+)\@(\S+)\.(\S+)$'));
And, re-associate the new domain with the email column:
ALTER TABLE t1 MODIFY email DOMAIN email_dom;
Example 10-53 Changing the Domain
Properties Using the online dbms_redefinition
Package
You can use the Oracle online table reorganization package
called dbms_redefinition
to change permitted
values, such as updating which currencies are supported. For
instance, to change the supported currencies in a currency domain,
the required steps are:
-
Create a new domain.
-
Migrate columns associated with the current domain to use the new domain.
The following example has only basic error handling. There can be instances where an error can occur after several tables are migrated, such as when some data violates the new constraint. A complete solution would need to account for these scenarios.
The following code creates a domain with a constraint that allows the following currencies: USD, GBP, and EUR.
CREATE DOMAIN currency AS (
amount AS NUMBER,
iso_currency_code AS CHAR ( 3 CHAR )
) CONSTRAINT supported_currencies_c
CHECK ( iso_currency_code in ( 'USD', 'GBP', 'EUR' ) );
Suppose that the following tables have columns associated
with the currency
domain.
CREATE TABLE order_items (
order_id INTEGER, product_id INTEGER,
total_paid NUMBER(10, 2), currency_code CHAR ( 3 CHAR ),
DOMAIN currency ( total_paid, currency_code ),
PRIMARY KEY ( order_id, product_id )
);
CREATE TABLE product_prices (
product_id INTEGER,
unit_price NUMBER(10, 2),
currency_code CHAR( 3 char ),
DOMAIN currency ( unit_price, currency_code ),
PRIMARY KEY ( product_id, currency_code )
);
Use the INSERT
command to store some values
into the product_prices
and
order_items
tables.
INSERT INTO product_prices
VALUES (1, 9.99, 'USD'),
(1, 8.99, 'GBP'),
(1, 8.99, 'EUR');
INSERT INTO order_items
VALUES (1, 1, 9.99, 'USD'),
(2, 1, 8.99, 'GBP'),
(3, 1, 8.99, 'EUR');
COMMIT;
Suppose that your business is expanding and you want to support more currencies. You cannot modify the constraints directly, so you need an alternative approach that includes:
-
Creating a new domain.
-
Altering the
product_prices
andorder_items
tables to drop the existing domain from the associated columns while preserving the constraints. -
Altering the tables to add the new domain.
-
Removing the preserved constraints from the tables.
However, when done online, these are blocking DDL
statements. Instead, you can use the
dbms_redefinition
package to modify the
constraints online.
You must create a new domain with the constraint including the newly supported currencies, and associate it with temporary tables. The new domain replaces the original domain.
CREATE DOMAIN currency_d as (
amount AS NUMBER,
iso_currency_code AS CHAR ( 3 CHAR )
) CONSTRAINT supported_currencies_d_c
CHECK ( iso_currency_code in ( 'USD', 'GBP', 'EUR', 'CAD', 'MXP', 'INR', 'JPY' ) );
CREATE TABLE order_items_tmp (
order_id INTEGER, product_id INTEGER,
total_paid NUMBER(10, 2), currency_code CHAR ( 3 CHAR ),
DOMAIN currency_d ( total_paid, currency_code ) ,
PRIMARY KEY ( order_id, product_id )
);
CREATE TABLE product_prices_tmp (
product_id INTEGER,
unit_price NUMBER(10, 2),
currency_code CHAR (3 CHAR),
DOMAIN currency_d ( unit_price, currency_code ),
PRIMARY KEY ( product_id, currency_code )
);
To make the code more reusable, you can create a
redefine_table
procedure that calls the
dbms_redefinition
procedures to copy the
properties of the temporary table columns to the current table
columns, and then swap the current table columns to the new
domain.
DECLARE
PROCEDURE redefine_table ( current_table VARCHAR2, staging_table VARCHAR2 ) AS
num_errors pls_integer;
BEGIN
DBMS_REDEFINITION.CAN_REDEF_TABLE(user, current_table);
DBMS_REDEFINITION.START_REDEF_TABLE(user, current_table, staging_table);
DBMS_REDEFINITION.copy_table_dependents(
uname => user,
orig_table => current_table,
int_table => staging_table,
copy_constraints => false,
num_errors => num_errors);
IF num_errors > 0 THEN
dbms_redefinition.abort_redef_table(user, current_table, staging_table);
raise_application_error ( -20001, num_errors || ' errors copying dependents from ' || current_table || ' to ' || staging_table );
ELSE
dbms_redefinition.finish_redef_table(user, current_table, staging_table);
END IF;
END redefine_table;
BEGIN
FOR tabs IN (
SELECT distinct table_name from user_tab_cols
WHERE domain_name = 'CURRENCY'
) LOOP
redefine_table(tabs.table_name, tabs.table_name || '_TMP');
END LOOP;
END;
/
Use DML on the product_prices
table to see
if the new currencies are now supported.
-- New currencies now supported
INSERT INTO product_prices
VALUES (1, 9.99, 'CAD');
-- Invalid currencies raise exception
INSERT INTO product_prices
VALUES (1, 9.99, 'N/A');
SELECT * FROM product_prices;
The output is:
PRODUCT_ID UNIT_PRICE CUR
---------- ---------- ---
1 9.99 USD
1 8.99 GBP
1 8.99 EUR
1 9.99 CAD
Clean up the temporary objects and old domain:
currency
.
DROP TABLE order_items_tmp PURGE;
DROP TABLE product_prices_tmp PURGE;
DROP DOMAIN currency;
See Also:
DBMS_REDEFINITION in PL/SQL Packages and Types Reference Guide.
10.1.9 SQL Functions for Usage Domains
Domain functions enable you to work with usage domains more efficiently.
You can use the following SQL functions with usage domains:
-
DOMAIN_DISPLAY
returns the domain display expression for the domain that the argument is associated with. -
DOMAIN_NAME
returns the qualified domain name of the domain that the argument is associated with. Note that if there is a public synonym to the domain, it is returned; otherwise domain name is returned indomain_owner.domain_name
format. -
DOMAIN_ORDER
returns the domains order expression for the domain that the argument is associated with. -
DOMAIN_CHECK(domain_name, value1, value2, ...)
applies constraint conditions ofdomain_name
(not null or check constraint) to thevalue
expression. It also checks the values for type compatibility. There can be many values; the number of value expressions must match the number of columns in the domain or the statement raises an error. -
DOMAIN_CHECK_TYPE(domain_name, value1, value2, ...)
verifies whether the input expressions are compatible with the domain's data type. There can be many values; the number of value expressions must match the number of columns in the domain or the statement raises an error.
See Also:
Domain Functions in Oracle Database SQL Language Reference for more information about using SQL functions for usage domains
10.1.10 Viewing Domain Information
You can use the dictionary views to get information about the domains. Dictionary views can also help identify columns that have different properties, such as constraint and default expressions when compared to their associated domain.
10.1.10.1 Dictionary Views for Usage Domains
Dictionary views: [USER|DBA|ALL]_DOMAINS
and
[USER|DBA|ALL]_DOMAIN_COLS
represent domains and provide the
following information about the domain columns. For flexible domains, the views also
include the domain selector expression.
-
Domain name
-
Domain owner
-
Display and ordering expression
-
Default value
-
Data type of the domain
-
Collation
The following dictionary views are available for usage domains:
-
ALL_DOMAINS
describes the domains accessible to the current user. -
DBA_DOMAINS
describes all domains in the database. -
USER_DOMAINS
describes the domains owned by the current user. -
ALL_DOMAIN_COLS
describes columns of the domains accessible to the current user. -
DBA_DOMAIN_COLS
describes columns of all domains in the database. -
USER_DOMAIN_COLS
describes columns of the domains owned by the current user. -
ALL_DOMAIN_CONSTRAINTS
describes constraint definitions in the domains accessible to the current user. -
DBA_DOMAIN_CONSTRAINTS
describes constraint definitions in all domains in the database. -
USER_DOMAIN_CONSTRAINTS
describes constraint definitions in the domains owned by the current user.
See Also:
Oracle Database Reference for more information about the following views that are used for usage domains: ALL_DOMAINS, DBA_DOMAINS, USER_DOMAINS, ALL_DOMAIN_COLS, DBA_DOMAIN_COLS, USER_DOMAIN_COLS, ALL_DOMAIN_CONSTRAINTS, DBA_DOMAIN_CONSTRAINTS, USER_DOMAIN_CONSTRAINTS
10.1.11 Built-in Usage Domains
Oracle Database provides some built-in usage domains that you can use directly on table columns, for example, email_d, ssn_d, and credit_card_number_d. Built-in usage domains exist in all PDBs. When a new PDB is added into a CDB, the built-in usage domains automatically get created and added in the PDB.
The following is a list of all built-in usage domains that are supported in Oracle Database:
Table 10-1 Built-in Domains
Name | Allowed Values | Description |
---|---|---|
email_d |
^([a-zA-Z0-9!#$%&*+=?^_`{|}~-]+(\.[ A-Za-z0-9!#$%&*+=?^_`{|}~-]+)*)@(([ a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9] )?\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-z A-Z0-9])?)$ |
Email address Implementation: Regex |
day_short_d |
'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN' |
Day of the week in short format Domain Order: based on Implementation: List |
day_d |
'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY' |
Day of the week in long format Domain Order: based on Implementation: List |
month_short_d |
'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC' |
Month in short format Implementation: List |
month_d |
'JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER' |
Month in long format Implementation: List |
year_d |
year > 0 and year <= 9999 |
Year (0-9999) Implementation: Check |
positive_number_d |
positive_number > 0 |
Positive Number : 1,2,3,4,... Implementation: Check |
negative_number_d |
negative_number < 0 |
Negative Number : ...,-3,-2,-1 Implementation: Check |
non_positive_number_d |
non_positive_number <= 0 |
Non-Positive Number: ...,-3,-2,-1,0 Implementation: Check |
non_negative_number_d |
non_negative_number >= 0 |
Non-Negative Number : 0,1,2,3... Implementation: Check |
mac_address_d |
^([a-fA-F0-9]{2}[-]){5}[a-fA-F0-9]{2}$ ^([a-fA-F0-9]{2}[:]){5}[a-fA-F0-9]{2}$ |
MAC address Implementation: regex |
ssn_d |
^[0-9]{3}[-][0-9]{2}[-][0-9]{4}$ |
US SSN Implementation: regex |
credit_card_number_d |
^([0-9]{4}[-]){3}[0-9]{4}$ ^([0-9]{4}[ ]){3}[0-9]{4}$ ^([0-9]{4}){3}[0-9]{4}$ ^[0-9]{4}[-][0-9]{6}[-][0-9]{5}$ ^[0-9]{4}[ ][0-9]{6}[ ][0-9]{5}$ ^[0-9]{15}$ |
Credit Card Number Implementation: regex |
ipv4_address_d |
^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ |
IPv4 Address Implementation: regex |
ipv6_address_d |
^([0-9a-fA-F]{4}[:]){7}[0-9a-fA-F]{4}$ ^([0-9a-fA-F]{4}[:]){6}(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ |
IPv6 Address Implementation: regex |
subnet_mask_d |
^(((255\.){3}(255|254|252|248|240|224|192|128|0))|((255\.){2}(255|254|252|248|240|224|192|128|0)\.0)| ((255\.)(255|254|252|248|240|224|192|128|0)(\.0+){2})|((255|254|252|248|240|224|192|128|0)(\.0){3}))$ |
Subnet Mask Implementation: regex |
sha1_d |
^[0-9a-fA-F]{40}$ |
SHA1 Implementation: regex |
sha256_d |
^[0-9a-fA-F]{64}$ |
SHA256 Implementation: regex |
sha512_d |
^[0-9a-fA-F]{128}$ |
SHA512 Implementation: regex |
cidr_d |
^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/([1-9]|[1-2][0-9]|3[0-2])$ |
CIDR Implementation: regex |
phone_number_d |
^[+]{0,1}[0-9]{1,16}$ |
Phone Number Implementation: regex |
mime_type_d |
'application/epub+zip', 'application/gzip', 'application/java-archive', 'application/json', 'application/ld+json', 'application/msword', 'application/msword', 'application/ogg', 'application/pdf', 'application/rtf', 'application/vnd.amazon.ebook', 'application/vnd.apple.installer+xml', 'application/vnd.ms-excel', 'application/vnd.ms-fontobject', 'application/vnd.ms-powerpoint', 'application/vnd.oasis.opendocument.presentation', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.text', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.rar', 'application/vnd.visio', 'application/x-abiword', 'application/x-bzip', 'application/x-bzip2', 'application/x-cdf', 'application/x-compressed', 'application/x-csh', 'application/x-freearc', 'application/x-httpd-php', 'application/x-sh', 'application/x-shockwave-flash', 'application/x-tar', 'application/x-zip-compressed', 'application/zip', 'audio/aac', 'audio/midi', 'audio/mpeg', 'audio/ogg', 'audio/opus', 'audio/wav', 'audio/webm', 'audio/x-midi', 'font/otf', 'font/ttf', 'image/avif', 'image/bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/svg+xml', 'image/tiff', 'image/vnd.microsoft.icon', 'text/calendar', 'text/css', 'text/csv', 'text/html', 'text/javascript', 'text/javascript', 'text/plain', 'video/mp2t', 'video/mp4', 'video/mpeg', 'video/ogg', 'video/webm', 'video/x-msvideo' |
MIME Types Implementation: list |
10.2 Application Usage Annotations
This section explains how you can use application usage annotations (hereinafter "annotations") for database objects.
For many applications, it is important to maintain additional property metadata for database objects such as tables, views, table columns, indexes, and domains. Annotations enable your applications to store and retrieve additional user-specific metadata about database objects and table columns. Applications can use such metadata to help render effective user interfaces and customize application logic.
10.2.1 Overview of Annotations
What are annotations and where can you use them?
Annotations are a lightweight declarative facility for developers to centrally register usage properties for database schema objects. Annotations are stored in dictionary tables and are available to any application looking to standardize behavior across common data in related applications. Annotations are not interpreted by the database in any way. They are custom data properties for database metadata - included for table columns, tables, and indexes, that applications can use as additional property metadata to render user interfaces or customize application logic.
Being a mechanism to define and store application metadata centrally in the
database, annotations enable you to share the metadata information across applications,
modules and microservices. You can add annotations to schema objects when you create new
objects (using the CREATE
statements) or modify existing objects (using
the ALTER
statements).
Annotating the data model with metadata provides additional data integrity, consistency and data model documentation benefits. Your applications can store user-defined metadata for database objects and table columns that other applications or users can retrieve and use. Storing the metadata along with the data guarantees consistency and universal accessibility to any user or application that uses the data.
An individual annotation has a name and an optional value. The name and the
optional value are freeform text fields. For example, you can have an annotation with a
name and value pair, such as Display_Label ‘Employee Salary’
, or you
can have a standalone annotation with only a name, such as UI_Hidden
,
which does not need a value because the name is self-explanatory.
The following are further details about annotations.
-
When an annotation name is specified for a schema object using the
CREATE
DDL statement, an annotation is automatically created. -
Annotations are additive, meaning that you can specify multiple annotations for the same schema object.
-
You can add multiple annotations at once to a schema object using a single DDL statement. Similarly, a single DDL statement can drop multiple annotations from a schema object.
-
An annotation is represented as a subordinate element to the database object to which the annotation is added. Annotations do not create a new object type inside the database.
-
You can add annotations to any schema object that supports annotations provided you own or have alter privileges on the schema object. You do not need to schema qualify the annotation name.
-
You can issue SQL queries on dictionary views to obtain all annotations, including their names and values, and their usage with schema objects.
10.2.2 Annotations and Comments
You can also annotate database objects such as tables and table columns using
the COMMENT
command. Comments that are associated with schema objects
are stored in data dictionaries along with the metadata of the objects.
Annotations are simpler to use and have a broader scope than comments. Following are the major differences between comments and annotations:
-
Comments are a commenting mechanism used to add metadata to only certain schema objects, such as tables and columns. Comments are not available for other schema objects, such as indexes, procedures, triggers, and domains.
-
Comments do not have a name, they have only a freeform value.
-
Comments are not additive meaning that you cannot add multiple comments for the same object. Specifying a new comment overwrites the prior comment for the corresponding table or column.
-
You need separate DDL statements for comments whereas you can combine multiple annotations into one DDL statement.
-
A separate set of dictionary views exists for different entities. For instance, there is a view for table comments and another view for column comments. Annotations, on the other hand, are unified across all object types, which makes them simpler to query and use.
See Also:
Comments for more information about using
COMMENTS
.
10.2.3 Supported Database Objects
Annotations are supported for the following database objects.
-
Tables and table columns
-
Views and view columns
-
Materialized views and materialized view columns
-
Indexes
-
Domains and multi-column domain columns
10.2.4 Privileges Required for Using Annotations
To add or drop annotations, you require the CREATE
or
ALTER
privilege on the schema object for which the annotation is
specified in the CREATE
or ALTER
DDL statements.
You cannot create or remove annotations explicitly. Annotations are automatically created when they are used for the first time. Since annotations are stored as subordinate elements within the database object on which they are defined, adding annotations does not create a new object type inside the database.
10.2.5 DDL Statements for Annotations
This section explains the annotation syntax and provides the DDL statements to define or alter annotations for tables, table columns, views, materialized views, indexes, and domains.
Topics:
10.2.5.1 Annotation Syntax
The following snippet illustrates the annotation syntax that is used in DDL statements to define annotations for tables, table columns, views, materialized views, indexes, and domains.
annotations ::= 'ANNOTATIONS' '(' annotations_list ')' annotations_list ::= ( 'ADD' ('IF NOT EXISTS' | 'OR REPLACE' )? | 'DROP' 'IF EXISTS'? | REPLACE)? annotation ( ',' ( 'ADD' ('IF NOT EXISTS' | 'OR REPLACE' )? | 'DROP' 'IF EXISTS'? | REPLACE)? annotation )* annotation ::= annotation_name annotation_value? annotation_name ::= identifier annotation_value ::= character_string_literal
<annotation_value
> is a character string literal that can hold up
to 4000 characters.
<annotation_name
> is an identifier and has the
following requirements:
-
An identifier can have up to 1024 characters.
-
If an identifier is a reserved word, you must provide the annotation name in double quotes.
-
An identifier with double quotes can contain white characters.
-
An identifier that contains only white characters is not allowed.
10.2.5.2 DDL Statements to Annotate a Table
You can use the following DDL statements to annotate a table when creating or altering the table.
Using the CREATE TABLE
Statement
The following are examples of the CREATE TABLE
statement
with annotations.
The following example adds an annotation: Operation
with a JSON value, and another annotation: Hidden
, which is
standalone and has no value.
CREATE TABLE Table1 ( T NUMBER) ANNOTATIONS(Operations '["Sort", "Group"]', Hidden);
Adding an annotation can be preceded by the ADD
keyword. The ADD
keyword is considered to be the default operation,
if nothing is specified.
The following example uses the optional ADD
keyword to
add the Hidden
annotation (which is also standalone) to
Table2
.
CREATE TABLE Table2 ( T NUMBER) ANNOTATIONS (ADD Hidden);
The ADD
keyword is an implicit operation when
annotations are defined, and can be omitted.
Using the ALTER TABLE
Statement
In the following example, the ALTER TABLE
command drops
all annotation values for the following annotation names:
Operations
and Hidden
.
ALTER TABLE Table1 ANNOTATIONS(DROP Operations, DROP Hidden);
The following example has the ALTER TABLE
command to
add JoinOperations
annotation with Join
value, and
to drop the annotation name: Hidden
. When dropping an annotation,
you need to only include the annotation name with the DROP
command.
ALTER TABLE Table1 ANNOTATIONS(ADD JoinOperations 'Join', DROP Hidden);
Multiple ADD
and DROP
keywords can be
specified in one DDL statement.
ALTER TABLE Table1 ANNOTATIONS(ADD JoinOperations 'Join Ops');
The output is:
ORA-11552: Annotation name 'JOINOPERATIONS' already exists.
REPLACE
keyword. The following statement
replaces the value of JoinOperations
with 'Join
Ops
':ALTER TABLE Table1 ANNOTATIONS(REPLACE JoinOperations 'Join Ops');
The output is
Table altered.
IF NOT EXISTS
clause. The following statement adds the
JoinOperations
annotation only if it does not exist. If the
annotation exists, the annotation value is unchanged and no error is
raised.ALTER TABLE Table1 ANNOTATIONS(ADD IF NOT EXISTS JoinOperations 'Join Ops');
ALTER TABLE Table1 ANNOTATIONS(DROP Title);
The output is:
ORA-11553: Annotation name 'TITLE' does not exist.
IF EXISTS
clause can be used, as
follows:ALTER TABLE Table1 ANNOTATIONS(DROP IF EXISTS Title);
The output is:
Table altered.
See Also:
CREATE TABLE and ALTER TABLE in SQL Language Reference for complete clause changes and definitions.
10.2.5.3 DDL Statements to Annotate a Table Column
You can use the following DDL statements to annotate a table column when creating or altering the table.
Using the CREATE TABLE
Statement
To add column-level annotations using a CREATE TABLE
statement, specify the annotations as a part of the
column_definition
clause. Annotations are specified at the end,
after inline constraints.
The following examples specify annotations for columns at table creation.
CREATE TABLE Table1 (T NUMBER ANNOTATIONS(Operations 'Sort', Hidden)); CREATE TABLE Table2 (T NUMBER ANNOTATIONS (Hidden));
The following example specifies table-level and column-level annotations for the
Employee
table.
CREATE TABLE Employee ( Id NUMBER(5) ANNOTATIONS(Identity, Display 'Employee ID', "Group" 'Emp_Info'), Ename VARCHAR2(50) ANNOTATIONS(Display 'Employee Name', "Group" 'Emp_Info'), Sal NUMBER ANNOTATIONS(Display 'Employee Salary', UI_Hidden) ) ANNOTATIONS (Display 'Employee Table');
The Employee
table in the previous example has
column-level and object-level annotations with Display
annotations
defined at the column level and object level. You can define a new annotation with
the same name as long as it corresponds to a different object, column pair. For
instance, you cannot define another annotation with the Display
name for the Employee
table but you can define a new annotation
"Group
" for the Sal
column. The annotation
"Group
" needs to be double quoted because it is a reserved
word.
Using the ALTER TABLE
Statement
To add column-level annotations using an ALTER TABLE
statement, specify the annotations as a part of the
modify_col_properties
clause. Annotations are specified at the
end, after inline constraints.
The following example adds a new Identity
annotation for the column
T of Table1
table.
ALTER TABLE Table1 MODIFY T ANNOTATIONS(Identity 'ID');
The following example adds a Label
annotation and drops the
Identity
annotation.
ALTER TABLE Table1 MODIFY T ANNOTATIONS(ADD Label, DROP Identity);
See Also:
CREATE TABLE and ALTER TABLE in SQL Language Reference for complete clause changes and definitions.
10.2.5.4 DDL Statements to Annotate Views and Materialized Views
You can use the following DDL statements to annotate a view and a materialized view.
Views and materialized views support annotations at the view level and column level. Column-level annotations are only supported for table views as a part of the column alias definition clause.
Using the CREATE
VIEW
Statement
The following example shows the view-level and column-level annotations:
CREATE OR REPLACE VIEW HighWageEmp ( Id ANNOTATIONS(Identity, Display 'Employee ID', "Group" 'Emp_Info'), Ename ANNOTATIONS (Display 'Employee Name', "Group" 'Emp_Info'), Sal ANNOTATIONS (Display 'Emp Salary') ) ANNOTATIONS (Title 'High Wage Employee View') AS SELECT * FROM EMPLOYEE WHERE Sal > 100000;
Using the CREATE
MATERIALIZED VIEW
Statement
The following example adds annotation at the view level in the
Materialized View
statement:
CREATE MATERIALIZED VIEW MView1 ANNOTATIONS (Title 'Tab1 MV1', ADD Snapshot) AS SELECT * FROM Table1;
The following example adds annotation at the view level and column level
in the Materialized View
statement:
CREATE MATERIALIZED VIEW MView1( T ANNOTATIONS (Hidden)) ANNOTATIONS (Title 'Tab1 MV1', ADD Snapshot) AS SELECT * FROM Table1;
Using the ALTER
VIEW
Statement
To provide support for annotations, the ALTER VIEW
statement has a new sub-clause added to it that allows altering annotations at the
view level. Other sub-clauses that are supported in the ALTER VIEW
statement are: modifying view constraints, enabling recompilation, and changing
EDITIONABLE
property.
Column-level annotations for views cannot be altered. Previously added column-level annotations can be dropped only by dropping the view and recreating a new one.
The following example is an ALTER VIEW
statement that
drops the Title
annotation and adds the Identity
annotation at the view level.
ALTER VIEW HighWageEmp ANNOTATIONS(DROP Title, ADD Identity);
Using the ALTER
MATERIALIZED VIEW
Statement
The ALTER MATERIALIZED VIEW
statement has a new
sub-clause that is added to alter annotations globally at the materialized view
level. Column-level annotations can be dropped only by dropping and recreating the
materialized view.
The following ALTER MATERIALIZED VIEW
statement drops
Snapshot
annotation from MView1
.
ALTER MATERIALIZED VIEW MView1 ANNOTATIONS(DROP Snapshot);
See Also:
CREATE VIEW, ALTER VIEW, CREATE MATERIALIZED VIEW, and ALTER MATERIALIZED VIEW in SQL Language Reference for complete clause changes and definitions.
10.2.5.5 DDL Statements to Annotate Indexes
You can use the following DDL statements to annotate an index.
Using the CREATE INDEX
Statement
The following are examples of creating index-level annotations.
CREATE TABLE DEPARTMENT( DEPT_ID NUMBER, UNIT NUMBER); CREATE INDEX I_DEPT_ID ON DEPARTMENT(DEPT_ID) ANNOTATIONS(Display 'Department Index'); CREATE UNIQUE INDEX UI_UNIT ON DEPARTMENT(UNIT) ANNOTATIONS(Display 'Department Unique Index');
Using the ALTER INDEX
Statement
The following is an example of altering an index-level annotation.
ALTER INDEX I_DEPT_ID ANNOTATIONS(DROP Display, ADD ColumnGroup 'Group1');
See Also:
CREATE INDEX and ALTER INDEX in SQL Language Reference for complete clause changes and definitions.
10.2.5.6 DDL Statements to Annotate Domains
You can use the following DDL statements to annotate a domain.
You can specify annotations for domains at the domain level or at the column level. Annotations defined on domains are inherited to objects that reference the domain. Annotations are allowed only for regular domains and not for flexible domains.
To specify domain-level annotations for single-column domains, the syntax with parentheses (used for multi-column domains) is required to distinguish between column-level and object-level annotations. Otherwise, the annotations for single column domains are considered column level.
Using the CREATE DOMAIN
Statement
The following example creates domain annotations by specifying column-level annotations for a single-column domain.
CREATE DOMAIN dept_codes_1 AS NUMBER(3) CONSTRAINT dept_chk_1 CHECK (dept_codes_1 > 99 AND dept_codes_1 != 200) ANNOTATIONS (Title 'Column level annotation');
The following examples specify a domain-level annotation for a single-column domain. This requires the use of the domains syntax for multi-column domains (with parentheses for columns).
CREATE DOMAIN dept_codes_2 AS ( code AS NUMBER(3) CONSTRAINT dept_chk_2 CHECK (code > 99 AND code != 200)) ANNOTATIONS (Title 'Domain Annotation');
CREATE DOMAIN HourlyWages AS Number(10) DEFAULT ON NULL 15 CONSTRAINT MinimalWage CHECK (HourlyWages > = 7 and HourlyWages <=1000) ENABLE DISPLAY TO_CHAR(HourlyWages, '$999.99') ORDER ( -1*HourlyWages ) ANNOTATIONS (Title 'Column level annotation');
The following example creates a multi-column domain with annotations at the column and domain levels.
CREATE DOMAIN US_City AS ( name AS VARCHAR2(50) ANNOTATIONS (Address), state AS VARCHAR2(50) ANNOTATIONS (Address), zip AS NUMBER ANNOTATIONS (Address) ) CONSTRAINT City_CK CHECK(state in ('CA','AZ','TX') and zip < 100000) DISPLAY name || ', ' || state || ' , ' || TO_CHAR(zip) ORDER state || ', ' || TO_CHAR(zip) || ', ' || name ANNOTATIONS (Title 'Domain Annotation');
Using the ALTER DOMAIN
Statement
Object-level annotations can be modified with ALTER
statements. Column-level annotations for domains cannot be altered. Previously added
column-level annotations can be dropped only by dropping the domain and recreating a
new one.
The following example alters domain-level annotation for the
dept_codes_2
domain.
ALTER DOMAIN dept_codes_2 ANNOTATIONS(DROP Title, ADD Name 'Domain');
See Also:
CREATE DOMAIN and ALTER DOMAIN in SQL Language Reference for complete clause changes and definitions.
10.2.5.7 Dictionary Table and Views
A dictionary table called ANNOTATIONS_USAGE$
includes all
the usage of annotations with schema objects, such as tables and views. When a new
annotation name, value, or both are specified to a schema object, a new entry in
ANNOTATIONS_USAGE$
table is created. Similarly, when a schema
object drops an annotation, the corresponding entry is dropped from the
ANNOTATIONS_USAGE$
table.
The following dictionary views track the list of annotations and their usage across all schema objects:
-
{DBA|USER|ALL|CDB}_ANNOTATIONS
-
{DBA|USER|ALL|CDB}_ANNOTATIONS_USAGE
-
{DBA|USER|ALL|CDB}_ANNOTATIONS_VALUES
10.2.5.7.1 Querying Dictionary Views
You can run queries on dictionary views to obtain the list of annotations that are used for specific schema objects.
Here are examples of query statements issued on an 'EMP' table:
SELECT * FROM USER_ANNOTATIONS_USAGE WHERE Object_Name = 'EMPLOYEE' AND Object_Type = 'TABLE' AND Column_Name IS NULL;
SELECT * FROM USER_ANNOTATIONS_USAGE WHERE Object_Name = 'EMPLOYEE' AND Object_Type = 'TABLE' AND Column_Name IS NOT NULL;
SELECT U.Column_Name, JSON_ARRAYAGG(JSON_OBJECT(U.Annotation_Name, U.Annotation_Value)) FROM USER_ANNOTATIONS_USAGE U WHERE Object_Name = 'EMPLOYEE' AND Object_Type = 'TABLE' AND Column_Name IS NOT NULL GROUP BY Column_Name;