Managing tables.

Oracle datatypes.

Character datatypes.
Type Description Range
CHAR[(size [BYTE | CHAR])] This is fixed length datatype. If the stored string is less than specified value of size, it's padded with trailing white-spaces. The default size is 1 1 to 2000 bytes
NCHAR[(size)] It's similar to CHAR, but is used to store Unicode character strings. The default size is 1. up to 2000 bytes
VARCHAR2(size [BYTE | CHAR]) Specifies a variable-length string up to size bytes/characters long. 1 to 4000 bytes
NVARCHAR2(size) Is used to store variable-length Unicode strings. 1 to 4000 bytes
CLOB Character Large OBject - is used to store variable-length character data. up to 4GB
NCLOB Is used to store large amount of Unicode character data. up to 4GB
LONG Using LONG is discouraged by Oracle. It's provided only for backward compatibility. Use the CLOB type instead. There can be only one LONG column in a table. Columns of this type cannot appear in WHERE, GROUP BY, or ORDER BY clauses. up to 2GB

Date Datatypes.
Type Description Range
DATE Stores date and time information. If a date value is specified without the time component (like '26-07-2003'), then the time is set to 12am. If a value is specified without the date component, the default day is the first day of the current month. To change the way the DATE values printed by Oracle, use function TO_CHAR or session variable NLS_DATE_FORMAT. Jan 1, 4712 BC to Dec 31, 9999 AD
TIMESTAMP[(precision)] Stores date and time information with fractional seconds precision. The default precision is 6, the maximum precision is 9. TIMESTAMP(0) is the same as DATE. DATE and 0 to 9 fractional seconds
TIMESTAMP[(precision)]
 WITH TIME ZONE
Is similar to TIMESTAMP datatype, but stores the time zone displacement (the difference) between the local time and the UTC (Coordinate Universal Time, same as GMT). The displacement is represented in hours and minutes. Two values of this type are considered to be identical if they represent the same time in UTC. DATE and 0 to 9 fractional seconds
TIMESTAMP[(precision)]
 WITH LOCAL TIME ZONE
Is similar to the TIMESTAMP datatype, but is also includes the time zone displacement. Although, this displacement is not stored in the database. Instead, the date-time information is stored in a normalized form. The data is always stored in the database time zone, but when the user retrieves the data, it is shown in the user's local session time zone. DATE and 0 to 9 fractional seconds
INTERVAL YEAR[(precision)]
 TO MONTH
Is used to represent a period of time as years and months. The precision specifies the number of digits in the year field (the default is 2). See functions NUMTOYMINTERVAL and TO_YMINTERVAL. Valid precisions values are from 0 to 9.
INTERVAL DAY[(precision)]
 TO SECOND
Represents a period of time as days, hours, minutes, and seconds. The precision specifies the number of digits in the day field (the default value is 6). See functions NUMTODSINTERVAL and TO_DSINTERVAL. Valid precisions values are from 0 to 9.

Date arithmetic

We can use the operators +, -, *, and / with the INTERVAL datatypes and operators + and - with the DATE and TIMESTAMP datatypes. Using these operators we can:
Numeric Datatypes.
Type Description Range
NUMBER[(precision [, scale])] This type stores both fixed-point and floating point numbers. The precision is the number of digits in the value, and the scale is number of digits to the right of the decimal point. The scale can be negative, which indicates that the value is rounded to the specified number of places to the left of the decimal point.  

Binary Datatypes.
Type Description Range
RAW(size) Is used to store binary information. We must specify the maximum size in bytes. This is a variable-length datatype. up to 2000 bytes
BLOB Is used to store Binary Large OBjects. up to 4GB
BFILE Is used to store information in external files. The external file size can be up to 4GB. Oracle stores only the file pointer in the database. file size up to 4GB
LONG RAW Is supported by Oracle for backward compatibility. Use BLOB instead. There can be only one LONG RAW column in a table. up to 2GB

Row ID Datatypes.
Type Description
ROWID Stores the physical address of a row. Physical ROWIDs store the address of rows in ordinary tables, clustered tables, table partitions and subpartitions, indexes, and index partitions and subpartitions. It provides the fastest access to a row of a given table.
UROWID Stores the logical ROWID of index-organized tables. Oracle creates logical ROWID based on an index-organized table's primary key.

Creating tables

To create a table we use the CREATE TABLE statement. The syntax for the statement is
CREATE TABLE table_name (
  column_name datatype [[CONSTRAINT constraint_name] column_constraint] [default_value],
  column_name datatype [[CONSTRAINT constraint_name] column_constraint] [default_value],
  ...
  column_name datatype [[CONSTRAINT constraint_name] column_constraint] [default_value]
  [, list_of_table_constraints]
);
where table_name and column_names are identifiers for the name of the table and the table's fields. These identifiers may include any alphanumeric character, the underscore (_), the dollar sign ($), and the pound sign (#), but must begin with a letter. Names of tables and columns are case insensitive in Oracle. If, however, we enclose those names in double quotes, then the names become case sensitive in the Oracle dictionary. Here is a simple example:
CREATE TABLE products (
  pid       CHAR(4),
  name      VARCHAR2(32),
  color     VARCHAR2(12),
  price     NUMBER(8,2),
  min_price NUMBER(8,2)
);

Note: we can use the DESCRIBE or DESC SQL*Plus command to list all of the columns in a table, along with their datatypes and other information.
DESC products;

Column-level constraints and default values

We can specify the default value for a column when we creating or modifying column (using ALTER TABLE statement). The specified default value will be used when we insert a new row into the table without providing a value for this column. If a default value is not set, then the default value for a column is set to NULL. To specify a default value for a column we need to use the keyword DEFAULT. For example,
CREATE TABLE products (
  pid       CHAR(4),
  name      VARCHAR2(32),
  color     VARCHAR2(12) DEFAULT 'Red',
  price     NUMBER(8,2) DEFAULT 19.99,
  min_price NUMBER(8,2)
);

For the default values we can use functions SYSDATE, SYSTIMESTAMP, USER, USERENV, and UID. For example

CREATE TABLE records (
  sid   CHAR(8),
  login CHAR(16) DEFAULT USER
);

Defining a column in a table we can also specify some column-level constraints; that is, requirements for the values this column stores. The list of constraints supported by Oracle is given in the table.
Oracle column-level constraints.
Constraint Description
NOT NULL This constraint does not allow (or allow) to insert a NULL value into this field. The general syntax for the constraint is
 [CONSTRAINT constraint_name] [NOT] NULL
If there is no constraint name specified, a system-generated name will be given to the constraint. Example:
CREATE TABLE products (
  ...
  name      VARCHAR2(32) CONSTRAINT products_notnull_name NOT NULL,
  ...
);
UNIQUE This constraint ensures that no two rows in a table duplicate data in the protected column. Oracle creates a unique index to enforce the uniqueness. This constraint allows NULL values in the constraint column. The general syntax for the constraint is
[CONSTRAINT constraint_name] UNIQUE
For example
CREATE TABLE users (
  user_id   NUMBER(6),
  user_name CHAR(16) CONSTRAINT users_unique_name UNIQUE,
  ...
);  
CHECK This constraint specifies some condition that values of the protected column should satisfy. The condition cannot use queries; environment functions (such as SYSDATE, USER, etc) and pseudo-columns (such as ROWID, CURVAL, etc) cannot be used to evaluate in the check condition. The general syntax for this constraint is
[CONSTRAINT constraint_name] CHECK (condition)
For example,
CREATE TABLE products (
  ...
  price NUMBER(9,2) CHECK (price > 0),
  ...
);  
PRIMARY KEY This constraint is more restricted version of the UNIQUE constraint. The column with the PRIMARY KEY constraint may not include NULL values. A table may contain only one PRIMARY KEY. The general syntax for this constraint is
[CONSTRAINT constraint_name] PRIMARY KEY
For example
CREATE TABLE products (
  pid       CHAR(4) CONSTRAINT products_pk PRIMARY KEY,
  ...
);
FOREIGN KEY   A foreign key constraint protects one or more column in a table by ensuring that for each non-NULL value there is data available elsewhere in the database with a primary key or unique key. The foreign key is the column (or columns) in the table (child table) where the constraint is created. The referenced key is the primary key or unique key column (or columns) in the table (parent table) that is referenced by the constraint. The column datatypes in the parent table and in child table should match. The general syntax for this constraint is
[CONSTRAINT constraint_name] REFERENCES [schema.]table [(colunm)]
   [ON DELETE {CASCADE | SET NULL}]
We can omit the column name in the parent table if we reference to the primary key. The ON DELETE clause specifies the action to be taken when a row in the parent table is deleted and child rows exist for the deleted parent primary key. We can either delete all child rows referencing the deleted parent row (CASCADE) or set their value to NULL (SET NULL). If we omit this clause, Oracle will not allow us to delete rows from the parent table if there are rows in the child table referencing these rows.
Example
CREATE TABLE orders (
  prod_id CHAR(4) CONSTRAINT orders_prod_fk FOREING KEY REFERENCES products ON DELETE CASCADE,
  pfj_id  CHAR(4) CONSTRAINT orders_proj_fk FOREING KEY REFERENCES projects ON DELETE CASCADE,
  supp_id CHAR(4) CONSTRAINT orders_supp_fk FOREING KEY REFERENCES supplier.id ON DELETE CASCADE,
  qty     NUMBER(6)
);

Table-level constraints

Table-level constraints are the same constraints (except NOT NULL) that cannot be defined for a particular column. Often those constraints involve more than one column.
Oracle table-level constraints.
Constraint Description
UNIQUE The general syntax for the constraint is
[CONSTRAINT constraint_name] UNIQUE (column, column, ... )
For example
CREATE TABLE registration (
  ...
  CONSTRAINT registration_uq_reg UNIQUE (sid, cid)
);  
CHECK The table-level CHECK constraint can include more than one column The general syntax for this constraint is
[CONSTRAINT constraint_name] CHECK (condition)
For example,
CREATE TABLE products (
  ...
  CONSTRAINT products_min_price CHECK ( min_price < price )
);  
PRIMARY KEY This constraints allows to create composite primary keys. The general syntax for this constraint is
[CONSTRAINT constraint_name] PRIMARY KEY (column, column, ...)
For example
CREATE TABLE orders (
  ...
  CONSTRAINT orders_pk PRIMARY KEY (prod_id, prj_id, supp_id)
);
FOREIGN KEY   This constraint allows to create composite foreign keys The general syntax for this constraint is
[CONSTRAINT constraint_name] (column, column, ...)
   REFERENCES [schema.]table [(colunm, column, ...)]
   [ON DELETE {CASCADE | SET NULL}]
Example
CREATE TABLE atlas (
  ...
  CONSTRAINT atlas_fk (year, term) REFERENCES semester (year, term)
);
See complete examples.

Creating a table from another table

We can create a table using a query based on another table or tables or views. The datatypes of the columns for the new table will be determined automatically by the query result. The general syntax for the corresponding statement is
CREATE TABLE table_name [(column_names)] AS
 SELECT query;
These are several examples
-- create a new table with exactly the same structure, but no data
CREATE TABLE employees_archive AS
 SELECT *
   FROM employees
  WHERE 1 = 2;
When we create a table like this, only the NOT NULL constraints will be copied into the new table.

Adding comments

We can store comments on tables and columns in the Oracle dictionary. To create these comments use COMMENT ON statement. The general syntax of the statement is
COMMENT ON {TABLE | COLUMN} fullname IS 'comments';
For example
COMMENT ON TABLE orders
 IS 'Order information includes: which project ordered what parts from which supplier and how many';
COMMENT ON COLUMN supplier.status
 IS 'It is a numeric coefficient between 0 and 100 that indicates how reliable this supplier is. 100 is the best.';
We can retrieve these comments and other table information from Oracle dictionary tables:

Creating a temporary table

When we create a table without any specific key words about table type, the table created is a relational table that is permanent. If we use key words GLOBAL TEMPORARY, Oracle will create a temporary table whose definition available to all sessions in the DB, but the data is available only to the session that inserted to it. The syntax is
CREATE GLOBAL TEMPORARY TABLE table_name (
  table definition
)
ON COMMIT {PRESERVE | DELETE} ROWS;
The ON COMMIT clause specifies if the data in the temporary table is session specific (PRESERVE ROWS) or transaction specific (DELETE ROWS - the default option). Example:
CREATE GLOBAL TEMPORARY TABLE emp_bonus_temp (
  ssn   NUMBER(9),
  bonus NUMBER(12, 2)
)
ON COMMIT PRESERVE ROWS;

Modifying tables

In this section we mostly will use the ALTER TABLE command.

Adding columns

To add a new column to an existing table we use the ALTER TABLE statement with parameter ADD. The general syntax is
ALTER TABLE [schema.]table_name
  ADD { column definition | ( list_column_definitions )};
Example:
ALTER TABLE projects
  ADD manager_id NUMBER(9) CONSTRAINT projects_fk REFERENCES employees (ssn) ON DELETE SET NULL;
Note:

Modifying columns

The general syntax for modifying an existing column in a table is
ALTER TABLE [schema.]table_name
  MODIFY { column_name new_column_attributes | ( list_of_column_names_and_attributes ) } ;
where new_column_attributes is any part (or parts) of column definition. If we omit any part of the column definition (datatype, default value, or constraints), the omitted parts remain unchanged. Example:
ALTER TABLE orders
     MODIFY ( quantity NUMBER(8), status DEFAULT 'in process' );
The new DEFAULT value affects only the rows inserted after the table modification, none of the existing rows will be changed.

There are some rules for modifying column definitions:

Dropping columns

Using the ALTER TABLE command we can drop a column, make a column unused, and drop all unused columns. The syntax for dropping a column is
ALTER TABLE [schema.]table_name
 DROP { COLUMN column_name | ( list_of_column_names ) }
 [ CASCADE CONSTRAINTS ];
If we drop a column, the indexes and constraints on this column are also dropped. We must specify CASCADE CONSTRAINTS if the column being dropped is part of a multicolumn constraint; the constraint will be dropped.

The syntax for marking a column as unused is

ALTER TABLE [schema.]table_name
  SET UNUSED { COLUMN column_name | ( list_of_column_names ) }
  [ CASCADE CONSTRAINTS ];
To avoid rebuilding the entire table during the peak hours, we can mark a column unused and remove it later (when the system is free):
ALTER TABLE orders
  SET UNUSED COLUMN status;

To drop the columns marked as unused, we use the command

ALTER TABLE [schema.]table_name
 DROP { UNUSED COLUMNS | COLUMNS CONTINUE };
The UNUSED COLUMNS clause drops all the columns marked as unused (we cannot selectively remove only some of them). The COLUMNS CONTINUE clause makes the Oracle to continue the previously interrupted DROP operation.

Renaming tables

To rename a table we can use the following syntax
ALTER TABLE [schema.]table_name
    RENAME TO new_table_name;
For example,
ALTER TABLE orders RENAME TO spj;

We can also use the RENAME command to change a name of a table, but this command allows to change table names only for the current schema. The general syntax is

RENAME old_table_name TO new_table_name;
When we renaming a table

Adding table-level constraints

We can add column-level constrains just by modifying the desired column, but for adding new constraints that involves several columns we need to use the following syntax of the ALTER TABLE statement
ALTER TABLE [schema.]table_name
  ADD CONSTRAINT constraint_name constraint_definition;
For example
ALTER TABLE records
  ADD CONSTRAINT records_semester_fk
  FOREIGN KEY (year, term) REFERENCES semester (year, term) ON DELETE CASCADE;

Enabling and disabling constraints

When a constraint is created, it is enabled automatically. We can disable a constraint using the syntax
ALTER TABLE [schema.]table_name
  DISABLE { CONSTRAINT constraint_name | UNIQUE column_name | PRIMARY KEY }
  [ CASCADE ];
If we specify the UNIQUE and a column name, the unique key will be disabled. If we specify PRIMARY KEY, the primary key of the table will be disabled. We cannot disable primary key or unique key if there are foreign keys that reference them. To disable such constraints use the CASCADE clause. For example
ALTER TABLE projects
  DISABLE CONSTRAINT projects_fk;

Using the ALTER TABLE statement we can also enable previously disabled constraint by using the syntax

ALTER TABLE [schema.]table_name
  ENABLE { CONSTRAINT constraint_name | UNIQUE column_name | PRIMARY KEY };

Dropping constraints

We can also completely drop a constraint by using
ALTER TABLE [schema.]table_name
  DROP { CONSTRAINT constraint_name | UNIQUE column_name | PRIMARY KEY }
  [ CASCADE ];
Example
ALTER TABLE bonus
  DROP PRIMARY KEY CASCADE;

Validated constraints

Enabling and disabling constraints affects only the future data (that is, rows inserted in the table after the constraint was changed). On the contrary, the VALIDATE and NOVALIDATE keywords in the ALTER TABLE statement act on existing data. Thus, each constraint can have four possible states:
Possible constraint states
State Description
ENABLE VALIDATE The existing data in the table is validated to verify that it conforms to the constraint. This is the default for the ENABLE clause.
ENABLE NOVALIDATE The constraint is enabled for future checking, but the existing data is not verified.
DISABLE VALIDATE The constraint is disabled, but the existing data is kept valid. No DML operation is allowed on the table because future changes cannot be verified.
DISABLE NOVALIDATE  This is the default for the DISABLE clause. No checks are done for the future or existing data.

We can use the MODIFY CONSTRAINT to set a new constraint status:
ALTER TABLE [schema.]table_name
  MODIFY CONSTRAINT constraint_name status;
For example,
ALTER TABLE departments MODIFY CONSTRAINT departments_fk DISABLE VALIDATE;

Deferring constraints

If there are some CHECK constraints on a table, then by default Oracle checks whether the data conforms to these constraints when the DML statement is executed. Although, we can change this default behavior and specify that the data check is to be executed when the transaction is complete. We can change the behavior only for the constraints that were created with the keyword DEFERRABLE (by default all constraint are created as NOT DEFERRABLE). To create a DEFERRABLE constraint we need to use this keyword. For example
ALTER TABLE customer
  ADD CONSTRAINT customer_pk PRIMARY KEY (cust_id) DEFERRABLE;

If a constraint is DEFERRABLE, we can set the behavior by using the SET CONSTRAINT command

SET CONSTRAINT[S] { ALL | constraint_list }
  { IMMEDIATE | DEFERRED };
or by using the ALTER SESSION SET CONSTRAINT command
ALTER SESSION SET CONSTRAINT[S] { ALL | constraint_list }
  { IMMEDIATE | DEFERRED };
(where the keyword IMMEDIATE makes Oracle to execute the check after each DML statement, and DEFERRED makes it to wait until the end of the transaction). For example:
SET CONSTRAINT customer_pk DEFERRED;

Another way to set the behavior of the check constraint is to specify at the moment we create the constraint. To do this, Oracle provides the INITIALLY clause. This clause has the following syntax:

INITIALLY { IMMEDIATE | DEFERRED }
For example, we'll add the same constraint customer_pk initially DEFERRED
ALTER TABLE customer
  ADD CONSTRAINT customer_pk PRIMARY KEY (cust_id)
  DEFERRABLE INITIALLY DEFFERED;
We can also use the INITIALLY clause in the ALTED TABLE MODIFY CONSTRAINT command to change the behavior. For example, we can set the customer_pk back to the default behavior:
ALTER TABLE customer
  MODIFY CONSTRAINT customer_pk INITIALLY IMMEDIATE;

Dropping tables

To drop a table we use the DROP TABLE statement. The syntax of the statement is as follows
DROP TABLE [schema.]table_name [ CASCADE CONSTRAINTS ];
When a table is dropped To drop a table that is referenced by other table's foreign keys, we must specify the CASCADE CONSTRAINTS clause. Please also see the
difference between dropping and truncating a table.