Previous Section Table of Contents Next Section

3.3 SQL Command Reference

ALL/ANY/SOME Operators

The ALL operator performs a Boolean test of a subquery for the existence of a value in all rows. The ANY operator, and its synonym SOME, performs a Boolean test of a subquery for the existence of a value in any of the rows tested.

Platform

Command

DB2

Supported

MySQL

Not supported

Oracle

Supported

PostgreSQL

Supported

SQL Server

Supported


SQL2003 Syntax

SELECT ...

WHERE expression comparison {ALL | ANY | SOME} ( subquery )

Keywords


WHERE expression

Tests a scalar expression, such as a column, against every value in the subquery, for ALL, and against every value until a match is found for ANY and SOME. All rows must match the expression to return a Boolean TRUE value for the ALL operator, while one or more rows must match the expression, for ANY and SOME, to return a Boolean TRUE value.


comparison

Compares the expression to the subquery. The comparison must be a standard comparison operator like =, <>, !=, >, >=, <, or <=.

Rules at a Glance

The ALL operator returns a Boolean TRUE value when one of two things happen: either the subquery returns an empty set (i.e., no records) or every record in the set meets the comparison. ALL returns FALSE when any records in the set do not match the value comparison. ANY and SOME operators return a Boolean TRUE when at least one record in the subquery matches the comparison operation, and FALSE when no record matches the comparison operation (or when a subquery returns an empty result set). If even one return value of the subquery is NULL, then the operation evaluates as NULL, not as TRUE.

Do not include special clauses like ORDER BY, GROUP BY, CUBE, ROLLUP, WITH, etc. in your subquery. Refer to SUBQUERY Substatement for more information.


For example, we want to see which authors currently have no titles:

SELECT au_id

FROM authors

WHERE au_id <> ALL(SELECT au_id FROM titleauthor)

You can use ANY / SOME to perform filtering checks of different kinds. For example, the following query will retrieve any records from the employees table that exist in the employees_archive table that were located in Anchorage:

SELECT *

FROM employees

WHERE job_lvl = ANY(SELECT job_lvl FROM employees_archive

                    WHERE city = 'Anchorage')

The above query returns information about employees who have the same job_lvl as any employee working in Anchorage, Alaska.

Programming Tips and Gotchas

The ALL and ANY/SOME operators are somewhat difficult to get used to. Most developers find it a lot easier to use similar functions like IN and EXISTS.

EXISTS is symantically equivalent to the ANY/SOME operator.


Platform Differences

All of the platforms support ALL and ANY/SOME in the manner described above except MySQL, which doesn't support subqueries until Version 4.0. On pre-Version 4.0 MySQL platforms, consider using the IN operator instead of EXISTS for ANY/SOME.

Oracle supports one minor variation in that you can supply a list of values instead of a subquery. For example, we can find all employees who have a job_lvl value equal to 9 or 14:

SELECT * FROM employee

WHERE job_lvl = ALL(9, 14);

DB2 and SQL Server support some additional comparison operators: not greater than (!>) and not less than (!<).

See Also

ALL/ANY/SOME
BETWEEN
EXISTS
SELECT
WHERE
BETWEEN Operator

The BETWEEN operator performs a Boolean test of a value against a range of values. It returns TRUE when the value is included in the range and FALSE when the value falls outside of the range. The results are NULL (unknown) if any of the range values are NULL.

Platform

Command

DB2

Supported

MySQL

Supported

Oracle

Supported

PostgreSQL

Supported

SQL Server

Supported


SQL2003 Syntax

SELECT ...

WHERE expression [NOT] BETWEEN lower_range AND upper_range

Keywords


WHERE expression

Compares a scalar expression, such as a column, to the range of values bounded by upper_range and lower_range.


[NOT] BETWEEN lower_range AND upper_range

Compares the expression to the lower_range and upper_range. The comparison is inclusive, meaning that it is equivalent to saying "where expression is [not] greater than or equal to lower_range and less than or equal to upper_range."

Rules at a Glance

The BETWEEN operator is used to test an expression against a range of values. The BETWEEN operator may be used with any datatype except BLOB, CLOB, NCLOB, REF, and ARRAY.

For example, we want to see title_ids that have year-to-date sales between 10,000 and 20,000:

SELECT title_id

FROM titles

WHERE ytd_sales BETWEEN 10000 AND 20000

BETWEEN is inclusive of the range of values listed. In this case, it includes the values of 10,000 and 20,000 in the search. If you want an exclusive search, then you must use the greater than (>) and less than (<) symbols:

SELECT title_id

FROM titles

WHERE ytd_sales > 10000

  AND ytd_sales < 20000

The NOT operator allows you to search for values outside of the BETWEEN range. For example, you can also find all the title_ids that were not published during 2002:

SELECT title_id

FROM titles

WHERE pub_date NOT BETWEEN '01-JAN-2003' AND '31-DEC-2003'

Programming Tips and Gotchas

Some coders are very particular about how the keyword AND is used in WHERE clauses. To prevent a casual reviewer from thinking that the AND used in a BETWEEN operation is a logical AND operator, you might want to use parentheses to encapsulate the entire BETWEEN clause:

SELECT title_id

FROM titles

WHERE (ytd_sales BETWEEN 10000 AND 20000)

  AND pubdate >= '1991-06-12 00:00:00.000'

Platform Differences

All of the platforms support BETWEEN in the manner described above.

See Also

ALL/ANY/SOME
EXISTS
SELECT
WHERE
CALL Statement

The CALL statement invokes a stored procedure.

Platform

Command

DB2

Supported, with variations

MySQL

Not supported

Oracle

Supported, with variations

PostgreSQL

Not supported

SQL Server

Not supported


SQL2003 Syntax

CALL procedure_name ([parameter [,...] ])

Keywords


CALL procedure_name

Specifies the stored procedure that you want to invoke. It must be a previously defined stored procedure that is available in the current user context (instance, database, schema, etc.).


(parameter [,...] )

Provides values for each input parameter required by the stored procedure. Each parameter listed is required by the stored procedure in the same ordinal position. Thus, the fifth parameter listed would provide the value for the fifth argument required by the stored procedure. The parameters must be enclosed in parentheses and separated by commas. Note that the parentheses are required even if there are no parameter values (e.g., even if there are no parameter values, you must still use CALL( )). Strings should be in single quotes. If the stored procedure has only OUT parameters, place host variables or parameter markers within the parentheses.

Rules at a Glance

The CALL statement makes it easy to invoke a stored procedure. Simply provide the name of the stored procedure and include any parameters used by the stored procedure, enclosing them within parentheses.

This Oracle example creates a simple stored procedure, and then calls it:

CREATE PROCEDURE update_employee_salary

(emp_id NUMBER, updated_salary NUMBER)

IS

BEGIN

  UPDATE employee SET salary = updated_salary

WHERE employee_id =emp_id ;

END;

CALL update_employee_salary(1517, 95000);

Programming Tips and Gotchas

The return status of a called stored procedure can be found, typically, by using GET DIAGNOSTIC. GET DIAGNOSTIC is not widely supported among the various database platforms, so check the platform documentation for more details.

Many platforms also support an alternative command called EXECUTE to perform the same functionality. In some cases, you may prefer EXECUTE to CALL, since the former can be used to execute any kind of prepared SQL, including methods, functions, or batches of SQL code.

DB2

DB2 supports CALL along with DESCRIPTOR capabilities:

CALL procedure_name { [(parameter [,...] )] | USING DESCRIPTOR

     descriptor_name }

where:


USING DESCRIPTOR descriptor_name

Identifies a SQL Descriptor Area (SQLDA) structure containing a valid description of the host variables. An SQLDA is a collection of variables that is required for execution of the SQL DESCRIBE statement. The SQLDA variables are options that can be used by the PREPARE, OPEN, FETCH, EXECUTE, and CALL statements. Values in the SQLDA must be set prior to issuing the CALL statement. This is a deprecated feature in DB2. We recommend that you instead use the standard CALL proc(param, param) syntax.

DB2 allows you to substitute host variables for the procedure name or the parameters, where appropriate. When using the USING DESCRIPTOR clause, the variables must be string variables of 254 or fewer characters.

On DB2, any return status issued by the called stored procedure is returned to the SQLERRD field of the SQLCA (SQL Communications Area). You can also use the GET DIAGNOSTIC statement to retrieve the RETURN_STATUS value (-1 indicates error) or row count.

MySQL

Not supported.

Oracle

Oracle allows the CALL statement to invoke standalone stored procedures, functions, and methods, as well as stored procedures and functions contained within a type or package. Following is the Oracle syntax:

CALL [schema.][{type_name | package_name}.]procedure_name@dblink

[(parameter [,...] )]

[INTO :variable_name [[INDICATOR] :indicator_name] ]

where:


CALL [schema.][{type_name | package_name}.] procedure_name@dblink

Calls the named object. You may fully enumerate the object name, including schema, type, etc., or allow Oracle to assume the current schema and database instance. If the procedure or function resides in another database, simply specify the database via a database link name, shown as dblink in the syntax. dblink must refer to a previously created database link.


INTO :variable_name

Specifies the name of a previously declared variable that will store the value returned when you call a function. INTO is required, and only usable, when calling a function.


INDICATOR :indicator_name

Retains the condition of the host variable, for example whether the return value is NULL, for functions precompiled in a Pro*C/C++ routine.

The parameters used in an Oracle CALL statement may not include pseudocolumns or the VALUE or REF functions. You must use a host variable for any parameter that corresponds to an OUT or IN OUT argument of the called stored procedure.

PostgreSQL

Not Supported.

SQL Server

Not supported. Instead, use the non-ANSI EXECUTE statement.

See Also

CREATE/ALTER PROCEDURE
CLOSE CURSOR Statement

The CLOSE CURSOR statement closes a server-side cursor created with a DECLARE CURSOR statement.

Platform

Command

DB2

Supported, with variations

MySQL

Not supported

Oracle

Supported

PostgreSQL

Supported

SQL Server

Supported, with variations


SQL2003 Syntax

CLOSE cursor_name

Keywords


cursor_name

Names a cursor previously created with the DECLARE CURSOR statement.

Rules at a Glance

The CLOSE statement closes a cursor and destroys the cursor result set. All the database platforms release any locks that were held by the cursor, though this is not specified in the ANSI standard. For example:

CLOSE author_names_cursor;

Programming Tips and Gotchas

You can also close a cursor implicitly using a COMMIT statement or, for cursors defined WITH HOLD, using a ROLLBACK statement.

DB2

DB2 supports an added optional WITH clause on the CLOSE statement:

CLOSE cursor_name [WITH RELEASE]

where:


WITH RELEASE

Attempts to release all read locks held by the cursor. Note that DB2 is not always able to release all locks since some locks may be in use by other operations.

The WITH RELEASE clause is ignored on cursors run under isolation level 3 CS or UR, when the cursor is defined in a method, when the cursor is defined in a function, or when the cursor is defined in a stored procedure that is called by a function or method. WITH RELEASE may allow phantom read and nonrepeatable read anomalies when run under isolation levels RS or RR. For a detailed explanation of isolation levels, including phantom reads and nonrepeatable reads, refer to SET TRANSACTION ISOLATION LEVEL.

PostgreSQL

PostgreSQL supports the ANSI standard syntax. PostgreSQL issues an implicit CLOSE statement for every open cursor when a transaction is ended with a COMMIT or ROLLBACK statement.

SQL Server

Microsoft SQL Server supports the ANSI standard syntax, and an additional GLOBAL keyword:

CLOSE [GLOBAL] cursor_name

where:


GLOBAL

Identifies the previously defined cursor as a global cursor.

In the ANSI standard behavior, closing a cursor destroys the cursor result set. Locking is a physical feature of each database platform and thus not a part of the ANSI SQL definition. However, all the database platforms covered here drop the locks taken up by the cursor. Another physical implementation detail is that SQL Server does not automatically reallocate memory structures consumed by a cursor to the memory pool. To accomplish such reallocation, you must issue a DEALLOCATE cursor_name command.

This example from Microsoft SQL Server opens a cursor and fetches a result set of all employees who have a last name starting with "K":

DECLARE employee_cursor CURSOR FOR

  SELECT lname, fname

  FROM pubs.dbo.employee

  WHERE lname LIKE 'K%'

OPEN employee_cursor

FETCH NEXT FROM employee_cursor

WHILE @@FETCH_STATUS = 0

BEGIN

  FETCH NEXT FROM employee_cursor

END

CLOSE employee_cursor

DEALLOCATE employee_cursor

GO

See Also

DECLARE CURSOR
FETCH
OPEN
COMMIT Statement

The COMMIT statement explicitly ends an open transaction and makes the changes permanent in the database. Transactions can be opened implicitly as part of an INSERT, UPDATE, or DELETE statement, or opened explicitly with a START statement. In either case, an explicitly issued COMMIT statement will end the open transaction.

Platform

Command

DB2

Supported

MySQL

Supported, with variations

Oracle

Supported, with variations

PostgreSQL

Supported, with variations

SQL Server

Supported, with variations


SQL2003 Syntax

COMMIT [WORK] [AND [NO] CHAIN]

Keywords


COMMIT [WORK]

Ends the current, open transaction and writes any data manipulated by the transaction to the database. The optional keyword WORK is noise and has no effect.


AND [NO] CHAIN

AND CHAIN tells the DBMS to treat the next transaction as if it were a part of the preceding transaction. In effect, the two transactions are separate units of work, but they share a common transaction environment (such as transaction isolation level). Including the optional NO keyword tells the DMBS to explicitly use the ANSI default behavior. The COMMIT keyword by itself is functionally equivalent to the statement COMMIT WORK AND NO CHAIN.

Rules at a Glance

For simple operations, you will execute transactions (that is, SQL code that manipulates or changes data and objects in a database) without explicitly declaring a transaction. However, all transactions are best managed by explicitly closing them with a COMMIT statement. Because records and even entire tables can be locked for the duration of a transaction, it is extremely important that transactions are completed as quickly as possible. Thus, manually issuing a COMMIT statement with a transaction can help control user concurrency issues and locking problems on the database.

Programming Tips and Gotchas

The most important gotcha to consider is that some database platforms perform automatic and implicit transactions, while others require explicit transactions. If you assume a platform uses one method of transactions over the other, you may get bitten. Thus, when moving between database platforms you should follow a standard, preset way of addressing transactions. We recommend always using explicit transactions with START TRAN, on database platforms that support it, to begin a transaction, and COMMIT or ROLLBACK to end a transaction.

In addition to finalizing a single or group of data-manipulation operation(s), COMMIT has some interesting effects on other aspects of a transaction. First, it closes any associated open cursors. Second, any temporary table(s) specified with ON COMMIT DELETE ROWS (an optional clause of the CREATE TABLE statement) are cleared of data. Third, all deferred constraints are checked. If any deferred constraints are violated, the transaction is rolled back. Finally, all locks opened by the transaction are released. Please note that SQL2003 dictates that transactions are implicitly opened when one of the following statements is executed:

  • ALTER

  • CLOSE

  • COMMIT AND CHAIN

  • CREATE

  • DELETE

  • DROP

  • FETCH

  • FREE LOCATOR

  • GRANT

  • HOLD LOCATOR

  • INSERT

  • OPEN

  • RETURN

  • REVOKE

  • ROLLBACK AND CHAIN

  • SELECT

  • START TRANSACTION

  • UPDATE

If you did not explicitly open a transaction when you started one of the commands listed above, the standard dictates that the DBMS platform open a transaction for you.

DB2

DB2 supports the standard, but not the AND [NO] CHAIN clause.

MySQL

MySQL supports COMMIT and transactions only with InnoDB tables. It does not support the AND [NO] CHAIN clause.

Oracle

Oracle supports the standard, but not the AND [NO] CHAIN clause. In addition, Oracle has a couple of extensions to the standard clause:

COMMIT [WORK] [ {COMMENT 'text' | FORCE 'text' [, int]} ];

where:


COMMENT 'text'

Associates a comment with the current transaction where 'text' is a literal string up to 255 characters long. The text string is stored in the Oracle data dictionary view DBA_2PC_PENDING with the transaction ID, in case the transaction rolls back.


FORCE 'text' [, int]

Allows an in-doubt distributed transaction to be manually committed, where 'text' is a literal string that identifies the local or global transaction ID. Transactions can be identified by querying the Oracle data dictionary view DBA_2PC_PENDING. The optional int parameter is an integer that explicitly assigns a system change number (SCN) to the transaction. Without int, the transaction commits using the current SCN.

Issuing a COMMIT statement with the FORCE clause will commit only the transaction explicitly identified in the FORCE clause. It will not affect the current transaction unless it is explicitly identified. The FORCE clause is not usable in PL/SQL statements.

The following example commits a transaction while associating a comment with the transaction:

COMMIT WORK COMMENT 'In-doubt transaction, Call (949) 555-1234';

PostgreSQL

PostgreSQL implements the following syntax:

COMMIT [WORK | TRANSACTION];

In PostgreSQL, both the WORK and TRANSACTION keywords are optional. When you issue a COMMIT, all open transactions are written to disk and the results of those transactions then become visible to other users. For example:

INSERT INTO sales VALUES('7896','JR3435','Oct 28 1997',25,

   'Net 60','BU7832');

COMMIT WORK;

SQL Server

SQL Server does support the AND [NO] CHAIN clause. SQL Server supports the keyword TRANSACTION as an equivalent to WORK, as in the following syntax:

COMMIT { [TRAN[SACTION] [transaction_name] ] | [WORK] }

Microsoft SQL Server allows the creation of a specific, named transaction using the START TRAN statement. The COMMIT TRANSACTION syntax allows you to specify an explicit, named transaction to close or to store a transaction name in a variable. Curiously, SQL Server still commits only the most recently opened transaction, despite the name of the transaction that is specified.

When you issue COMMIT WORK, SQL Server terminates all open transactions and writes their changes to the database. You may not specify a transaction name when using COMMIT WORK.

See Also

ROLLBACK
START TRANSACTION
CONNECT

The CONNECT statement establishes a connection to the DBMS and to a specific database within the DBMS.

Platform

Command

DB2

Supported, with variations

MySQL

Not supported

Oracle

Supported

PostgreSQL

Not supported

SQL Server

Supported, with variations


SQL2003 Syntax

CONNECT TO {DEFAULT | {[server_name] [AS connection_name]

   [USER user_name ] }

Keywords


DEFAULT

Initiates a default session with the server where the user authorization is the default and the current database is the default. The standard specifies that CONNECT TO DEFAULT is issued implicitly if you start a SQL session without first issuing a CONNECT statement.


server_name

Establishes a connection to a named server. The server_name may be a string literal enclosed in single-quotes or a host variable.


AS connection_name

Establishes a connection with the name connection_name shown in single-quotes. The optional connection_name may be a string literal enclosed in single quotes or a host variable. It is optional only for the first connection attached to a server. All subsequent sessions must include the AS clause. This is useful for telling user connections apart when many users, perhaps even a single user, have many open sessions on a given server_name.


USER user_name

Establishes a connection to the named server under the user_name specified.

Rules at a Glance

Issue the CONNECT statement to open an interactive SQL session with a DBMS. The period between issuing the CONNECT and DISCONNECT statements is commonly called a session. Typically, you will complete all work on a DBMS during an explicitly invoked session.

If you do not specify the server name, the connection name, or the username, then the platform DBMS will provide default values for you. The defaults vary from platform to platform.

To connect to the "houston" server under a specific user ID, you might issue the command:

CONNECT TO houston USER pubs_admin

If the DBMS requires named connections, you might use the following, alternative syntax:

CONNECT TO houston USER pubs_admin AS

   pubs_administrative_session;

If you want just a simple, short-term connection then you might use the default:

CONNECT TO DEFAULT;

Programming Tips and Gotchas

If the CONNECT statement is invoked without explicitly disconnecting, the old session becomes dormant and the new session becomes active. You can then switch between connections using the SET CONNECTION statement.

The Oracle tool SQL*Plus uses the CONNECT command somewhat differently: to connect a user to a specific schema.


DB2

DB2 supports a couple of variations to the ANSI standard:

CONNECT { [TO] {[server_name] [IN SHARE MODE |

   IN EXCLUSIVE MODE [ON SINGLE DBPARTITIONNUM] | [RESET] }

[USER user_name ] { [USING password] | [NEW password

   CONFIRM password]}

where:


CONNECT

Equates to the SQL statement CONNECT TO DEFAULT, when used alone.


TO server_name

Identifies the server to which the connection will be established. The server_name may be a string literal or a character datatype variable of 8 or fewer characters (UDB) or 16 or fewer characters (OS/390 or z/OS).


IN SHARE MODE

Establishes a concurrent connection and allows other users to connect to the database. Prevents other users from connecting in exclusive mode.


IN EXCLUSIVE MODE [ON SINGLE DBPARTITIONNUM]

Acquires an exclusive connection on the application server and prevents any new users from connecting unless they use the same user_name and password. The optional ON SINGLE DBPARTITIONNUM clause is only usable on a partitioned database. This option specifies that the coordinator database partition is connected in exclusive mode, while all other database partitions are connected in share mode.


RESET

Executes a COMMIT statement, then disconnects the session from the server.


USER user_name

Establishes the connection under the named user account. The user_name may be a string literal or a character datatype variable of 8 or fewer characters in length.


USING password

Specifies the password for the user account of user_name. It may be a string literal or a character datatype variable of 8 or fewer characters in length.


NEW password CONFIRM password

Specifies a new password that will be assigned to the user account called user_name. It may be a string literal or a character datatype variable of 18 or fewer characters in length.

For example, we might want to change the password for the user account sam to mephrun using a VARCHAR(8) host variable, app_server, to store the value of the application server:

CONNECT TO :app_server USER sam NEW 'mephrun' CONFIRM 'mephrun';

MySQL

Not supported.

Oracle

The CONNECT clause allows a database connection as a specific username. Alternately, a connection can be established for special privileges with AS SYSOPER or AS SYSDBA. The Oracle syntax is:

CONN[ECT] [[username/password] {AS {SYSOPER | SYSDBA} ] ]

where:


CONN[ECT] username/password

Establishes a connection to the database instance.


AS { SYSOPER | SYSDBA }

Establishes the connection as one of the two optional system roles.

If another connection is already open, CONNECT commits any open transactions, closes the current session, and opens the new one.

Oracle also allows the CONNECT statement in its SQL*Plus and iSQL*Plus tools.

PostgreSQL

PostgreSQL does not explicitly support the CONNECT statement. However, it does support the statement SPI_CONNECT under the Server Programming Interface and PG_CONNECT under the PG/TCL programming package.

SQL Server

SQL Server supports the basic elements of the CONNECT statement within Embedded SQL (inside of C++ or Visual Basic programs), as in the following:

CONNECT TO [server_name.]database_name [AS connection_name]

USER {login_name[.password] | $integrated}

where:


CONNECT TO server_name.database_name

Specifies the server and database to which you want a connection. You may leave off the server_name if you wish to default to the local server.


AS connection_name

Names the connection as an alphanumeric string up to 30 characters in length. Symbols are allowed, except for hyphens (-), but the first character must be a letter. CURRENT and ALL are reserved and may not be used for a connection_name. You need only define connection names when making more than one connection.


USER {login_name[.password | $integrated]}

Connects the session under the login_name specified using the password provided or using Windows integrated security. The password is optional when supplying a login name.

For example, we can connect to the server named new_york as the Windows login pubs_admin:

CONNECT TO new_york.pubs USER pubs_admin

To issue the same command under SQL Server standard security:

EXEC SQL CONNECT TO new_york.pubs USER pubs_admin

To issue the same command under Windows integrated security:

EXEC SQL CONNECT TO new_york.pubs USER $integrated

To switch to a different connection, you should use the SET CONNECTION statement.

See Also

SET CONNECTION
CREATE/ALTER DATABASE Statement

The ANSI standard does not actually contain a CREATE DATABASE statement. However, since it is nearly impossible to operate a SQL database without this command, we've added CREATE DATABASE here. Almost all database platforms support some version of this command.

Platform

Command

DB2

Supported, with variations

MySQL

Supported, with variations

Oracle

Supported, with variations

PostgreSQL

Supported, with variations

SQL Server

Supported, with variations


Rules at a Glance

This command creates a new, blank database with a specific name. Most DBMS platforms require the user to possess administrator privileges in order to create a new database. Once the new database is created, you can populate it with database objects (such as tables, views, triggers, and so on) and populate the tables with data.

Depending on the platform, CREATE DATABASE may also create corresponding files on the filesystem that contain the data and metadata of the database.

Programming Tips and Gotchas

Since CREATE DATABASE is not an ANSI command, it is prone to rather extreme variation in syntax between platforms.

DB2

The DB2 statement CREATE DATABASE initializes a new database with a variety of user-defined characteristics, such as collation and autoconfiguration options. In addition, the statement also creates the three initial tablespaces, system tables, and recovery logs required by a DB2 database:

CREATE {DATABASE | DB} database_name

[AT DBPARITIONNUM] [ON path_and_drive] [ALIAS database_alias]

[USING CODESET codeset TERRITORY territory]

[COLLATE USING {COMPATIBILTIY | IDENTITY | NLSCHAR | SYSTEM} ]

[NUMSEGS int] [DFT_EXTENT_SZ int]

[CATALOG TABLESPACE tablespace_definition]

[USER TABLESPACE tablespace_definition]

[TEMPORARY TABLESPACE tablespace_definition] [WITH "comments"]

[AUTOCONFIGURE [USING param value [...] ]

[APPLY {DB ONLY | DB AND DBM | NONE} ]

where:


CREATE {DATABASE | DB} database_name

Creates a database called database_name. The name must be unique from all other database names on either the local database directory or the system database directory.


AT DBPARITIONNUM

Creates the database on the database partition where the command was issued. This command is used only to recreate a database that was dropped; it should not be used to create a brand new database. Once the CREATE DATABASE AT DBPARTITIONNUM statement is issued, the database must be immediately restored to the node.


ON path_and_drive

Specifies the path and drive, up to 205 characters long, to create the database on a Windows or Unix-based system. When this clause is omitted, the database is created on the default database path declared in the database manager configuration file dftdbpath parameter.


ALIAS database_alias

Declares an alias for the database within the system database directory.


USING CODESET codeset TERRITORY territory

Declares the codeset and territory used by the database. Once these values are set, they cannot be changed later.


COLLATE USING {COMPATIBILTIY | IDENTITY | NLSCHAR | SYSTEM}

Specifies the type of collation used for the database. Once set, the collation sequence cannot be changed later. Options are:


COMPATIBILITY

Uses DB2 v2 collation sequence for backward compatibility.


IDENTITY

Uses the identity collation sequence, where strings are compared byte for byte.


NLSCHAR

Uses the collation sequence unique for the database codeset and territory. This option is currently only supported with the Thai code page (CP874).


SYSTEM

Uses the collation sequence for the current territory.


NUMSEGS int

Specifies the number of segment directories, as int, created to store DAT, IDX, LF, LB, and LBA files for any default System Managed Space (SMS) tablespaces. This setting does not affect DMS tablespaces, SMS tablespaces with explicitly defined creation characteristics, or SMS tablespaces created after the database is created.


DFT_EXTENT_SZ int

Specifies the default extent size, as int, of the tablespaces in the database.


CATALOG TABLESPACE tablespace_definition

Specifies the definition of the tablespace that holds the catalog tables. Details on the syntax for tablespace_definition are detailed below. When this clause is omitted, the catalog tables will be created in an SMS tablespace called SYSCATSPACE with the values set by the NUMSEGS and DFT_EXTENT_SZ clauses.


USER TABLESPACE tablespace_definition

Specifies the definition of the tablepace that holds the initial user tablespace. Details on the syntax for tablespace_definition are detailed below. When this clause is omitted, the user tablespace will be created in an SMS tablespace called USERSPACE1 with the values set by the NUMSEGS and DFT_EXTENT_SZ clauses.


TEMPORARY TABLESPACE tablespace_definition

Specifies the definition of the tablepace that holds the initial system temporary tablespace. Details on the syntax for tablespace_definition are detailed below. When this clause is omitted, the user tablespace will be created in an SMS tablespace called TEMPSPACE1 with the values set by the NUMSEGS and DFT_EXTENT_SZ clauses.


WITH "comments"

Specifies a description, up to 30 characters in length, for the database within the database directory.


AUTOCONFIGURE [USING param value [...]]

Declares user-defined settings for important database settings such as the buffer pool size. When issued without the USING clause, DB2 calculates the optimal settings and applies them. The list of param settings and their possible values are:


mem_percent

Defines the percentage of memory dedicated to the database. The default is 25, but may range from 1-100. Do not set this to 100 if other applications are running on the server.


workload_type

Defines the database workload as either 'simple', 'mixed', or 'complex', with 'mixed' as the default. The 'simple' workload tunes I/O for transactions, while 'complex' tunes the workload for more CPU intensive queries. 'Mixed' provides tuning that is effective, though not optimized, for both workloads.


num_stmts

Defines the number of statements per unit of work. The default is 25, but may range from 1-1,000,000.


tpm

Defines the expect number of transactions per minute. The default is 60, but may range from 1-50,000.


admin_priority

Defines whether the database should be tuned for better performance (value = 'performance') or better recovery time (value = 'recovery'), or the middle ground (value = 'both'), which is the default.


num_local_apps

Defines the number of connected local applications. The default is 0, but may range from 0-5,000.


num_remote_apps

Defines the number of connections by remote applications. The default is 100, but may range from 0-5,000.


isolation

Defines the transaction isolation level of the applications connecting to the database. The default is RR, but valid values include RR, RS, CS, and UR. Refer to the entry on SET TRANSACTION ISOLATION LEVEL for more details on DB2's isolation levels.


bp_resizeable

Defines whether buffer pools may be resized or not. The default is yes, but it may also be set to no.


APPLY {DB ONLY | DB AND DBM | NONE}

Determines the scope of any autoconfiguration parameters set using the AUTOCONFIGURATION clause:


DB ONLY

Applies changes only to the database configuration and buffer pool settings.


DB AND DBM

Applies settings to the database manager configuration, the database configuration, and the buffer pool settings.


NONE

Displays the recommended settings, but does not apply them.

The tablespace_definition used by DB2 has its own syntax as well:

MANAGED BY

   {SYSTEM USING ('container' [,...] ) |

    DATABASE USING ({FILE | DEVICE} 'container' int [,...] ) }

    [EXTENTSIZE int] [PREFETCHSIZE int] [OVERHEAD int]

    [TRANSFERRATE int]

where:


MANAGED BY

Defines whether the tablespace is managed by a system managed space (SMS) or a database managed space (DMS):


SYSTEM USING ('container' [,...] )

Defines one or more containers for the SMS of up to 240 bytes in length. The container may be an absolute or relative directory name.


DATABASE USING ({FILE | DEVICE} 'container' int [,...] )

Defines one or more containers for the DMS of up to 254 bytes in length. The container may be an absolute or relative directory name. The type of container (FILE for a filename or DEVICE for a pre-existing device) and its size (int), plus a suffix of K (kilobytes), M (megabytes), or G (gigabytes) are also specified. If the file does not exist when specified, DB2 will create one. The device must already exist to be used.


EXTENTSIZE int

Defines the number of pages, int, that are written to the container before skipping to the next container. (The size of the pages is determined by the PAGESIZE setting.) Alternately, the extentsize (int) may be declared in bytes by attaching a suffix of K (kilobytes), M (megabytes), or G (gigabytes) to the integer value.


PREFETCHSIZE int

Defines the number of pages, int, that are read from the tablespace when prefetching data. (The size of the pages are determined by the PAGESIZE setting.) Alternately, the extent size (int) may be declared in bytes by attaching a suffix of K (kilobytes), M (megabytes), or G (gigabytes) to the integer value.


OVERHEAD int

Defines the I/O controller overhead, disk seek, and latency time, in milliseconds, int, used to determine the cost of I/O during query optimization. The value for int should be an average for all containers that belong to the tablespace.


TRANSFERRATE int

Defines the time to read one page into memory, in milliseconds, int, used to determine the cost of I/O during query optimization. The value for int should be an average for all containers that belong to the tablespace.

Note that DB2 tablespaces may also be created using the DB2-specific command CREATE TABLESPACE.

On DB2 servers that are enabled to support Lightweight Directory Access Protocol (LDAP), the new database is automatically registered in the LDAP directory.

DB2 does not support an ALTER DATABASE statement.


The following example creates a database called sales with specifically declared NUMSEGS, DFT_EXTENT_SZ, and AUTOCONFIGURATION enabled and applied:

CREATE DATABASE sales

NUMSEGS 200 DFT_EXTENT_SZ 1000

WITH "Temporary sales database"

AUTOCONFIGURE APPLY DB ONLY;

The WITH clause adds a description of the sales database to the database directory.

MySQL

In MySQL, CREATE DATABASE essentially creates a new directory that holds the database objects:

CREATE DATABASE [IF NOT EXISTS] database_name

where:


CREATE DATABASE database_name

Creates a database and directory of database_name. The database directory appears under the MySQL data directory. Tables in MySQL then appear as files in the database directory.


IF NOT EXISTS

Avoids an error if the database already exists.

For example, we could create a database called sales_archive on a MySQL server. If the database already exists, we want to abort the command without causing an error:

 CREATE DATABASE IF NOT EXISTS sales_archive

Any tables that we create in the sales_archive database will now appear as files within the sales_archive directory.

MySQL does not support an ALTER DATABASE statement.


Oracle

Oracle provides an extraordinary level of control over database file structures beyond merely naming the database and specifying a path for the database files. CREATE and ALTER DATABASE are very powerful commands in Oracle. Some of the more sophisticated clauses are best used only by experienced DBAs. These commands can be very large and complex. (ALTER DATABASE alone consumes over 50 pages in the Oracle vendor documentation!)

Novices should be aware that CREATE DATABASE, when run, erases all data in the specified datafiles that are already in existence. Similarly, all the data in an existing database will be lost.

Following is the syntax to create a new database in Oracle:

CREATE DATABASE [database_name]

{[USER SYS IDENTIFIED BY password | USER SYSTEM IDENTIFIED BY password]}

[CONTROLFILE REUSE]

{[LOGFILE definition [,...] ] [MAXLOGFILES int] [[MAXLOGMEMBERS] int]

   [[MAXLOGHISTORY] int] [{ARCHIVELOG | NOARCHIVELOG}] [FORCE LOGGING]}

[MAXDATAFILES int]

[MAXINSTANCES int]

[CHARACTER SET charset]

[NATIONAL CHARACTER SET charset]

[EXTENT MANAGEMENT {DICTIONARY | LOCAL}]

[DATAFILE definition [,...] ]

[SYSAUX DATAFILE definition [,...] ]

[DEFAULT TABLESPACE tablespace_name

   [DATAFILE file_definition]

   EXTENT MANAGEMENT {DICTIONARY |

      LOCAL {AUTOALLOCATE | UNIFORM [SIZE int [K | M] } } ]

[ [{ BIGFILE | SMALLFILE}] DEFAULT [TEMPORARY] TABLESPACE tablespace_name

   [TEMPFILE file_definition]

   EXTENT MANAGEMENT {DICTIONARY |

      LOCAL {AUTOALLOCATE | UNIFORM [SIZE int [K | M] } } ]

[ [{ BIGFILE | SMALLFILE}] UNDO TABLESPACE tablespace_name

   [DATAFILE temp_datafile_definition] ]

[SET TIME_ZONE = ' { {+ | -} hh:mi | time_zone_region}']

[SET DEFAULT {BIGFILE | SMALLFILE} TABLESPACE]

Following is the syntax to alter an existing database:

ALTER DATABASE [database_name] 

[ARCHIVELOG | NOARCHIVELOG] |

{MOUNT [{STANDBY | CLONE} DATABASE] |

   OPEN [READ WRITE | READ ONLY

      [RESETLOGS | NORESETLOGS] | [UPGRADE | DOWNGRADE] } |

{ACTIVATE [PHYSICAL | LOGICAL] STANDBY DATABASE

      [SKIP [STANDBY LOGFILE] ] |

   SET STANDBY [DATABASE] TO MAXIMIZE {PROTECTION | AVAILABILITY |

      PERFORMANCE} |

   REGISTER [OR REPLACE] [PHYSICAL | LOGICAL] LOGFILE ['file']

      [FOR logminer_session_name] |

   {COMMIT | PREPARE} TO SWITCHOVER TO

      {{[PHYSICAL | LOGICAL] PRIMARY | STANDBY} [WITH[OUT]

         SESSION SHUTDOWN] [WAIT | NOWAIT]} |

      CANCEL} |

   START LOGICAL STANDBY APPLY [IMMEDIATE] [NODELAY]

      [{INITIAL int | NEW PRIMARY dblink_name | {FINISH |

         SKIP FAILED TRANSACTION] } ] |

   {STOP | ABORT} LOGICAL STANDBY APPLY |

   [[NO]PARALLEL int] } |

{RENAME GLOBAL_NAME TO database[.domain[.domain ...]] |

   CHARACTER SET character_set |

   NATIONAL CHARACTER SET character_set |

   DEFAULT TABLESPACE tablespace_name |

   DEFAULT TEMPORARY TABLESPACE {GROUP int | tablespace_name} |

   {DISABLE BLOCK CHANGE TRACKING | ENABLE BLOCK CHANGE TRACKING [USING

      FILE 'file' [REUSE] } |

   FLASHBACK {ON | OFF} |

   SET TIME_ZONE = '{ {+ | -} hh:mi | time_zone_region}' |

   SET DEFAULT {BIGFILE | SMALLFILE} TABLESPACE } |

{ENABLE | DISABLE} { [PUBLIC] THREAD int | INSTANCE 'instance_name' } |

{GUARD {ALL | STANDBY | NONE} } |

{CREATE DATAFILE 'file' [,...] [AS {NEW | file_definition [,...] } ] |

   {DATAFILE 'file' | TEMPFILE 'file'} [,...]

      {ONLINE | OFFLINE [FOR DROP | RESIZE int [K | M] |

         END BACKUP | AUTOEXTEND {OFF | ON [NEXT int [K | M] [MAXSIZE

         [UNLIMITED | int [K | M] } |

   {TEMPFILE 'file' | TEMPFILE 'file'} [,...]

      {ONLINE | OFFLINE | DROP [INCLUDING DATAFILES] |

         RESIZE int [K | M] | AUTOEXTEND {OFF | ON [NEXT int [K | M]

         [MAXSIZE [UNLIMITED | int [K | M] } |

   RENAME FILE 'file' [,...] TO 'new_file_name' [,...] } |

{[[NO] FORCE LOGGING] | [ [NO]ARCHIVELOG [MANUAL] ] |

      [ADD | DROP] SUPPLEMENTAL LOG DATA [(ALL | PRIMARY KEY | UNIQUE |

         FOREIGN KEY) [,...] ] COLUMNS |

      [ADD | DROP] [STANDBY] LOGFILE

         {{[THREAD int | INSTANCE 'instance_name']} {[GROUP int |

             logfile_name [,...]} [SIZE [K | M]] | [REUSE]  |

         [MEMBER] 'file' [REUSE] [,...] TO logfile_name [,...]} |

      ADD LOGFILE MEMBER 'file' [RESUSE] [,...] TO {[GROUP int |

         logfile_name [,...]} |

      DROP [STANDBY] LOGFILE {MEMBER 'file' | {[GROUP int | logfile_name

         [,...]} }

      CLEAR [UNARCHIVED] LOGFILE {[GROUP int | logfile_name [,...]} [,...]

         [UNRECOVERABLE DATAFILE] } |

{CREATE [LOGICAL | PHYSICAL] STANDBY CONTROLFILE AS 'file' [REUSE] |

   BACKUP CONTROLFILE TO

      {'file' [REUSE] | TRACE [AS 'file' [REUSE] ] {RESETLOGS |

         NORESETLOGS]} } |

{RECOVER

   {[AUTOMATIC [FROM 'location'] ]  |

      {[STANDBY] DATABASE

         {[UNTIL {CANCEL | TIME date | CHANGE int}] |

         USING BACKUP CONTROLFILE } |

      {{[STANDBY] {TABLESPACE tablespace_name [,...] | DATAFILE

         'file' [,...] } [UNTIL [CONSISTENT WITH] CONTROLFILE]} |

         TABLESPACE tablespace_name [,...] | DATAFILE 'file' [,...]} |

      LOGFILE filename [,...] } [{TEST | ALLOW int CORRUPTION | [NO]PARALLEL

         int}]} |

      CONTINUE [DEFAULT] |

      CANCEL [IMMEDIATE][NOWAIT] }

   {MANAGED STANDBY DATABASE

      {[[NO]TIMEOUT int] [{[NO]DELAY int | DEFAULT DELAY}] [NEXT int]

         [[NO]EXPIRE int] [{[NO]PARALLEL int}] [USING CURRENT LOGFILE]

         [UNTIL CHANGE int]

         [THROUGH

            {ALL ARCHIVELOG | {ALL | LAST | NEXT} SWITCHOVER |

            [[THREAD int] SEQUENCE int ] } |

      [CANCEL [IMMEDIATE] [{WAIT | NOWAIT}] ] |

      [DISCONNECT [FROM SESSION] [{[NO]PARALLEL int}]

         FINISH [SKIP [STANDBY LOGFILE]] [{WAIT | NOWAIT}] ] |

{BEGIN | END} BACKUP} }

The syntax elements in Oracle are as follows:


{CREATE | ALTER} DATABASE database_name

Creates or alters a database with the name database_name. The database name can be up to 8 bytes in length and may not contain European or Asian characters. You can omit a database name and allow Oracle to create a database name for you, but beware that Oracle can create some counter-intuitive names.


USER SYS IDENTIFIED BY password

 


USER SYSTEM IDENTIFIED BY password

Specifies passwords for the SYS and SYSTEM users. You may specify neither or both of these clauses, but not just one of them.


CONTROLFILE REUSE

Causes existing control files to be reused, enabling you to specify existing files in the CONTROL_FILES parameter in INIT.ORA. Oracle will then overwrite any information those files may contain. This clause is normally used when recreating a database. Consequently, you probably don't want to use this clause in conjunction with MAXLOGFILES, MAXLOGMEMBER, MAXLOGHISTORY, MAXDATAFILES, or MAXINSTANCES.


LOGFILE definition

Specifies one or more logfiles for the database. You may define multiple files all with the same size and characteristics, using the file parameter, or you may define multiple files, each with its own size and characteristics. The entire logfile definition syntax is rather ponderous, but offers a great deal of control:

LOGFILE { ('file' [,...]) [SIZE int [K | M]

[GROUP int] [REUSE]} [,...]

where:


LOGFILE ('file' [,...])

Defines one or more files that will act as redo logfiles; file is both the filename and path. Any files defined in the CREATE DATABASE statement are assigned to redo log thread number 1. When specifying multiple redo logfiles, each filename should be enclosed in single quotes and separated from the other names by commas. The entire list should be enclosed in parentheses.


SIZE int [K | M]

Specifies the size of the redo logfile in bytes as an integer value, int. Alternately, you may define the redo logfile in large units than bytes by appending a K (for kilobytes) or an M (for megabytes).


GROUP int

Defines the integer ID, int, of the redo logfile group. The value may be from 1 to the value of the MAXLOGFILES clause. An Oracle database must have at least two redo logfile groups. Oracle will create a redo logfile group for you, at 100 MB each, if you leave off this group ID.


REUSE

Reuses an existing redo logfile.


MAXLOGFILES int

Sets the maximum number of logfiles, int, available to the database being created. The minimum, maximum, and default for this clause are OS-dependent.


MAXLOGMEMBERS int

Sets the maximum number of members (i.e., copies) for a redo logfile group. The minimum value is 1 while the maximum and default values for this clause are OS-dependent.


MAXLOGHISTORY int

Sets the maximum number of archived redo logfiles available to a Real Application Cluster. You can use the MAXLOGHISTORY clause only when Oracle is in ARCHIVELOG mode on a Real Application Cluster. The minimum value is 0 while the maximum and default values for this clause are OS-dependent.


ARCHIVELOG | NOARCHIVELOG

Defines how redo logs operate. When used with ALTER DATABASE, allows the current setting to be changed. ARCHIVELOG saves data stored in the redo log(s) to an archiving file, providing for media recoverability. Conversely, NOARCHIVELOG allows a redo log to be reused without archiving the contents. Both options provide recoverability, although NOARCHIVELOG (the default) does not provide media recovery.


FORCE LOGGING

Places all instances of the database into FORCE LOGGING mode, in which all changes to the database are logged, except for changes to temporary tablespaces and segments. This setting takes precedence over any tablespace- or object-level settings.


MAXDATAFILES int

Sets the initial number of datafiles, int, available to the database being created. Note that the INIT.ORA setting, DB_FILES, also limits the number of datafiles accessible to the database instance.


MAXINSTANCES int

Sets the maximum number of instances, int, which may mount and open the database being created. The minimum value is 1 while the maximum and default values for this clause are OS-dependent.


CHARACTER SET charset

Controls the language character set in which the data is stored. The value for charset cannot be AL16UTF16. The value of charset is OS-dependent.


NATIONAL CHARACTER SET charset

Controls the national language character set for data stored in NCHAR, NCLOB, and NVARCHAR2 columns. The value for charset must be either AL16UTF16 (the default) or UTF8.


EXTENT MANAGEMENT {DICTIONARY | LOCAL}

Creates a locally managed SYSTEM tablespace, otherwise the SYSTEM tablespace will be dictionary managed. This clause requires a default temporary tablespace. If you omit a DATAFILE clause, you can also omit a default temporary tablespace because Oracle will create them both for you.


DATAFILE definition

Specifies one or more datafiles for the database. (All these datafiles become part of the SYSTEM tablespace.) You may repeat filenames to define multiple files all with the same size and characteristics. Alternately, you may repeat the entire DATAFILE clause, with each occurrence defining one or more files with the same size and characteristics. The entire datafile definition syntax is rather large, but offers a great deal of control:

DATAFILE {('file1' [,...]) [GROUP int] [SIZE int [K | M] [REUSE]

[AUTOEXTEND [OFF | ON [NEXT int [K | M]

[MAXSIZE [UNLIMITED | int [K | M]] } [,...]

where:


DATAFILE ('file1' [,...])

Defines one or more files that will act as the datafile(s), where file1 is both the filename and path. For multiple files, each filename should be enclosed in single-quotes and separated by a comma. The entire list should be enclosed in parentheses.


GROUP int

Defines the integer ID, int, of the datafile group. The value may be from 1 to the value of MAXLOGFILES clause. An Oracle database must have at least two datafile groups. Oracle will create them for you, at 100 MB each, if you leave off this clause.


SIZE int [K | M]

Specifies the size of the datafile in bytes as an integer value, int. Alternately, you may define the datafile in large units by appending a K (for kilobytes) or an M (for megabytes).


REUSE

Reuses the existing datafile.


AUTOEXTEND

Enables (ON) the automatic extension of new or existing data or temp files (but does not redo logfiles). NEXT specifies the next increment of space allocated to the file in bytes, kilobytes (K), or megabytes (M) when more space is needed.


MAXSIZE [UNLIMITED | int [K | M]]

Specifies the maximum disk space allowed for automatic extension of the file. UNLIMITED allows the file to grow without an upper limit, except of course the total capacity of the drive. Otherwise, you may define the maximum size limit as an integer, int, in bytes (the default), kilobytes with the keyword K, and megabytes with the keyword M.


SYSAUX DATAFILE definition

Specifies one or more datafiles for the SYSAUX tablespace. By default, Oracle creates and manages the SYSTEM and SYSAUX tablespaces automatically. You must use this clause if you have specified a datafile for the SYSTEM tablespace. If you omit the SYSAUX clause when using Oracle-managed files, then Oracle will create the SYSAUX tablespace as an online, permanent, locally managed tablespace with a single datafile of 100 MB, using automatic segment-space management and logging.


BIGFILE | SMALLFILE

Specifies the default file type of a subsequently created tablespace. BIGFILE indicating the tablespace will contain a single datafile or tempfile of up to 8 exabytes (8 million terabytes) in size, while SMALLFILE indicates the tablespace is a traditional Oracle tablespace. The default, when omitted, is SMALLFILE.


DEFAULT TABLESPACE tablespace_name

Specifies a default permanent tablespace for the database for all non-SYSTEM users. When this clause is omitted, the SYSTEM tablespace is the default permanent tablespace for non-SYSTEM users. The EXTENT MANAGEMENT clause has the same syntax as in the DEFAULT TEMPORARY TABLESPACE clause appearing later.


DEFAULT TEMPORARY TABLESPACE tablespace_name [TEMPFILE file_definition]

Defines the name and location of the default temporary tablespace for the database. Users who are not explicitly assigned to a temporary tablespace will operate in this one. If you don't create a default temporary tablespace, Oracle uses the SYSTEM tablespace. Under ALTER DATABASE, this clause allows you to change the default temporary tablespace.


TEMPFILE file_definition

The tempfile definition is optional when the DB_CREATE_FILE_DEST INIT.ORA parameter is set. Otherwise, you'll have to define the tempfile yourself. The TEMPFILE definition syntax is otherwise identical to the DATAFILE definition syntax earlier in this section.


EXTENT MANAGEMENT {DICTIONARY | LOCAL {AUTOALLOCATE | UNIFORM [SIZE int [K | M]}}

Defines the way in which the SYSTEM tablespace is managed. When this clause is omitted, the SYSTEM tablespace is dictionary-managed. Once created as a locally managed tablespace, it cannot be converted back to a dictionary-managed tablespace, nor can any new dictionary-managed tablespaces be created in the database.


DICTIONARY

Specifies that the Oracle data dictionary manages the tablespace. This is the default. The AUTOALLOCATE and UNIFORM subclauses are not used with this clause.


LOCAL

Declares that the tablespace is locally managed. This clause is optional since all temporary tablespaces have locally managed extents by default. Use of this clause requires a default temporary tablespace. If you do not manually create one, Oracle will automatically create one called TEMP of 10 MB size with autoextend disabled.


AUTOALLOCATE

Specifies that new extents will be allocated as needed by the locally managed tablespace.


UNIFORM [SIZE int [K | M] ]

Specifies that all extents of the tablespace are the same size (UNIFORM), in bytes, as int. The SIZE clause allows you to configure the size of the extents to your liking in bytes (the default), in kilobytes using the keyword K, or in megabytes using the keyword M. The default is 1M.


UNDO TABLESPACE tablespace_name [DATAFILE temp_datafile_definition]

Defines the name and location for undo data, creating a tablespace named tablespace_name, but only if you have set the UNDO_MANAGEMENT INIT.ORA parameter to AUTO. If you don't use this clause, Oracle manages undo space via rollback segments. (You may also set the INIT.ORA parameter to UNDO_TABLESPACE. If so, the value of the parameter and the tablespace_name used here must be identical.)

where:


DATAFILE temp_datafile_definition

Creates and assigns the datafile, as you have defined it, to the undo tablespace. Refer to the earlier section on DATAFILE for the full syntax on this clause. This clause is required if you have not specified a value for the INIT.ORA parameter DB_CREATE_FILE_DEST.


SET TIME_ZONE = ' { {+ | -} hh:mi | time_zone_region}'

Sets the time zone for the database, either by specifying a delta from Greenwich Mean Time (now called Coordinated Universal Time) or by specifying a time zone region. (For a list of time zone regions, query the tzname column of the v$timezone_names view.) If you do not use this clause, Oracle defaults to the operating-system time zone.


SET DEFAULT TABLESPACE

Sets all tablespaces created by the current CREATE DATABASE or ALTER DATABASE statement as either BIGFILE or SMALLFILE. When creating databases, this clause also applies to the SYSTEM and SYSAUX tablespaces.


MOUNT [[{STANDBY} | CLONE] DATABASE]

Mounts a database for users to access. The STANDBY keyword mounts a physical standby database, enabling it to receive archived redo logs from the primary instance. The CLONE keyword mounts a clone database. This clause cannot be used with OPEN.


OPEN [READ WRITE | READ ONLY] [RESETLOGS | NORESETLOGS] [UPGRADE | DOWNGRADE]

Opens the database separately from the mounting process. (Mount the database first.) READ WRITE opens the database in read/write mode, allowing users to generate redo logs. READ ONLY allows reads but disallows changes to redo logs. RESETLOGS discards all redo information not applied during recovery and sets the log sequence number to 1. NORESETLOGS retains the logs in their present condition. The optional UPGRADE and DOWNGRADE clauses tell Oracle to dynamically modify the system parameters as required for database upgrade or downgrade, respectively. The default is OPEN READWRITE NORESETLOGS.


ACTIVATE [PHYSICAL | LOGICAL] STANDBY DATABASE [SKIP [STANDBY LOGFILE] ]

Promotes a standby database to the primary database. You can optionally specify a PHYSICAL standby, the default, or a LOGICAL standby. Use the SKIP clause to immediately promote a physical standby and discard any data still unapplied by the RECOVER MANAGED STANDBY DATABASE FINISH statement. The clause STANDBY LOGFILE is noise.


SET STANDBY [DATABASE] TO MAXIMIZE {PROTECTION | AVAILABILITY | PERFORMANCE}

Sets the level of protection for data in the primary database. The old terms PROTECTED and UNPROTECTED equate to TO MAXIMIZE PROTECTION and MAXIMIZE PERFORMANCE, respectively, where:


PROTECTION

Provides the highest level of data protection, but has the greater overhead and negatively impacts availability. This setting commits transactions only after all data necessary for recovery has been physically written in at least one physical standby database that uses SYNC log transport mode.


AVAILABILITY

Provides the second highest level of data protection, but the highest level of availability. This setting commits transactions only after all data necessary for recovery has been physically written in at least one physical or logical standby database that uses SYNC log transport mode.


PERFORMANCE

Provides the highest level of performance, but compromises data protection and availability. This setting commits transactions before all data necessary for recovery has been physically written to a standby database.


REGISTER [OR REPLACE] [PHYSICAL | LOGICAL] LOGFILE ['file']

Manually registers redo logfiles from a failed primary server when issued from a standby server. The logfile may optionally be declared as PHYSICAL or LOGICAL. The OR REPLACE clause allows updates to details for an existing archivelog entry.


FOR logminer_session_name

Registers the logfile with a single, specific LogMiner session in an Oracle Streams environment.


{COMMIT | PREPARE} TO SWITCHOVER TO {[PHYSICAL | LOGICAL] PRIMARY | STANDBY}

Performs a graceful switchover, moving the current primary database to standby status and promoting a standby database to primary. (In a RAC environment, all instances other than the current instance have to be shutdown.) To gracefully switch over, you should issue the command twice, once to prepare the primary and standby databases to begin exchanging logfiles in advance of the switchover using PREPARE TO SWITCHOVER. To demote the primary database and switchover of the standby databases, use COMMIT TO SWITCHOVER. The PHYSICAL clause puts the primary database into physical standby mode. The LOGICAL clause puts the primary database into logical standby mode. However, you must then issue an ALTER DATABASE START LOGICAL STANDBY APPLY statement.


WITH[OUT] SESSION SHUTDOWN] [WAIT | NOWAIT]

WITH SESSION SHUTDOWN closes any open application sessions and rolls back any uncommitted transactions during a switchover of physical databases (but not logical ones). WITHOUT SESSION SHUTDOWN, the default, causes the COMMIT TO SWITCHOVER statement to fail if it encounters any open application sessions. WAIT returns control to the console after completion of the SWITCHOVER command, while NOWAIT returns control before the command completes.


START LOGICAL STANDBY APPLY [IMMEDIATE][NODELAY][{INITIAL int | NEW PRIMARY dblink_name}
| {FINISH | SKIP} FAILED TRANSACTIONS}]

Starts to apply redo logs to the logical standby database. IMMEDIATE tells the Oracle LogMiner to read the redo data in the standby redo logfiles. NODELAY tells Oracle to ignore a delay for the apply, such as when the primary database is unavailable or disabled. INITIAL is used the first time you apply logs to the standby database. NEW PRIMARY is required after a switchover has completed or after a standby database has processed all redo logs and another standby is promoted to primary. Use SKIP FAILED TRANSACTION to skip the last transaction and to restart the apply. Use FINISH to apply the data in the redo logs if the primary database is disabled.


[STOP | ABORT] LOGICAL STANDBY APPLY

Stops the application of redo logs to a logical standby server. STOP performs an orderly stop, while ABORT performs an immediate stop.


[NO]PARALLEL [int]

[NO]PARALLEL determines whether parallel recovery of media is used. NOPARALLEL is the default and enforces serial reading of the media. PARALLEL with no int value tells Oracle to choose the degree of parallelism to apply. Specifying int declares the degree of parallelism to apply.


RENAME GLOBAL_NAME TO database[.domain[.domain ...]]

Changes the global name of the database, where database is the new name of up to 8 bytes in length. The optional domain specifications identify the database's location in the network. This does not propagate database name changes to any dependent objects like synonyms, stored procedures, etc.


{DISABLE | ENABLE} BLOCK CHANGE TRACKING [USING FILE 'file'] [REUSE]

Tells Oracle to stop or start tracking the physical location of all database updates, respectively, and maintain the information in a special file called the block change tracking file. Oracle will automatically create the file as defined by the DB_CREATE_FILE_DEST parameter, unless you add the USING FILE 'file' clause, where 'file' is the path and name of the file. REUSE tells Oracle to overwrite an existing block change tracking file of the same name as 'file'. The USING and REUSE subclauses are only allowed with the ENABLE BLOCK clause.


FLASHBACK {ON | OFF}

Places the database in or out of FLASHBACK mode, respectively. When in flashback mode, an Oracle database automatically creates and maintains flashback database logs in the flash recovery area. When OFF, the flashback database logs are deleted and unavailable.


SET TIME ZONE

Specifies the time zone for the server. Refer to the SET TIME ZONE statement for more information.


ENABLE [PUBLIC] THREAD int | DISABLE THREAD int | INSTANCE 'instance_name'

In Real Application Cluster (RAC) environments, you can ENABLE or DISABLE a redo log thread by number (int). You may optionally specify an instance_name to enable or disable a thread mapped to a specific database instance of an Oracle Real Application Cluster environment. The instance_name may be up to 80 characters long. The PUBLIC keyword makes the thread available to any instance. When omitted, the thread is only available when explicitly requested. To enable a thread, the thread must have at least two redo logfile groups. To disable a thread, the database must be open but not mounted by an instance using the thread.


GUARD {ALL | STANDBY | NONE}

Protects the data in a database from changes. ALL prevents users other than SYS from making changes. STANDBY prevents all users other than SYS from making changes in a logical standby. NONE provides normal security for the database.


CREATE DATAFILE 'file' [,...] [AS {NEW | file_definition}]

Creates a new empty datafile, replacing an existing one. The value 'file' identifies a file (either by filename or file number) that was lost or damaged without a backup. AS NEW creates a new file in the default filesystem using an Oracle-supplied name. AS file_definition allows you to specify a filename and sizing details, as defined under the file_definition section earlier in the list.


DATAFILE 'file' | TEMPFILE 'file' [,...] {ONLINE | OFFLINE [FOR DROP]}
| RESIZE int [K | M] | AUTOEXTEND {OFF | ON [NEXT
int [K | M]} [MAXSIZE [UNLIMITED | int [K | M]]} {END BACKUP [INCLUDING DATAFILES}]

Changes the attributes, such as the size, of one or more existing datafiles or tempfiles. You may alter one or more files in a comma-delimited list, identified in the value 'file' by filename or file number. Do not mix datafile and tempfile declarations; only one or the other should appear in this clause at a time, where:


ONLINE

Sets the file online.


OFFLINE [FOR DROP]

Sets the file offline allowing media recovery. FOR DROP is required to take a file offline in NOARCHIVELOG mode, but does not actually destroy the file. It is ignored in ARCHIVELOG mode.


RESIZE int [K | M]

Sets a new size for an existing datafile or tempfile.


END BACKUP

Described later in the list under END BACKUP. Used only with the DATAFILE clause.


DROP INCLUDING DATAFILES

Drops not only the tempfile, but all datafiles on the filesystem associated with the tempfile. Oracle also adds an entry to the alert log for each file that is erased. Used only with the TEMPFILE clause.


AUTOEXTEND {OFF | ON [NEXT int [K | M] [MAXSIZE [UNLIMITED | int [K | M] }

Described earlier in the list under DATAFILE definition.


RENAME FILE 'file' [,...] TO 'new_file_name' [,...]

Renames a datafile, tempfile, or redo logfile member from the old name, 'file', to the 'new_file_name'. You can rename multiple files at once by specifying multiple old and new filenames. This command does not rename files at the operating system level. Rather, it specifies new names that Oracle will use to open the files. You need to rename at the operating system level yourself.


[NO] FORCE LOGGING

Puts the database into force logging mode (FORCE LOGGING) or takes it out of force logging mode (NO FORCE LOGGING). In the former, Oracle logs all changes to the database except in temporary tablespaces or segments. This database-level FORCE LOGGING setting supersedes all tablespace level declarations regarding force logging mode.


[NO]ARCHIVELOG [MANUAL]

Tells Oracle to create redo logfiles, but the user will handle the archiving of the redo logfiles explicitly. It is used only with the ALTER DATABASE statement and only for backward compatibility for users with older tape backup systems. When this clause is omitted, Oracle defaults the redo logfile destination to the LOG_ARCHIVE_DEST_n initialization parameter.


[ADD | DROP] SUPPLEMENTAL LOG DATA [ (ALL | PRIMARY KEY | UNIQUE | FOREIGN KEY) [,...] COLUMNS ]

ADD places additional column data into the log stream whenever an update is executed. It also enables minimal supplemental logging, which ensures that LogMiner can support chained rows and special storage arrangements like clustered tables. Supplemental logging is disabled by default. You can add the clauses PRIMARY KEY COLUMNS, UNIQUE KEY COLUMNS, FOREIGN KEY COLUMNS, or ALL (to get all three earlier options), if you need to enable full referential integrity via foreign keys in another database, such as a logical standby. In either case, Oracle places either the primary key columns, unique key columns (or where none exist, a combination of columns that uniquely identify each row), foreign key columns, or all three into the log. DROP tells Oracle to suspend supplemental logging.


[ADD | DROP] [STANDBY] LOGFILE [THREAD int] [GROUP int] [MEMBER] 'file' [,...]

ADD adds one or more primary or standby redo logfile groups to the specified instance. THREAD assigns the added files to a specific thread number (int) on a Real Application Cluster. When omitted, the default is the thread assigned to the current instance. GROUP assigns the redo logfile groups to a specific group within the thread. MEMBER adds the specified 'file' (or files in a comma-delimited list) to an existing redo logfile group. DROP LOGFILE MEMBER drops one or more redo logfile members, after issuing an ALTER SYSTEM SWITCH LOGFILE statement.


CLEAR [UNARCHIVED] LOGFILE GROUP int logfile_name [,...] [UNRECOVERABLE DATAFILE] }

Reinitializes one or more specified online redo logs. Specify the logs in a comma-delimited list. UNARCHIVED skips archiving the redo logs. UNRECOVERABLE DATAFILE is required when any datafile is offline and the database is in ARCHIVELOG mode.


CREATE {LOGICAL | PHYSICAL} STANDBY CONTROLFILE AS 'file' [REUSE]}

Creates a control file that maintains a logical or physical standby database. REUSE is needed if the file already exists.


BACKUP CONTROLFILE TO {'file' [REUSE] | TRACE [AS 'file' [REUSE] ] [RESETLOGS | NORESETLOGS]

Backs up the current control file of an open or mounted database. TO 'file' identifies a full path and filename for the control file. TO TRACE writes SQL statements to recreate the control file to a trace file. TO TRACE AS 'file' writes all the SQL statements to a standard file rather than a trace file. REUSE is needed if the file already exists. RESETLOGS initializes the trace file with the statement ALTER DATABASE OPEN RESETLOGS, and is only valid when online logs are unavailable. NORESETLOGS initializes the trace file with the statement ALTER DATABASE OPEN NORESETLOGS and is only valid when online logs are available.


RECOVER

Controls media recovery for the database, standby database, tablespace, or file. In Oracle, the ALTER TABLE command is one of the primary means of recovering a damaged or disabled database, file, or tablespace. Use RECOVER when the database is mounted (in exclusive mode), the files and tablespaces involved are not in use (offline), and the database is in either an open or closed state. The entire database can be recovered only when it is closed, but specific files or tablespaces can be recovered in a database that is open.


AUTOMATIC [FROM 'location']

Tells Oracle to automatically generate the name of the next archived redo logfile necessary for continued operation during recovery. Oracle will prompt you if it cannot find the next file. The FROM 'location' clause tells Oracle where to find the archived redo logfile group. The following subclauses may be applied to an automatically recovered database.


STANDBY

Specifies that the database or tablespace to recover is a standby type.


DATABASE {UNTIL {CANCEL | TIME date | CHANGE int} | USING BACKUP CONTROLFILE }

Tells Oracle to recover the entire database. The UNTIL keyword tells Oracle to continue recovery until ALTER DATABASE...RECOVER CANCEL (CANCEL) is issued, until a specified time is reached (TIME) in the format YYYY-MM-DD:HH24:MI:SS, or until a specific system change number (CHANGE int) is reached where int is the number. The clause USING BACKUP CONTROLFILE enables use of the backup, rather than current, control file.


[STANDBY] TABLESPACE tablespace_name [,...] | DATAFILE 'file' [,...]

Recovers one or more specific tablespaces or datafiles, respectively. You may specify more than one tablespace or datafile using a comma-delimited list. You may also recover a datafile by datafile number, rather than by name. The tablespace may be in normal or standby mode. The standby tablespace or datafile is reconstructed using archived redo logfiles copied from the primary database and a control file.


UNTIL [CONSISTENT WITH] CONTROLFILE

Tells Oracle to recover an older standby tablespace or datafile by using the current standby control file. CONSISTENT WITH are noise words.


LOGFILE filename [,...]

Continues media recovery by applying one or more redo logfiles that you specify in a comma-delimited list.


TEST | ALLOW int CORRUPTION | [NO]PARALLEL int

TEST performs a trial recovery, allowing you to foresee any problems. ALLOW int CORRUPTION tells how many corrupt blocks (int) to tolerate before causing recovery to abort. Int must be 1 for a real recovery, but may be any number you chose when paired with TEST. Parallelism is described earlier in the list.


CONTINUE [DEFAULT]

Determines whether multi-instance recovery continues after interruption. CONTINUE DEFAULT is the same as RECOVER AUTOMATIC, but does not result in a prompt for a filename.


CANCEL [IMMEDIATE][[NO]WAIT]

Cancels a managed recovery operation at the next archived log boundary, if it was started with the USING CANCEL clause. The IMMEDIATE keyword cancels the managed recovery in process after the current I/O or archived log boundary, whichever is first. NOWAIT cancels the recovery immediately without regard to current work in process, while WAIT allows current work to complete normally.


MANAGED STANDBY DATABASE

Specifies managed physical standby recovery mode on an active component of a standby database. This command is used for media recovery only and not to construct a new database, using the following parameters:


[NO]TIMEOUT int

TIMEOUT specifies, in minutes (int), how long the foreground managed recovery operation will wait for the next available redo log before timing out. NOTIMEOUT, the default, tells Oracle to wait indefinitely for the next redo log, or until the instance is shutdown, or until RECOVER CANCEL is issued.


CANCEL [IMMEDIATE][[NO]WAIT]

Described earlier.


[NO]DELAY int | DEFAULT DELAY int

Tells, in minutes (int), how long Oracle should wait to apply an archived redo log after it has been selected for recovery. DEFAULT DELAY tells Oracle to use the delay specified by the LOG_ARCHIVE_DEST_n INIT.ORA parameter. NODELAY tells Oracle to apply the archived redo log immediately.


NEXT int

Tells Oracle to apply the int next archived redo logs as soon as possible after they have been archived. Incompatible with FINISH.


[NO]EXPIRE int

Tells Oracle, in minutes (int), when to automatically terminate a managed recovery relative to the time the recovery started. NOEXPIRE disables a previously set EXPIRE value. Incompatible with FINISH.


USING CURRENT LOGFILE

Invokes real time apply, which allows recovery of redos from standby online logs as they are being filled, without first requiring that they be archived by the standby database.


UNTIL CHANGE int

Conducts a managed recovery up to (but not including) the specified system change number called int.


THROUGH {ALL ARCHIVELOG | {ALL | LAST | NEXT} SWITCHOVER | [THREAD int] SEQUENCE int}

Tells Oracle when to terminate managed recovery to a standby server. THROUGH ALL ARCHIVELOG, the default, continues managed recovery until all archivelogs are recovered. THROUGH...SWITCHOVER controls the termination of managed recovery when Oracle switches over to a secondary standby server. ALL keeps managed recovery in operation through any switchovers. LAST terminates managed recovery after receiving the final end-of-redo indicator. NEXT terminates managed recovery after receiving the next end-of-redo indicator. THROUGH...SEQUENCE tells Oracle to terminate managed recovery when it encounters a specific THREAD number and/or SEQUENCE number.


DISCONNECT [FROM SESSION] [[NO]PARALLEL int]

Causes the managed redo process to occur in the background, leaving the current process available for other tasks. FROM SESSION are noise words. DISCONNECT is incompatible with TIMEOUT.


FINISH [SKIP [STANDBY LOGFILE]] [{WAIT | NOWAIT}]]

Recovers the current physical standby online redo logfiles in preparation of the standby assuming the primary database role when the primary database has failed. The FINISH clause, when used without any other keywords, is known as a terminal recovery. The optional clause SKIP [STANDBY LOGFILE] allows the standby to prepare for the primary role when standby online redo logfiles are not available. The FINISH SKIP clause, when used without any other keywords, is known as a terminal incomplete recovery. WAIT tells Oracle to return control after completing the recovery process, while NOWAIT returns control immediately. Incompatible with TIMEOUT, DELAY, EXPIRE, and NEXT.


{BEGIN | END} BACKUP

Controls online backup mode for any datafiles. BEGIN places all datafiles into online backup mode. The database must be mounted and open, in archivelog mode with media recovery enabled. (Note that while the database is in online backup mode the instance cannot be shutdown, and individual tablespaces cannot be backed up, taken offline, or made read only.) END takes all datafiles currently in online backup mode out of that mode. The database must be mounted, but need not be open.

After that long discussion of specific syntax, it's important to establish some Oracle basics.

Oracle allows the use of primary and standby databases. A primary database is a mounted and open database accessible to users. The primary database then ships its redo logs to a standby database where they are recovered, thus making the standby database a very up-to-date copy of the primary.

Unique to the Oracle environment is the INIT.ORA file, which specifies the database name and a variety of other options when creating and starting up the database. You should always define startup parameters, such as the name of any control files, in the INIT.ORA file to identify the control files or else the database will not start. Starting in Oracle 9.1, you can use binary parameter files rather than INIT.ORA files.

When a group of logfiles is listed, they are usually shown in parentheses. The parentheses aren't needed when creating a group with only one member, but this is seldom done. Here's an example using a parenthetical list of logfiles:

CREATE DATABASE publications

LOGFILE ('/s01/oradata/loga01','/s01/oradata/loga02') SIZE 5M

DATAFILE;

The example above creates a database called publications with an explicitly defined logfile clause and an automatically created datafile. The following example of an Oracle CREATE DATABASE command is much more sophisticated:

CREATE DATABASE sales_reporting

CONTROLFILE REUSE

LOGFILE

   GROUP 1 ('diskE:log01.log', 'diskF:log01.log') SIZE 15M,

   GROUP 2 ('diskE:log02.log', 'diskF:log02.log') SIZE 15M

MAXLOGFILES 5

MAXLOGHISTORY 100

MAXDATAFILES 10

MAXINSTANCES 2

ARCHIVELOG

CHARACTER SET AL32UTF8

NATIONAL CHARACTER SET AL16UTF16

DATAFILE

   'diskE:sales_rpt1.dbf' AUTOEXTEND ON,

   'diskF:sales_rpt2.dbf' AUTOEXTEND ON NEXT 25M MAXSIZE UNLIMITED

DEFAULT TEMPORARY TABLESPACE temp_tblspc

UNDO TABLESPACE undo_tblspc

SET TIME_ZONE = '-08:00';

This example defines log and data files, as well as all appropriate character sets. We also define a few characteristics for the database, such as the use of ARCHIVELOG mode and CONTROLFILE REUSE mode, the time zone, maximum number of instances, datafiles, etc. The example also assumes that the INIT.ORA parameter for DB_CREATE_FILE_DEST has already been set. Thus, we don't have to define file definitions for the DEFAULT TEMPORARY TABLESPACE and UNDO TABLESPACE clauses.

When issued by a user with SYSDBA privileges, this statement creates a database and makes it available to users in either exclusive or parallel mode, as defined by the value of the CLUSTER_DATABASE initialization parameter. Any data that exists in predefined datafiles is erased. You will usually want to create tablespaces and rollback segments for the database. (Refer to the vendor documentation for the platform specific commands CREATE TABLESPACE and CREATE ROLLBACK SEGMENT.)

Oracle has tightened up security around default database user accounts. Many default database user accounts are now locked and expired during initial installation. Only SYS, SYSTEM, SCOTT, DBSNMP, OUTLN, AURORA$JIS$UTILITY$, AURORA$ORB$UNAUTHENTICATED, and OSE$HTTP$ADMIN are the same as they were in earlier versions. You must manually unlock and assign a new password to all locked accounts, as well as assign a password to SYS and SYSTEM during the initial installation.

In the next example, we add more logfiles to the current database, then add a datafile:

ALTER DATABASE ADD LOGFILE GROUP 3

   ('diskf: log3.sales_arch_log','diskg:log3.sales_arch_log')

SIZE 50M;

ALTER DATABASE sales_archive

CREATE DATAFILE 'diskF:sales_rpt4.dbf'

AUTOEXTEND ON NEXT 25M MAXSIZE UNLIMITED;

We can set a new default temporary tablespace, as shown in the next example:

ALTER DATABASE DEFAULT TEMPORARY TABLESPACE sales_tbl_spc_2;

Next, we'll perform a simple full database recovery:

ALTER DATABASE sales_archive RECOVER AUTOMATIC DATABASE;

In the next example, we perform a more elaborate partial database recovery:

ALTER DATABASE RECOVER STANDBY DATAFILE 'diskF:sales_rpt4.dbf' 

UNTIL CONTROLFILE;

Now, we'll perform a simple recovery of a standby database in managed standby recovery mode:

ALTER DATABASE RECOVER sales_archive MANAGED STANDBY DATABASE;

In the following example, we gracefully switch over from a primary database to a logical standby, and promote the logical standby to primary:

-- Demotes the current primary to logical standby database.

ALTER DATABASE COMMIT TO SWITCHOVER TO LOGICAL STANDBY;

-- Applies changes to the new standby.

ALTER DATABASE START LOGICAL STANDBY APPLY;

-- Promotes the current standby to primary database.

ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY;

PostgreSQL

PostgreSQL's implementation of the CREATE DATABASE command creates a database and a file location for the datafiles:

CREATE DATABASE database_name

   [ WITH {[LOCATION = 'dbpath' ] [TEMPLATE = tmp_name]

   [ENCODING = enc_value]} ]

Where:


WITH LOCATION = 'dbpath'

Specifies the file path where the database will be located. You can leave off this clause to accept the default location or use the clause WITH LOCATION = DEFAULT. The path must be prepared in advance using the initlocation command (which is a Unix command, not a SQL statement). In general, PostgreSQL uses environmental variable names (an environmental variable name is a pathname without slashes). If you want to specify an absolute file and path name, like /usr/local/pgsql/data01, you must set and compile the server with the ALLOW_ABSOLUTE_DBPATH parameter.


TEMPLATE = tmp_name

Names a template to use for creating the new database. You can leave off this clause to accept the default template describing the location of the database files or use the clause TEMPLATE = DEFAULT. The default is to copy the standard system database template1. You can get a pristine database (one that contains only required database objects) by specifying TEMPLATE = template0.


ENCODING = enc_value

Specifies the multibyte encoding method to use in the new database using either a string literal (such as 'SQL_ASCII'), an integer encoding number, or DEFAULT for the default encoding.

For example, to create the database sales_revenue in the /home/teddy/private_db directory:

CREATE DATABASE sales_revenue WITH LOCATION =

'/home/teddy/private_db';

Be careful using absolute file- and pathnames, since they impact security and data integrity issues.

PostgreSQL advises that databases used as templates be treated as read-only. Template databases should not be used for general purpose "copy database" functionality.

PostgreSQL does not support the ALTER DATABASE command.


SQL Server

SQL Server offers a high degree of control over the OS filesystem structures that hold the database and its objects. The syntax for Microsoft SQL Server's CREATE DATABASE statement looks like this:

CREATE DATABASE database_name

[ ON file_definition [,...] ]

[, FILEGROUP filegroup_name file_definition [,...] ]

[ LOG ON file_definition [,...] ]

[ COLLATE collation_name]

[ FOR LOAD | FOR ATTACH ]

Following is the syntax for ALTER DATABASE:

ALTER DATABASE database_name

{ADD FILE file_definition [,...] [TO FILEGROUP filegroup_name]

| ADD LOG FILE file_definition [,...]

| REMOVE FILE file_name

| ADD FILEGROUP filegroup_name 

| REMOVE FILEGROUP filegroup_name 

| MODIFY FILE file_definition

| MODIFY NAME = new_database_name 

| MODIFY FILEGROUP filegroup_name {filegroup_property 

| NAME = new_filegroup_name }

| SET {state_option | cursor_option 

| auto_option | sql_option | 

recovery_option}

     [,...] [ WITH termination_option]

| COLLATE collation_name }

Parameter descriptions are as follows:


{CREATE | ALTER} DATABASE database_name

Creates a database, or alters an existing database, of database_name. The name cannot be longer than 128 characters. You should limit the database name to 123 characters when no logical filename is supplied, since SQL Server will create a logical filename by appending a suffix to the database name.


{ON | ADD} file_definition [,...]

Defines the disk file(s) that store the data components of the database for CREATE DATABASE or adds disk file(s) for ALTER DATABASE. ON is required for CREATE DATABASE only if you wish to provide one or more file definitions, where the syntax for file_definition is:

{[PRIMARY] ( [NEW][NAME = file_name] [, FILENAME = 'os_file_name']  

[, SIZE = int [KB | MD | GB | TB] ] [, MAXSIZE = { int | 

UNLIMITED } ] [, FILEGROWTH = int] ) } [,...]

where:


PRIMARY

Defines the file_definition as the primary file. Only one is allowed per database. (If you don't define a primary file, SQL Server defaults primary status to the file that it autocreates, in the absence of any user-defined file, or to the first file that you define.) The primary file, or groups of files (also called filegroups), contains the logical start of the database, all the database system tables, and all other objects not contained in user filegroups.


[NEW]NAME = file_name

Defines the logical name of the file defined by the file_definition for CREATE DATABASE. Use NEWNAME for ALTER DATABASE to define a new logical name for the file. In either case, the logical name must be unique within the database. This clause is optional when using FOR ATTACH.


FILENAME = 'os_file_name'

Defines the operating system path and filename for the file defined by file_definition. The file must be in a non-compressed directory on the filesystem. For raw partitions, specify only the drive letter of the raw partition.


SIZE = int [KB | MB | GB | TB]

Defines the size of the file defined by the file_definition. This clause is optional, but defaults to the file size for the primary file of the model database, which is usually very small. Logfiles and secondary datafiles default to 1MB in size. The value of int defaults to megabytes; however, you can explicitly define the size of the file using suffixes for kilobyte (KB), megabyte (MB), gigabyte (GB), and terabyte (TB). Size cannot be smaller than 512KB or the size of the primary file of the model database.


MAXSIZE = { int | UNLIMITED }

Defines the maximum size the file may grow to. Suffixes, as described under the entry for SIZE, are allowed. The default, UNLIMITED, allows the file to grow until all available disk space is consumed. Not required for files on raw partitions.


FILEGROWTH = int

Defines the growth increment for the file each time it grows. Suffixes, as described under the entry for SIZE, are allowed. You may also use the percentage (%) suffix to indicate that the file should grow by the percentage of the total disk space currently consumed. If you omit the FILEGROWTH clause, the file will grow in 10% increments, but never less than 64KB. Not required for files on raw partitions.


[ADD] LOG {ON | FILE} file_definition

Defines the disk file(s) that store the log component of the database for CREATE DATABASE or adds disk file(s) for ALTER DATABASE. You can provide one or more file_definitions for the transaction logs in a comma-delimited list. Refer to the earlier section under the keyword ON for the full syntax of file_definition.


REMOVE FILE file_name

Removes a file from the database and deletes the physical file. The file must be emptied of all content first.


[ADD] FILEGROUP filegroup_name file_definition [,...]

Defines any user filegroups and their file definitions used by the database. All database have at least one primary filegroup (though many databases only use the primary filegroup that comes with SQL Server by default). Adding filegroups and then moving files to the filegroups can allow you greater control over disk I/O. (We recommend that you do not add filegroups without careful analysis and testing.)


REMOVE FILEGROUP filegroup_name

Removes a filegroup from the database and deletes all the files in the filegroup. The files and the filegroup must be empty first.


MODIFY FILE file_definition

Changes the definition of a file. This clause is very similar to the {ADD | ON} FILE clause. For example: MODIFY FILE (NAME = file_name, NEWNAME = new_file_name, SIZE=...).


MODIFY NAME = new_database_name

Changes the database name from its current name to new_database_name.


MODIFY FILEGROUP filegroup_name {filegroup_property | NAME = new_filegroup_name }

Used with ALTER DATABASE, this clause has two forms. The first form allows you to change a filegroup name, as in MODIFY FILEGROUP filegroup_name NAME = new_filegroup_name. The second form allows you to specify a filegroup_property for the filegroup, which must be one of the following:


READONLY

Sets the filegroup to read-only and disallows updates to all objects within the filegroup. READONLY can only be enabled by users with exclusive database access and cannot be applied to the primary filegroup.


READWRITE

Disables the READONLY property and allows updates to objects within the filegroup. READWRITE can only be enabled by users with exclusive database access.


DEFAULT

Sets the filegroup as the default filegroup for the database. All new tables and indexes are assigned to the default filegroup unless explicitly assigned elsewhere. Only one default filegroup is allowed per database. (By default, the CREATE DATABASE statement sets the primary filegroup as the default filegroup.)


SET {state_option | cursor_option | auto_option | sql_option | recovery_option} [,...]

Controls a wide variety of behaviors for the database. These are discussed in the rules and information later in this section.


WITH termination_option

Used after the SET clause, WITH sets the rollback behavior for incomplete transactions whenever the database is in transition. When omitted, transactions must commit or rollback on their own with the database state changes. There are two termination_option settings:


ROLLBACK AFTER int [SECONDS] | ROLLBACK IMMEDIATE

Causes the database to roll back in int number of seconds, or immediately. SECONDS is a noise word and does not change the behavior of the ROLLBACK AFTER clause.


NO_WAIT

Causes database state or option changes to fail if a change cannot be completed immediately, without waiting for the current transaction to independently commit or roll back.


COLLATE collation_name

Defines or alters the default collation used by the database. Collation_name can be either a SQL Server collation name or a Windows collation name. By default, all new databases receive the collation of the SQL Server instance. (You can execute the query SELECT * FROM ::fn_helpcollations( ) to see all the collation names available.) To change the collation of a database, you must be the only user in the database, no schema bound objects that depend on the current collation may exist in the database, and the collation change must not result in the duplication of any object names in the database.


FOR LOAD | FOR ATTACH

Places the database in special startup mode. FOR LOAD is supported only for backward compatibility with versions earlier than 7.0 and sets the database to a status of loading and "dbo use only." FOR ATTACH creates the database from a set of pre-existing operating system files, almost always database files created previously. Because of this, the new database must have the same code page and sort order as the previous database. You only need the file_definition of the first primary file or those files that have a different path from the last time the database was attached. In general, you should use the sp_attach_db system stored procedure over the CREATE DATABASE FOR ATTACH statement unless you need to specify more than 16 file_definitions.

The CREATE DATABASE command should be issued from the master system database. You can, in fact, issue the command CREATE DATABASE database_name, with no other clauses, to get a very small, default database.

SQL Server uses files, formerly called devices, to act as a repository for databases. Files are grouped into one or more filegroups, with at least a PRIMARY filegroup assigned to each database. A file is a predefined block of space created on the disk structure. A database may be stored on one or more files or filegroups. SQL Server also allows the transaction log to be placed in a separate location from the database using the LOG ON clause. These functions allow sophisticated file planning for optimal control of disk I/O. For example, we can create a database called sales_report with a data and transaction logfile:

USE master

GO

CREATE DATABASE sales_report

ON

( NAME = sales_rpt_data, FILENAME =

   'c:\mssql\data\salerptdata.mdf',

   SIZE = 100, MAXSIZE = 500, FILEGROWTH = 25 )

LOG ON

( NAME = 'sales_rpt_log',

   FILENAME = 'c:\mssql\log\salesrptlog.ldf',

   SIZE = 25MB, MAXSIZE = 50MB,

   FILEGROWTH = 5MB )

GO

When a database is created, all objects in the model database are copied into the new database. All of the empty space within the file or files defined for the database is then initialized (i.e., emptied out), which means that creating a new and very large database can take a while, especially on a slow disk.

A database always has at least a primary datafile and a transaction logfile, but may also have secondary files for both the data and log components of the database. SQL Server uses default filename extensions: .mdf for primary datafiles, .ndf for secondary files, and .ldf for transaction logfiles. The following example creates a database called sales_archive with several very large files that are grouped into a couple of filegroups:

USE master

GO

CREATE DATABASE sales_archive

ON

PRIMARY (NAME = sales_arch1, FILENAME = 'c:\mssql\data\archdata1.mdf',

      SIZE = 100GB, MAXSIZE = 200GB, FILEGROWTH = 20GB),

   (NAME = sales_arch2,

      FILENAME = 'c:\mssql\data\archdata2.ndf',

      SIZE = 100GB, MAXSIZE = 200GB, FILEGROWTH = 20GB),

   (NAME = sales_arch3,

      FILENAME = 'c:\mssql\data\archdat3.ndf',

      SIZE = 100GB, MAXSIZE = 200GB, FILEGROWTH = 20GB)

FILEGROUP sale_rpt_grp1

   (NAME = sale_rpt_grp1_1_data,

   FILENAME = ' c:\mssql\data\SG1Fi1dt.ndf',

      SIZE = 100GB, MAXSIZE = 200GB, FILEGROWTH = 20GB),

 (NAME = sale_rpt_grp1_1_data,

   FILENAME = ' c:\mssql\data\SG1Fi2dt.ndf',

      SIZE = 100GB, MAXSIZE = 200GB, FILEGROWTH = 20GB),

FILEGROUP sale_rpt_grp2

(NAME = sale_rpt_grp2_1_data, FILENAME = ' c:\mssql\data\SRG21dt.ndf',

      SIZE = 100GB, MAXSIZE = 200GB, FILEGROWTH = 20GB),

 (NAME = sale_rpt_grp2_2_data, FILENAME = ' c:\mssql\data\SRG22dt.ndf',

      SIZE = 100GB, MAXSIZE = 200GB, FILEGROWTH = 20GB),

LOG ON

   (NAME = sales_archlog1,

    FILENAME = 'd:\mssql\log\archlog1.ldf',

      SIZE = 100GB, MAXSIZE = UNLIMITED, FILEGROWTH = 25%),

   (NAME = sales_archlog2,

    FILENAME = 'd:\ mssql\log\archlog2.ldf',

      SIZE = 100GB, MAXSIZE = UNLIMITED, FILEGROWTH = 25%)

GO

The FOR ATTACH clause is commonly used for situations like a salesperson traveling with a database on a CD. This clause tells SQL Server that the database is attached from an existing operating-system file structure, such as a DVD-ROM, CD-ROM, or portable hard drive. When using FOR ATTACH, the new database inherits all the objects and data of the parent database, not the model database.

The following examples show how to change the name of a database, file, or filegroup:

-- Rename a database

ALTER DATABASE sales_archive MODIFY NAME = sales_history

GO

-- Rename a file

ALTER DATABASE sales_archive MODIFY FILE 

NAME = sales_arch1,

NEWNAME = sales_hist1

GO

-- Rename a filegroup

ALTER DATABASE sales_archive MODIFY FILEGROUP 

sale_rpt_grp1

NAME = sales_hist_grp1

GO

There may be times when you want to add new free space to a database, especially if you have not enabled it to auto-grow:

USE master

GO

ALTER DATABASE sales_report ADD FILE

( NAME = sales_rpt_added01, FILENAME = 'c:\mssql\data\salerptadded01.mdf',

   SIZE = 50MB, MAXSIZE = 250MB, FILEGROWTH = 25MB )

GO

When you alter a database, you can set many behavior options on the database. State options (shown as state_option in the earlier syntax diagram) control how users access the database. Following is a list of valid state options:


SINGLE_USER | RESTRICTED_USER | MULTI_USER

Sets the number and type of users with access to the database. SINGLE_USER mode allows only one user to access the database at a time. RESTRICTED_USER mode allows access only members of the system roles db_owner, dbcreator, or sysadmin. MULTI_USER, the default, allows concurrent database access from all users who have permission.


OFFLINE | ONLINE

Sets the database to offline (unavailable) or online (available).


READ_ONLY | READ_WRITE

Sets the database to READ_ONLY mode, where no modifications are allowed, or to READ_WRITE mode, where data modifications are allowed. READ_ONLY databases can be very fast for query intensive operations, since almost no locking is needed.

Cursor options control default behavior for cursors in the database. In the ALTER DATABASE syntax shown earlier, you can replace cursor_option with any of the following:


CURSOR_CLOSE_ON_COMMIT { ON | OFF }

When set ON, any open cursors are closed when a transaction commits or rolls back. When set OFF, any open cursors remain open when transactions are committed and open cursors close when a transaction rolls back unless the cursor is INSENSITIVE or STATIC. (See DECLARE CURSOR Command later in this chapter for more details.)


CURSOR_DEFAULT { LOCAL | GLOBAL }

Sets the default scope of all cursors in the database to either LOCAL or GLOBAL. (See DECLARE CURSOR Command later in this chapter for more details.)

In the SET clause, auto_option controls the automatic file handling behaviors of the database. The following are valid replacements for auto_option:


AUTO_CLOSE { ON | OFF }

When set ON, the database automatically shuts down cleanly and frees all resources when the last user exits. When set OFF, the database remains open when the last user exits. The default is OFF.


AUTO_CREATE_STATISTICS { ON | OFF }

When set ON, statistics are automatically created when SQL Server notices they are missing during query optimization. When set OFF, statistics are not created during optimization. The default is ON.


AUTO_SHRINK { ON | OFF }

When set ON, the database files may automatically shrink. The database periodically looks for an opportunity to shrink files, though the time is not always predictable. When set OFF, files will shrink only when you explicitly and manually shrink them. The default is OFF.


AUTO_UPDATE_STATISTICS { ON | OFF }

When set ON, out-of-date statistics are reassessed during query optimization. When set OFF, statistics are reassessed only by explicitly and manually recompiling them using the SQL Server command UPDATE STATISTICS.

The sql_options clause controls ANSI compatibility of the database. You can use the standalone SQL Server command SET ANSI_DEFAULTS ON to enable all the ANSI SQL92 behaviors at one time, rather than using the individual statements below. In the SET clause, you can replace sql_option with any of the following:


ANSI_NULL_DEFAULT { ON | OFF }

When set ON, the CREATE TABLE statement causes columns with no nullability setting to default to NULL. When set OFF, the nullability of a column defaults to NOT NULL. The default is OFF.


ANSI_NULLS { ON | OFF }

When set ON, comparisons to null yield UNKNOWN. When set OFF, comparisons to null yield null if both non-UNICODE values are null. The default is OFF.


ANSI_PADDING { ON | OFF }

When set ON, strings are padded to the same length for insert or comparison operations on VARCHAR and VARBINARY columns. When set OFF, strings are not padded. The default is ON. (We recommend that you do not change this!)


ANSI_WARNINGS { ON | OFF }

When set ON, the database warns when problems like "divide by zero" or "null in aggregates" occur. When set OFF, these warnings are not raised. The default is OFF.


ARITHABORT { ON | OFF }

When set ON, divide-by-zero and overflow errors cause a query or Transact-SQL batch to terminate and roll back any open transactions. When set OFF, a warning is raised but processing continues. The default is ON. (We recommend that you do not change this!)


CONCAT_NULL_YIELDS_NULL { ON | OFF }

When set ON, returns a null when a null is concatenated to a string. When set OFF, nulls are treated as empty strings when concatenated to a string. The default is OFF.


NUMERIC_ROUNDABORT { ON | OFF }

When set ON, an error is raised when a numeric expression loses precision. When set OFF, losses of precision result in rounding of the result from the numeric expression. The default is OFF.


QUOTED_IDENTIFIER { ON | OFF }

When set ON, double quotation marks identify an object identifier with special characters or one that is a reserved word (e.g., a table named SELECT). When set OFF, identifiers may not contain special characters or reserved words and all occurrences of double quotation marks signify a literal string value. The default is OFF.


RECURSIVE_TRIGGERS { ON | OFF }

When set ON, triggers can fire recursively. That is, the actions taken by one trigger may cause another trigger to fire, and so on. When set OFF, triggers cannot cause other triggers to fire. The default is OFF.

Recovery options control the recovery model used by the database. Use any of the following in place of recovery_option in the ALTER DATABASE syntax:


RECOVERY { FULL | BULK_LOGGED | SIMPLE }

When set to FULL, database backups and transaction logs provide full recoverability even for bulk operations like SELECT...INTO, CREATE INDEX, etc. FULL is the default for SQL Server 2000 Standard Edition and Enterprise Edition. FULL provides the most recoverability, even from a catastrophic media failure, but uses more space. When set to BULK_LOGGED, logging for bulk operations is minimized. Space is saved and fewer I/Os are incurred, but risk of data loss is greater than under FULL. When set to SIMPLE, the database can only be recovered to the last full or differential backup. SIMPLE is the default for SQL Server 2000 Desktop Edition and Personal Edition.


TORN_PAGE_DETECTION { ON | OFF }

When set ON, SQL Server can detect incomplete I/O operations at the disk level by checking each 512-byte sector per 8K database page. (Torn pages are usually detected in recovery.) The default is ON.

For example, we may want to change some behavior settings for the sales_report database without actually changing the underlying file structure:

ALTER DATABASE sales_report SET ONLINE, READ_ONLY,

AUTO_CREATE_STATISTICS ON

GO

This statement puts the database online and in read-only mode. It also sets the AUTO_CREATE_STATISTICS behavior to ON.

See Also

CREATE SCHEMA
DROP STATEMENT
CREATE/ALTER FUNCTION/PROCEDURE Statements

The CREATE FUNCTION and CREATE PROCEDURE statements are very similar in syntax and coding (as are the respective ALTER statements).

The CREATE PROCEDURE statement creates a stored procedure, which takes input arguments and performs conditional processing against various objects in the database. According to the ANSI standard, a stored procedure returns no result set (though it may return a value in an OUTPUT parameter). For example, you might use a stored procedure to perform all the processes that close an accounting cycle.

The CREATE FUNCTION statement creates a user-defined function (UDF), which takes input arguments and returns a single value output in the same way as system-supplied functions like CAST( ) or UPPER( ). These functions, once created, can be called in queries and data-manipulation operations, such as INSERT, UPDATE, and the WHERE clause of DELETE statements. Refer to Chapter 4 for descriptions of built-in SQL functions and their individual vendor implementations.

Platform

Command

DB2

Supported, with variations

MySQL

Supported, with limitations

Oracle

Supported, with variations

PostgreSQL

Supported, with limitations

SQL Server

Supported, with variations


SQL2003 Syntax

Use the following syntax to create a stored procedure or function:

CREATE {PROCEDURE | FUNCTION} object_name

   ( [{[IN | OUT | INOUT] [parameter_name] datatype [AS LOCATOR] [RESULT]}

      [,...] ] )

   [ RETURNS datatype [AS LOCATOR]

      [CAST FROM datatype [AS LOCATOR] ]

[LANGUAGE {ADA | C | FORTRAN | MUMPS | PASCAL | PLI | SQL}]

[PARAMETER STYLE {SQL | GENERAL}]

[SPECIFIC specific_name]

[DETERMINISTIC | NOT DETERMINISTIC]

[NO SQL | CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA]

[RETURN NULL ON NULL INPUT | CALL ON NULL INPUT]

[DYNAMIC RESULT SETS int]

[STATIC DISPATCH]

code_block

Use the following syntax to alter a pre-existing UDF or stored procedure:

ALTER {PROCEDURE | FUNCTION} object_name

   [( {parameter_name datatype } [,...])]

[NAME new_object_name]

[LANGUAGE {ADA | C | FORTRAN | MUMPS | PASCAL | PLI | SQL}]

[PARAMETER STYLE {SQL | GENERAL}]

[NO SQL | CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA]

[RETURN NULL ON NULL INPUT | CALL ON NULL INPUT]

[DYNAMIC RESULT SETS int]

[CASCADE | RESTRICT]

Keywords


CREATE {PROCEDURE | FUNCTION} [AS LOCATOR] [RESULT] object_name

Creates a new stored procedure or user-defined function with the name object_name. A user-defined function returns a value, where a stored procedure, in ANSI SQL, does not.


([IN | OUT| INOUT] [parameter_name] datatype [,...] )

Declares one or more parameters to be passed into a stored procedure in a comma-delimited list enclosed in parentheses. Parameters used with a procedure may pass a value IN, OUT, or both in and out via INOUT.

The syntax for the parameter declaration is:

[{IN | OUT | INOUT}] parameter_name1 datatype, 

[{IN | OUT | INOUT}] parameter_name2 datatype,[...]

To provide an optional parameter_name, make sure the name is unique within the stored procedure. The optional AS LOCATOR subclause is used to validate an external routine with a RETURNS parameter that is a BLOB, CLOB, NCLOB, ARRAY, or user-defined type. If you need to change the datatype of a RETURNS parameter on the fly, use the CAST clause (refer to the function, CAST, in Chapter 4). For example, RETURNS VARCHAR(12) CAST FROM DATE.When used with ALTER, this clause adds parameters to a pre-existing stored procedure. Refer to Chapter 2 for details on datatypes.


RETURNS datatype [AS LOCATOR] [CAST FROM datatype [AS LOCATOR] ]

Declares the datatype of the result returned by a function. (This clause is used only in the CREATE FUNCTION statement and is not used in stored procedures.) The key purpose of a user-defined function is to return a value.


LANGUAGE {ADA | C | FORTRAN | MUMPS | PASCAL | PLI | SQL}

Declares the language in which the function is written. Most database platforms do not support all of these languages, and often support several not mentioned, like Java. When omitted, the default is SQL. When used with ALTER, this clause changes the existing LANGUAGE value to the value that you declare.


PARAMETER STYLE {SQL | GENERAL}

Indicates, for external routines only, whether certain implicit and automatic parameters are passed, explicitly, with the options (SQL) or not (GENERAL). (The difference between SQL style and GENERAL style is that SQL style passes automatic SQL parameters, such as indicators, while the GENERAL style does not automatically pass parameters.) The default is PARAMETER STYLE SQL. When used with ALTER, this clause changes the existing PARAMETER STYLE value to the value that you declare.


SPECIFIC specific_name

Uniquely identifies the function generally used with user-defined types.


DETERMINISTIC | NOT DETERMINISTIC

States the nature of values returned by a function. (This clause is used only in CREATE and ALTER FUNCTION statement.) DETERMINISTIC functions always return the same value when given the same parameter values. NOT DETERMINISTIC functions may return variable results when given the same parameter values. For example, CURRENT_TIME is not deterministic because it returns a constantly advancing value corresponding to the time.


NO SQL | CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA

Specifies, in conjunction with the LANGUAGE setting, the type of SQL contained in the user-defined function. When used with ALTER, this clause changes the existing SQL style value to the value that you declare.


NO SQL

Indicates that no SQL statements of any type are in the function. It is used with a non-SQL LANGUAGE setting such as LANGUAGE ADA...CONTAINS NO SQL.


CONTAINS SQL

Indicates that SQL statements other than read or modify statements are in the function. This is the default.


READS SQL DATA

Indicates the function contains SELECT or FETCH statements.


MODIFIES SQL DATA

Indicates the function contains INSERT, UPDATE, or DELETE statements.


RETURN NULL ON NULL INPUT | CALL ON NULL INPUT

These options are for use with a host LANGUAGE that cannot support nulls. The RETURNS NULL ON NULL INPUT setting causes the function to immediately return a null value if it is passed a null value. The CALL ON NULL INPUT setting causes the function to handle nulls according to standard rules, for example returning UNKNOWN when a comparison of two null values occurs. (This clause is used in the CREATE and ALTER PROCEDURE and FUNCTION statements.) When used with ALTER, this clause changes the existing NULL style value to the value that you declare.


DYNAMIC RESULT SETS int

Declares that a certain number of cursors, int, can be opened by the stored procedure and that those cursors are visible after returning from the procedure. When omitted, the default is DYNAMIC RESULT SETS 0. (This clause is not used in CREATE FUNCTION statements.) When used with ALTER, this clause changes the existing DYNAMIC RESULT SETS value to the value that you declare.


STATIC DISPATCH

Returns the static values of a user-defined type or ARRAY datatype. Required for non-SQL functions that contain parameters that use user-defined types or ARRAYS. (This clause is not used in CREATE PROCEDURE statements.) This clause must be the last clause in the function or procedure declaration before the code_block.


code_block

Declares the procedural statements that handle all processing within the user-defined function or stored procedure. This is the most important, and usually largest, part of a function or procedure. We assume you're interested in a user-defined function of LANGUAGE SQL, so note that the code_block may not contain SQL-Schema statements, SQL-Transaction statements, nor SQL-Connection statements. While we assume that you're interested in SQL-based UDFs and stored procedures (this is a SQL book after all), you can declare that the code block is derived externally. The syntax for external code_blocks is:

EXTERNAL [NAME external_routine_name] [PARAMETER STYLE 

{SQL | GENERAL}] [TRANSFORM GROUP group_name]

where:


EXTERNAL [NAME external_routine_name]

Defines an external routine and assigns a name to it. When omitted, the unqualified routine name is used.


PARAMETER STYLE [SQL | GENERAL]

Same as for CREATE PROCEDURE.


TRANSFORM GROUP group_name

Transforms values between user-defined types and host variables in a user-defined function or a stored procedure. When omitted, the default is TRANSFORM GROUP DEFAULT.


NAME new_object_name

Declares the new name to use for a previously defined UDF or stored procedure. This clause is only used with ALTER FUNCTION and ALTER PROCEDURE statements.


CASCADE | RESTRICT

Allows you to cause changes to CASCADE down to all dependent UDFs or stored procedures, or to RESTRICT a change from happening if there are dependent objects. We strongly recommend that you do not issue an ALTER statement against UDFs or stored procedures that have dependent objects. This clause is only used with ALTER FUNCTION and ALTER PROCEDURE statements.

Rules at a Glance

With a user-defined function (UDF), you declare the input arguments and the single output argument that the function passes back out. You can then call the user-defined function just as you would any other function, for example, in SELECT statements, INSERT statements, or the WHERE clause of DELETE statements.

User-defined functions and stored procedures, when referred to generically, are called routines.


With a stored procedure, you declare the input arguments that go into the stored procedure and the output arguments that come out from it. You invoke a stored procedure using the CALL statement.

The content of the code_block must conform to the rules of whatever procedural language is supported by the database platform. Some platforms do not have their own internal procedural language, requiring you to use EXTERNAL code_block constructs.

For example, you might want build a user-defined function on Microsoft SQL Server that returns the first and last name of a person as a single string:

CREATE FUNCTION formatted_name (@fname VARCHAR(30),

@lname VARCHAR(30) )

RETURNS VARCHAR(60)

AS

BEGIN

   DECLARE @full_name VARCHAR(60)

   SET @full_name = @fname + ' ' + @lname

   RETURN @full_name

END

You could then use this user-defined function as any other function:

SELECT formatted_name(au_fname, au_lname) AS name, au_id AS id

FROM authors

The SELECT statement in this example will return a result set with the two columns, name and id.

The ANSI statement CREATE METHOD is supported only by DB2 at this time. A method is essentially a special purpose user-defined function and follows the same syntax.


Stored procedures behave similarly. In the following small example, this Microsoft SQL Server stored procedure generates a unique 22-digit value (based on elements of the system date and time) and returns it to the calling process:

-- A Microsoft SQL Server stored procedure

CREATE PROCEDURE get_next_nbr

   @next_nbr CHAR(22) OUTPUT

AS

BEGIN

  DECLARE @random_nbr INT

  SELECT @random_nbr = RAND( ) * 1000000

SELECT @next_nbr =

  RIGHT('000000' + CAST(ROUND(RAND(@random_nbr)*1000000,0))AS

    CHAR(6), 6) +

  RIGHT('0000' + CAST(DATEPART (yy, GETDATE( ) ) AS CHAR(4)), 2) +

  RIGHT('000'  + CAST(DATEPART (dy, GETDATE( ) ) AS CHAR(3)), 3) +

  RIGHT('00'   + CAST(DATEPART (hh, GETDATE( ) ) AS CHAR(2)), 2) +

  RIGHT('00'   + CAST(DATEPART (mi, GETDATE( ) ) AS CHAR(2)), 2) +

  RIGHT('00'   + CAST(DATEPART (ss, GETDATE( ) ) AS CHAR(2)), 2) +

  RIGHT('000'  + CAST(DATEPART (ms, GETDATE( ) ) AS CHAR(3)), 3)

END

GO

In this next, and final, ANSI SQL2003 example, we change the name of an existing stored procedure:

ALTER PROCEDURE get_next_nbr

NAME 'get_next_ID'

RESTRICT;

Programming Tips and Gotchas

A key advantage of a stored procedure or function is the fact that it is precompiled, meaning that once created its query plans are already stored in the database. Precompiled routines can often (though not always) be cached in database memory to provide an additional boost in performance. A stored procedure or user-defined function can perform many statements with a single communication to the server, thus reducing network traffic.

Implementations of user-defined functions and stored procedures vary widely by platform. Some database platforms do not support internal code_block content. On these platforms, you can only write an external code_block. Be sure to read about the variations and capabilities on each platform.

If you execute an ALTER PROCEDURE or FUNCTION statement, dependent objects may become invalid after a change to an object they depend on. Be careful to check all dependencies when altering UDFs or stored procedures on which other UDFs or stored procedures may depend.

DB2

DB2's implementations of these commands are very close to the ANSI standard. Although the syntax diagrams are long, much of the usage is identical to the ANSI standard. Consequently, the keyword explanation section that follows the syntax diagram is relatively short, since many of the clauses are explained in the SQL standard.

DB2 supports several classifications of functions. Each kind of UDF has its own set of allowable syntax, though much of it is shared across the various kinds of UDF. DB2 allows external scalar functions, external table functions, OLE-DB external table functions, sourced (or template) functions, and SQL functions. DB2 supports two kinds of stored procedures: external and SQL.

The following syntax is the full syntax to create any sort of stored procedure or a UDF in DB2. It is grouped together here to give you a concise list of clause definitions. However, refer to the sections below for greater detail on the specific allowable syntax for each type of UDF and stored procedure. If you prefer, for example, to see only the allowable syntax for a SQL user-defined function, then skip to the section below. The total available syntax for UDFs and stored procedures follows:

CREATE {PROCEDURE | FUNCTION} object_name

   [( {[IN | OUT| INOUT] [parameter_name] datatype } [,...])]

RETURNS {datatype | {ROW | TABLE} column_list} [AS LOCATOR]

   [CAST FROM datatype [AS LOCATOR] ]

[LANGUAGE {C | JAVA | COBOL | OLE | SQL]

[PARAMETER STYLE {SQL | DB2GENERAL | GENERAL | GENERAL WITH NULLS | JAVA}]

[SPECIFIC specific_name]

[EXTERNAL NAME external_routine_name]

[DETERMINISTIC | NOT DETERMINISTIC]

[ [NO] EXTERNAL ACTION]

[NO SQL | CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA]

[CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT]

[DYNAMIC RESULT SETS int]

[STATIC DISPATCH]

[SOURCE object_name | AS TEMPLATE ]

[INHERIT SPECIAL REGISTERS]

[[NOT] FENCED] [[NOT] THREADSAFE]

[PROGRAM TYPE {SUB | MAIN}]

[ [NO] SCRATCHPAD int] [ [NO] FINAL CALL]

[{ALLOW | DISALLOW} PARALLEL]

[ [NO] DBINFO]

[TRANSFORM GROUP group_name]

[CARDINALITY int]

[PREDICATES (predicate_definition) ]

code_block

In addition, use the following syntax to alter a pre-existing UDF or stored procedure, and assign it the characteristics that you declare:

ALTER {PROCEDURE | FUNCTION} object_name

[EXTERNAL NAME external_routine_name]

[ [NOT] FENCED] [ [NOT] THREADSAFE]

Following are the parameter descriptions for DB2:


RETURNS {datatype | {ROW | TABLE} column_list}

Allows you to return a single value of datatype, a ROW of values, or a TABLE of values where column_list uses the syntax column_name1 datatype1, column_name2 datatype2 [,...].


LANGUAGE {C | JAVA | COBOL | OLE | SQL}

Same as the ANSI standard, though DB2 supports other languages than in the ANSI standard. When you declare a LANGUAGE setting, other options are restricted or made available.


PARAMETER STYLE {SQL | DB2GENERAL | GENERAL | GENERAL WITH NULLS | JAVA}

Similar to the ANSI SQL standard but with a richer variety of choices. PARAMETER STYLE is only used with external stored procedures or user-defined functions. The various styles determine how parameters are passed, where:


SQL

Defines that when parameters are passed with the CALL statement, a null indicator for each parameter and a qualified and specific name for the stored procedure or function are also passed. In addition, the SQLSTATE and SQL diagnostic string are passed back to DB2.


DB2GENERAL

Available only with the LANGAUGE JAVA clause, the DB2GENERAL clause specifies that the parameters are passed using the convention defined for Java.


GENERAL

Passes parameters directly from the CALL statement to the stored procedure without using a SQLDA structure. Nulls are not passed. Only available with LANGUAGE C or COBOL.


GENERAL WITH NULLS

Same as GENERAL, but also passes null indicators.


JAVA

Passes parameters using the Java and SQLJ Routines specifications. For example, INOUT and OUT parameters are passed as a single entry array. Available only with the LANGUAGE JAVA clause. This clause is mutually exclusive of the DBINFO clause and PROGRAM TYPE clause.


EXTERNAL NAME [external_routine_name]

Registers a new function or procedure using a linked and interfaced external program. When external_routine_name is omitted, object_name is assumed to be the name of the external program. The method of linking depends on the LANGUAGE setting.


NO SQL | CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA

Same as the ANSI standard, though certain options are not usable for certain LANGUAGE settings.


INHERIT SPECIAL REGISTERS

Declares that updateable special registers receive their initial value from the invoking process. The invoking process could be a UDF, a stored procedure, trigger, view, or user issuing a CALL statement.


[[NOT] FENCED] [{THREADSAFE | NOT THREADSAFE}]

Specifies whether (or NOT) the external stored procedure or user-defined function is "safe" to run in DB2's manager operating environment process or address space. This is used only for external stored procedures. NOT FENCED procedures tend to be faster, but open the database up to potential risks.


[[NOT] THREADSAFE]

Declares whether the method is safe to run in the same process as other routines (THREADSAFE) or not (NOT THREADSAFE). When declared THREADSAFE, a procedure is considered safe to run in the same process as other UDFs and stored procedures. NOT THREADSAFE can only be used with FENCED stored procedures.


PROGRAM TYPE {SUB | MAIN}

Tells whether the external stored procedure should expect parameters in the style of a SUB routine or a MAIN routine. SUB, the default, declares that the parameters are expected as separate arguments. MAIN declares that the parameters are expected as an argument counter and argument vector. MAIN also requires that the external stored procedure is named "main" and that it is built as a shared library, not as a standalone executable. PROGRAM TYPE MAIN is only valid with LANGUAGE C or COBOL and PARAMETER STYLE GENERAL, GENERAL WITH NULLS, SQL, or DB2SQL.


[NO] SCRATCHPAD int

Provides a scratch pad for any external function or procedure. A SCRATCHPAD provides a way for a UDF to save its state from one call to the next. The default is NO SCRATCHPAD. If an int is specified, it represents the size of the scratch pad in bytes (defaulting to 100 bytes). One scratch pad is initialized per reference to an external routine.


[NO] FINAL CALL

FINAL CALL causes the routine to invoke two extra times. The first invocation occurs before data is first loaded so the routine can perform any one-time initialization needed. The second invocation occurs last and allows the routine to do any cleanup needed. Table functions are always a FINAL CALL. This clause is incompatible with PARAMETER STYLE JAVA. The clause NO FINAL CALL prevents a final call from happening.


{ALLOW | DISALLOW} PARALLEL

Allows the routine to be split in parallel across multiple CPUs (a.k.a. parallelized) during plan optimization on an SMP or MPP server, with ALLOW PARALLEL. Otherwise, DB2 enforces the serial processing of a routine on a single CPU, regardless of how many CPUs exist on the server, with DISALLOW PARALLEL. ALLOW PARALLEL is the default, unless the routine contains any of these clauses: NOT DETERMINISTIC, EXTERNAL ACTION, SCRATCHPAD, or FINAL CALL.


[NO] DBINFO

Tells whether the external stored procedure receives an additional argument (DBINFO) or not (NO DBINFO, the default) when invoked. The DBINFO argument tells the database name, application ID, application authorization ID, code page, database release version, and platform. DBINFO is mutually exclusive of LANGAUGE OLD and PARAMETER STYLE JAVA and DB2GENERAL.


TRANSFORM GROUP group_name

Declares the transform group, group_name, if the routine uses a user-defined structured type for either a parameter or return datatype.


CARDINALITY int
PREDICATES (predicate_definition)

Used with CREATE FUNCTION to create a user-defined predicate. This option is used when defining user-defined functions for use with DB2's index extensions. Index extensions are quite complex and not used by the average DB2 user. Consequently, you should refer to DB2's documentation on index extensions for information on this clause. In addition, DETERMINISTIC with NO EXTERNAL ACTION clauses are required to use PREDICATES.

DB2 accommodates several kinds of user-defined functions: external scalar, external table, OLE-DB, source/template, and SQL, and two kinds of stored procedures: external and SQL. Each of these types allows a mix of only some of the clauses shown above.

DB2 external scalar user-defined functions

This variation of the CREATE FUNCTION statement is used to register a user-defined external scalar function with an application server. (Remember that scalar functions return a single value each time they are invoked and are valid wherever SQL expressions are valid.) An external scalar UDF allows the following clauses:

CREATE FUNCTION object_name (parameter_name datatype

      [,...]) [AS LOCATOR]

   RETURNS datatype [AS LOCATOR] [CAST FROM datatype

      [AS LOCATOR] ]

   [LANGUAGE {C | JAVA | OLE} ] [PARAMETER STYLE

      {SQL | DB2GENERAL | JAVA}]

   [SPECIFIC specific_name]

      [EXTERNAL NAME external_routine_name]

   [DETERMINISTIC | NOT DETERMINISTIC] [STATIC DISPATCH]

   [ [NO] EXTERNAL ACTION]

   [NO SQL | CONTAINS SQL | READS SQL DATA]

   [CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT]

   [INHERIT SPECIAL REGISTERS]

   [ [NOT] FENCED [{THREADSAFE | NOT THREADSAFE}] ]

   [ [NO] SCRATCHPAD int] [ [NO] FINAL CALL]

      [{ALLOW | DISALLOW} PARALLEL]

   [ [NO] DBINFO] [TRANSFORM GROUP group_name]

   [PREDICATES (predicate_definition) ]

code_block

The following code is an example of an external scalar UDF, called report_reader.center, that defines the center of a circle. The statement explicitly declares all option clauses, even those that have identical defaults to the declared values:

CREATE FUNCTION report_reader.center (FLOAT, FLOAT, FLOAT)

RETURNS DECIMAL(8,4) CAST FROM FLOAT

SPECIFIC center04

EXTERNAL NAME 'center!focalpt'

LANGUAGE C PARAMETER STYLE SQL DETERMINISTIC FENCED NOT NULL CALL

NO SQL NO EXTERNAL ACTION SCRATCHPAD NO FINAL CALL

DISALLOW PARALLEL

Note that the report_reader.center UDF uses a scratch pad and can accumulate and act on results stored there

DB2 external table user-defined functions

This variation of the CREATE FUNCTION statement is used to register a user-defined external table function with an application server. (A table function can be used in the FROM clause of a SELECT statement, returning a table to the SELECT one row at a time.) An external table UDF allows the following clauses:

CREATE FUNCTION object_name (parameter_name datatype }

      [AS LOCATOR] [,...])

   RETURNS TABLE datatype [AS LOCATOR] [,...] ]

   [LANGUAGE {C | JAVA | OLE} ] [PARAMETER STYLE

      {SQL | DB2GENERAL}]

   [SPECIFIC specific_name] [EXTERNAL NAME external_routine_name]

   [DETERMINISTIC | NOT DETERMINISTIC] [ [NO] EXTERNAL ACTION]

   [NO SQL | CONTAINS SQL | READS SQL DATA]

   [CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT]

   [INHERIT SPECIAL REGISTERS] [ [NOT] FEDERATED]

   [ [NOT] FENCED [{THREADSAFE | NOT THREADSAFE}] ]

   [ [NO] SCRATCHPAD int] [ [NO] FINAL CALL]

      [DISALLOW PARALLEL]

   [ [NO] DBINFO] [TRANSFORM GROUP group_name]

   [CARDINALITY int]

code_block

Following is an example external table UDF that retrieves message header information and some message text from Microsoft Exchange:

CREATE FUNCTION MAIL( )

RETURNS TABLE (time_rcvd DATE, subjct VARCHAR(15),

   lngth INTEGER, txt VARCHAR(30))

EXTERNAL NAME 'mail.header!list'

LANGUAGE OLE

PARAMETER STYLE SQL

NOT DETERMINISTIC FENCED CALLED ON NULL INPUT

   SCRATCHPAD FINAL CALL

NO SQL

EXTERNAL ACTION DISALLOW PARALLEL

Note that the external function, mail.header!list, should already exist.

DB2 OLE-DB external table user-defined functions

This variation of the CREATE FUNCTION statement registers a user-defined OLE-DB external table function to access data from an OLE-DB provider. The table function may then be used in the FROM clause of a SELECT statement. This is useful to link to non-DB2 sources of relational data. An OLE-DB external table UDF allows the following clauses:

CREATE FUNCTION object_name (parameter_name datatype ) [,...])

   RETURNS TABLE datatype [,...] ] [SPECIFIC specific_name]

   [LANGUAGE OLEDB] [EXTERNAL NAME external_routine_name]

   [DETERMINISTIC | NOT DETERMINISTIC] [ [NO] EXTERNAL ACTION]

   [STATIC DISPATCH] [CALLED ON NULL INPUT |

      RETURNS NULL ON NULL INPUT]

   [CARDINALITY int]

code_block

The following example registers an OLE-DB table function that retrieves order information from the Microsoft Access database called Northwind:

CREATE FUNCTION orders ( )

RETURNS TABLE (orderid INTEGER, customerid CHAR(5), employeeid INTEGER,

   orderdate TIMESTAMP, requireddate TIMESTAMP, shippeddate TIMESTAMP,

   shipvia INTEGER, freight DEC(19,4))

LANGUAGE OLEDB

EXTERNAL NAME '!orders!Provider=Microsoft.Jet.OLEDB.3.51;

   Data Source=c:\sqllib\samples\oledb\nwind.mdb';

Note that the connection string is defined in the external name of the function.

DB2 sourced user-defined functions

This variation of the CREATE FUNCTION statement registers a user-defined function that is based on another existing scalar or column function. This statement can also be used to register a function template with an application server that acts as a federated server. (A function template is a partial function that has no executable code, but instead uses it to map to a data source function. Once the mapping is created, the user specifies the function template in queries to the federated server. The federated server will invoke the data source function and return values that correspond to those in the RETURNS portion of the template definition.) A source/template UDF allows the following clauses:

CREATE FUNCTION object_name (parameter_name datatype [,...])

   RETURNS datatype [,...] ]

   [SOURCE {object_name [input_argument [,...] ] |

      [SPECIFIC specific_name] ]

   [AS TEMPLATE [DETERMINISTIC | NOT DETERMINISTIC]

      [ [NO] EXTERNAL ACTION] ]

code_block

For example, the following sourced UDF is based on the report_reader.center scalar function created earlier in this section. The following function, called fn_center, accepts only integer arguments:

CREATE FUNCTION fn_center (INTEGER, INTEGER)

RETURNS FLOAT

SOURCE report_reader.center (INTEGER, FLOAT);

In the next example, using a federated server, we can invoke an Oracle UDF, called statistics in the schema scott, that returns table statistics as a double-precision floating point value:

CREATE FUNCTION scott.statistics (DOUBLE, DOUBLE)

RETURNS DOUBLE AS TEMPLATE

DETERMINISTIC NO EXTERNAL ACTION;

DB2 SQL user-defined functions

This variation of the CREATE FUNCTION statement defines a SQL scalar, table, or row function. This application shows the most common form of SQL UDF's in DB2. (Remember a scalar function returns a single value when invoked. A table function may be used in the FROM clause of a SELECT statement and returns a table. A row function returns a row and may be used as a transform function.)

A SQL UDF allows the following clauses:

CREATE FUNCTION object_name [(parameter_name datatype [,...])]

RETURNS {datatype | {ROW | TABLE} column_list}

      [SPECIFIC specific_name]

   [LANGUAGE SQL] [DETERMINISTIC | NOT DETERMINISTIC]

      [ [NO] EXTERNAL ACTION]

   [CONTAINS SQL | READS SQL DATA] [STATIC DISPATCH]

   [CALLED ON NULL INPUT] [PREDICATES (predicate_definition) ]

code_block

Here's an example of a SQL user-defined function that returns a concatenated name from separate fields:

CREATE FUNCTION prod.cust_name

 (in_custno INTEGER )

  RETURNS VARCHAR(31)

  LANGUAGE SQL

  READS SQL DATA

  NO EXTERNAL ACTION

  DETERMINISTIC

  RETURN

    SELECT (c.firstnme CONCAT ' '

      CONCAT c.midinit CONCAT '. '

      CONCAT c.lastname)

      AS name

      FROM prod.customer c

      WHERE c.custno = 10;

DB2 external stored procedure

This variation of the CREATE PROCEDURE statement defines an external procedure with a DB2 application server. Usually, external procedures are written in a non-SQL language like C or Java. An external procedure allows the following clauses:

CREATE PROCEDURE object_name

   [( [IN | OUT | INOUT] parameter_name datatype [,...] ) ]

   [SPECIFIC specific_name] [DYNAMIC RESULT SETS int]

   [NO SQL | CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA]

   [DETERMINISTIC | NOT DETERMINISTIC] [CALLED ON NULL INPUT]

LANGUAGE {C | JAVA | COBOL | OLE}

   EXTERNAL NAME external_routine_name

   [INHERIT SPECIAL REGISTERS]

PARAMETER STYLE {SQL | DB2GENERAL | DB2SQL | GENERAL |

   GENERAL WITH NULLS | JAVA}

   [ [NOT] FENCED [{THREADSAFE | NOT THREADSAFE}] ]

   [PROGRAM TYPE {SUB | MAIN}]

   [ [NO] DBINFO]

code_block

Following is an example of an external procedure. In the example, we define a procedure definition in DB2 for a C program that, when passed an author ID, tells us the total books sold, the total sales in dollars, and the book titles the specified author wrote:

CREATE PROCEDURE author_sales

   (IN au_id INTEGER, OUT books_sold INTEGER,

    OUT total_sales DOUBLE, OUT title VARCHAR(50) )

EXTERNAL NAME 'authors!sales'

DYNAMIC RESULT SETS 1 NOT FENCED

LANGUAGE C PARAMETER STYLE GENERAL

DB2 SQL stored procedure

This variation of the CREATE PROCEDURE statement defines a SQL-based procedure with a DB2 application server. A SQL procedure allows the following clauses:

CREATE PROCEDURE object_name [( [IN |

   OUT| INOUT] parameter_name datatype [,...] ) ]

   [SPECIFIC specific_name] [DYNAMIC RESULT SETS int]

   [CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA]

   [DETERMINISTIC | NOT DETERMINISTIC] [CALLED ON NULL INPUT]

   [INHERIT SPECIAL REGISTERS] [LANGUAGE SQL]

code_block

The following SQL stored procedure returns a customer's record based upon a SOUNDEX function on their name and state:

CREATE PROCEDURE prod.custlookup

 (IN in_lastname VARCHAR(15),

  IN in_st CHARACTER(2) )

  DYNAMIC RESULT SETS 1

  LANGUAGE SQL

  NOT DETERMINISTIC

  CALLED ON NULL INPUT

  MODIFIES SQL DATA

  INHERIT SPECIAL REGISTERS

  P1: BEGIN

    DECLARE cursor1 CURSOR WITH RETURN FOR

      SELECT *

        FROM prod.customer c

        WHERE SOUNDEX (c.lastname) = SOUNDEX (in_lastname)

          AND c.st = UPPER (in_st);

    OPEN cursor1;

  END P1;

DB2 has recently implemented new procedural extensions to SQL. You can now define the code_block for a DB2 UDF or stored procedure using conditional processing constructs like IF...THEN and WHILE loops (as shown in the examples above).

RETURNS TABLE is available as a return value for any LANGUAGE. The only clauses allowed are STATIC DISPATCH, DETERMINISTIC, EXTERNAL ACTION, RETURNS NULL ... | CALLED NULL... ON INPUT, and CARDINALITY.

READ SQL DATA and CONTAINS SQL are the only SQL-style options allowed when you chose LANGUAGE SQL. These clauses disable the CAST clause and the RETURNS NULL ON NULL INPUT clause. It also makes available (though optional) the RETURNS {ROW | TABLE} clause, FEDERATED clause, PREDICATES clause, and INHERIT SPECIAL REGISTERS clause.

ALTER FUNCTION and PROCEDURE on DB2 merely change the characteristics of an existing UDF or stored procedure. The two examples shown next make a function and a procedure, respectively, NOT FENCED.

ALTER FUNCTION mail( ) NOT FENCED;

ALTER PROCEDURE employee_pay NOT FENCED;

MySQL

MySQL does not support the ALTER FUNCTION statement, nor does it support the CREATE PROCEDURE and ALTER PROCEDURE statements.

All user-defined functions created on a MySQL database are, in effect, external function calls:

CREATE [AGGREGATE] FUNCTION function_name

RETURNS {STRING | REAL | INTEGER}

SONAME shared_program_library_name ;

where:


CREATE [AGGREGATE] FUNCTION function_name

Creates an external function with a function_name of not more than 64 characters. The module will be stored in the mysql2/udf directory, with an extension of .udf. If AGGREGATE is specified, the user-defined function must return an aggregate value like SUM( ) or AVG( ).


RETURNS {STRING | REAL | INTEGER}

Returns either STRING for character data, REAL for floating-point numbers, or INTEGER for whole numbers.


SONAME shared_program_library_name

Names the C/C++ program that performs the processing. This shared_program can be compiled and built into the MySQL engine, or it can function as an independent, linked program.

Once implemented, a MySQL UDF may be called just like any built-in function, such as ABS( ) or SOUNDEX( ).

The implementation of CREATE FUNCTION in MySQL is dependent on procedural code in C/C++ under an operating system that supports dynamic loading. The C/C++ program is named in the shared_program_library_name option. The function may be compiled either directly into the MySQL server, making the function permanently available, or as a dynamically callable program. For example, the code behind the UDF created in the following statement might be found on a Unix server:

CREATE FUNCTION find_radius RETURNS INT SONAME "radius.so";

Oracle

Oracle supports ALTER and CREATE for both FUNCTION and PROCEDURE object types. (You may also wish to learn about Oracle packages, which can also be used to create UDFs and stored procedures. Check Oracle's documentation.) Oracle's CREATE PROCEDURE syntax is as follows:

CREATE [OR REPLACE] {FUNCTION | PROCEDURE} [schema.]object_name

[(parameter1 [IN | OUT | IN OUT] [NOCOPY] datatype] [,...] ) ] ]

RETURN datatype

[DETERMINISTIC] [AUTHID {CURRENT_USER | DEFINER}]

[PARALLEL_ENABLE [( PARTITION prtn_name BY {ANY | {HASH | RANGE}

   (column [,...] ) [{ORDER | CLUSTER} BY (column [,...] ) ] ]

{ [PIPELINED | AGGREGATE] USING [schema.]implementation_type] |

   [PIPELINED] {IS | AS} }

{code_block | LANGUAGE {JAVA NAME external_program_name |

   C [NAME external_program_name]

   LIBRARY lib_name [AGENT IN (argument [,...]) [WITH CONTEXT]

   [PARAMETERS ( param [,...]) ] };

The ALTER FUNCTION and ALTER PROCEDURE statement shown next is used to recompile invalid UDFs or stored procedures:

ALTER {FUNCTION | PROCEDURE} [schema.]object_name

COMPILE [DEBUG] [compiler_param = value [...] ] [REUSE SETTINGS]

Following are the parameter descriptions:


CREATE [OR REPLACE] FUNCTION [schema.]object_name

Creates a new UDF or stored procedure. Use OR REPLACE to replace an existing procedure or UDF without first dropping it, and then having to reassign all permissions to it. Certain clauses are only used with user-defined functions, including the RETURN clause, the DETERMINISTIC clause, and the entirety of the USING clause.


[IN | OUT | IN OUT]

Specifies whether a parameter is an input to the function, an output from the function, or both.


NOCOPY

Speeds up performance when an OUT or IN OUT argument is very large, as with a VARRAY or RECORD datatype.


AUTHID {CURRENT_USER | DEFINER}

Forces the routine to run in the permission context of either the current user or the person who owns the function, using AUTHID CURRENT_USER or AUTHID DEFINER, respectively.


PARALLEL_ENABLE

Enables the routine to be executed by a parallel query operation on an SMP or parallel-processor server. This clause is used only for UDFs. (Don't use session state or package variables because they can't be expected to be shared among parallel execution servers.) Define the behavior of the PARALLEL_ENABLE query operation using these subclauses, where:


PARTITION prtn_name BY {ANY | {HASH | RANGE} (column [,...] )

Defines partitioning of inputs on functions with REF CURSOR arguments. This may benefit table functions. ANY allows random partitioning. You can restrict partitioning to a specific RANGE or HASH partition on a comma-delimited column list.


{ORDER | CLUSTER} BY (column [,...] )

Orders or clusters parallel processing based on a comma-delimited column list. ORDER BY causes the rows to be locally ordered on the parallel execution server according to the column list. CLUSTER BY restricts the rows on the parallel execution server to the key values identified in the column list.


{PIPELINED | AGGREGATE} [USING [schema.] implementation_type]

PIPELINED iteratively returns the results of a table function, instead of the normal serial return of the VARRAY or nested table result set. This clause is only used for UDFs. The clause PIPELINED USING implementation_type is for an external UDF that uses a language like C++ or Java. The AGGEGATE USING implementation_type clause defines a UDF as an aggregate function (a function that evaluates many rows, but returns a single value).


IS | AS

Oracle treats IS and AS equally. Use either one to introduce the code_block.


code_block

Oracle allows a PL/SQL code block for user-defined functions and stored procedures. Alternately, you may use the LANGUAGE clause for stored procedures written in Java or C.


LANGUAGE {JAVA NAME external_program_name | C [NAME external_program_name] LIBRARY lib_name [AGENT IN (argument) [WITH CONTEXT] [PARAMETERS ( params ) ] }

Defines the Java or C implementation of the external program. The parameters and semantics of each declaration are specific to Java and C, not SQL.


ALTER {FUNCTION | PROCEDURE} [schema.]object_name

Recompiles an invalid standalone stored routine. Use CREATE ... OR REPLACE to change the arguments, declarations, or definition of an existing routine.


COMPILE [DEBUG] [REUSE SETTINGS]

Recompiles the routine. Note that COMPILE is required. (You can see compile errors with the SQL*Plus command SHOW ERRORS.) The routine is marked valid if no compiler errors are encountered. The following optional subclauses may also be included with the COMPILE clause, where:


DEBUG

Generates and stores code used by the PL/SQL debugger.


compiler_param = value [...]

Specifies a PL/SQL compiler parameter. Allowable parameters include PLSQL_OPTIMIZE_LEVEL, PLSQL_CODE_TYPE, PLSQL_DEBUG, PLSQL_WARNINGS, and NLS_LENGTH_SEMANTICS. Refer to Oracle's documentation on the PL/SQL compiler for more details.


REUSE SETTINGS

Maintains the existing compiler switch settings and reuses them for recompilation. Normally, Oracle drops and reacquires compiler switch settings.

In Oracle, UDFs and stored procedures are very similar in composition and structure. The primary difference is that a stored procedure cannot return a value to the invoking process, while a function may return a single value to the invoking process.

For example, you can pass in the name of a construction project to the following function to obtain the project's profit:

CREATE OR REPLACE FUNCTION project_revenue (project IN varchar2)

RETURN NUMBER

AS

   proj_rev NUMBER(10,2);

BEGIN

   SELECT SUM(DECODE(action,'COMPLETED',amount,0)) -

          SUM(DECODE(action,'STARTED',amount,0))   +

          SUM(DECODE(action,'PAYMENT',amount,0))

   INTO proj_rev

   FROM construction_actions

   WHERE project_name = project;

   RETURN (proj_rev);

END;

In this example, the user-defined function accepts the project name as an argument. Then it processes the project revenue, behind the scenes, by subtracting the starting costs from the completion payment and adding any other payments into the amount. The RETURN (proj_rev); line returns the amount to the invoking process.

In Oracle, UDFs cannot be used in the following situations:

  • In a CHECK constraint or DEFAULT constraint of a CREATE TABLE or ALTER TABLE statement.

  • In a SELECT, INSERT, UPDATE, or DELETE, the UDF cannot, either directly or indirectly (if invoked by another routine):

    • Have an OUT or IN OUT parameter. (Indirect calls may take OUT and IN OUT parameters.)

    • Terminate the transaction with COMMIT, ROLLBACK, SAVEPOINT, or a CREATE, ALTER, or DROP statement that implicitly issues a COMMIT or ROLLBACK.

    • Use session control (SET ROLE) or system control (the Oracle-specific statement ALTER SYSTEM) statements.

    • Write to a database (when a component of a SELECT statement or a parallelized INSERT, UPDATE, or DELETE statement).

    • Write to the same table that is modified by the statement that calls the UDF.

Note that when you recompile a routine with the ALTER statement, it is marked valid if no compiler errors are encountered. (It is marked invalid if any errors are encountered.) Perhaps more importantly, any objects that depend upon the recompiled routine are marked invalid, regardless of whether an error occurs. You can either recompile those dependent objects yourself, or you can allow Oracle to take some additional time to recompile them at runtime.

By way of example, the following recompiles the project_revenue function and maintains any compiler information for the PL/SQL debugger:

ALTER FUNCTION project_revenue COMPILE DEBUG;

PostgreSQL

PostgreSQL supports the CREATE FUNCTION statement, but not CREATE PROCEDURE, ALTER FUNCTION, or ALTER PROCEDURE. Since PostgreSQL does not have an internal procedural language, user-defined functions are usually external functions, though they may be simple SQL queries. The syntax to use to create a function is:

CREATE [OR REPLACE] FUNCTION function_name

   ( [ parameter [,...] ] )

RETURNS datatype

AS {code_block | object_file, link_symbol}

LANGUAGE {C | SQL | PLPGSQL | PLTCL | PLTCLU | PLPERL |

   internal}

[WITH {[ISCACHABLE] [,] [ISSTRICT]} ]

where:


CREATE [OR REPLACE] function_name

Creates a new function of the name you provide, or replaces an existing function. OR REPLACE does not enable you to change the name, input parameters, or output results of an existing function. You must drop and recreate a function to change any of those settings.


RETURNS datatype

Specifies the type of data required by the function.


AS {code_block | object_file, link_symbol}

Defines the composition of the user-defined function. The code_block can be a string defining the function (dependent on the LANGUAGE setting), such as an internal function name, the path and name of an object file, a SQL query, or the text of a procedural language. The definition also can be an object file and link symbol for a C-language function.


LANGUAGE {C | SQL | PLPGSQL | PLTCL | PLTCLU | PLPERL | internal}

Defines a call to an external program or an internal SQL routine. Since all of the language options, except SQL, are programs compiled in other languages, they are beyond the scope of this book. However, the LANGUAGE SQL clause should be used when writing SQL user-defined functions.

Add a new language not installed by default on PostgreSQL by using the CREATE LANGUAGE statement.



[WITH {[ISCACHABLE] [,] [ISSTRICT]} ]

Optimizes PostgreSQL performance by indicating that the function always returns the same value when provided with the same parameter values. WITH ISCACHABLE is similar to the ANSI setting DETERMINISTIC, except that this setting then allows the optimizer to pre-evaluate the call of the function. WITH ISSTRICT is similar to the ANSI setting RETURNS NULL ON NULL INPUT. When omitted, the default behavior is similar to CALLED ON NULL INPUT. Note that you may include both keywords in a single function declaration.

PostgreSQL also allows function overloading in which the same function name is allowed for different functions, as long as they accept distinct input parameters.

Whenever you drop an existing function, all dependent objects are invalidated and must be recompiled.


Here's an example of a simple SQL function in PostgreSQL:

CREATE FUNCTION max_project_nbr

RETURNS int4

AS "SELECT MAX(title_ID) FROM titles AS RESULT"

LANGUAGE 'sql';

In this example, we created a UDF that returns the maximum title_ID from the titles table.

PostgreSQL uses CREATE FUNCTION as a substitute for CREATE PROCEDURE, as well as to define actions for CREATE TRIGGER.

SQL Server

SQL Server supports CREATE and ALTER for both types of routines. By default, SQL Server stored procedures can return result sets and SQL Server UDFs can return single or multirow result sets using the TABLE datatype on RETURNS arguments, contrary to the ANSI standard. However, this makes SQL Server routines more flexible and powerful. Use the following syntax to create a user-defined function or stored procedure:

CREATE {FUNCTION | PROCEDURE} [owner_name.]object_name[;int]

( [ {@parameter datatype [VARYING] [=default] [OUTPUT]} [,...] ] )

RETURNS {datatype | TABLE]

[WITH {ENCRYPTION | SCHEMABINDING | RECOMPILE |

   RECOMPILE, ENCRIPTION}]

[FOR REPLICATION]

[AS]

   code_block

Use the following syntax to alter an existing user-defined function or stored procedure:

ALTER {FUNCTION | PROCEDURE} [owner_name.]object_name[;int]

( [ {@parameter datatype [VARYING] [=default] [OUTPUT]} [,...] ] )

RETURNS {datatype | TABLE]

[WITH {ENCRYPTION | SCHEMABINDING | RECOMPILE |

   RECOMPILE, ENCRIPTION}]

[FOR REPLICATION]

[AS]

   code_block

Following are the parameter descriptions:


CREATE {FUNCTION | PROCEDURE} [owner_name.] object_name[;int]

Creates a new UDF or stored procedure in the current database. For SQL Server stored procedures, you may optionally specify a version number in the format procedure_name;1, where 1 is an integer indicating the version number. This facility allows you to have multiple versions of a single stored procedure.


{@parameter datatype [VARYING] [=default] [OUTPUT]} [,...]

Defines one or more input arguments for a UDF or stored procedure. SQL Server parameters are always declared with an at sign (@) as the first character.

where:


VARYING

Used in stored procedures with a CURSOR datatype parameter. Indicates that the result set is constructed dynamically by the procedure.


= default

Assigns a default value to the parameter. The default value is used whenever the stored procedure or UDF is invoked without supplying a value for the parameter.


OUTPUT

Used for stored procedures, OUTPUT is functionally equivalent to the ANSI OUT clause in the CREATE FUNCTION statement. The value stored in the return parameter is passed back to the calling procedure through the return variables of the SQL Server EXEC[UTE] command. Output parameters can be any datatype except TEXT and IMAGE.


RETURNS {datatype | TABLE}

Allows SQL Server UDFs to return a single datatype value or to return multiple values via the TABLE datatype. The TABLE datatype is considered inline if it has no accompanying column list and is defined with a single SELECT statement. If the RETURN clause returns multiple values via the TABLE datatype, and if the TABLE has defined columns and datatypes, the function is considered a multistatement, table-valued function.


WITH

Allows the assignment of additional characteristics to a SQL Server UDF or stored procedure.


ENCRYPTION

Tells SQL Server to encrypt the column in the system table that stores the text of the function, thus preventing unwarranted review of the function code. Usable by both UDFs and stored procedures.


SCHEMABINDING

Specifies that the function is bound to a specific database object, such as a table or view. That database object cannot be altered or dropped as long as the function exists (or maintains the SCHEMABINDING option). Usable only by UDFs.


RECOMPILE

Tells SQL Server not to store a cache plan for the stored procedure, but instead to recompile the cache plan each time the stored procedure is executed. This is useful when using atypical or temporary values in the procedure, but can cause serious degradation in performance. Used only by stored procedures. Note that RECOMPILE and ENCRYPTION can be invoked together.


FOR REPLICATION

Disables execution of the stored procedure on a subscribing server. It is used primarily to create a filtering stored procedure that is executed only by SQL Server's built-in replication engine. It is incompatible with RECOMPILE.

Like tables (see CREATE TABLE), local and global temporary stored procedures may be declared by prefixing a pound symbol (#) and double-pound symbol (##) to the name of the procedure, respectively. Temporary procedures exist only for the duration of the user or process session that created them. When that session ends, the temporary procedure automatically deletes itself.

A SQL Server stored procedure or UDF may have as many as 1,024 input parameters, specified by the at sign (@). Parameters are defined using SQL Server datatypes. (Parameters of CURSOR datatype must be both VARYING and OUTPUT.) The user or calling process must supply values for any input parameters. However, a default value can be supplied for any input parameter to allow the procedure to execute without a user- or process-supplied value. The default must be a constant or NULL, but it may contain wildcard characters, as discussed later in this chapter in the section LIKE Operator.

SQL Server requires that one or more user-supplied parameters be declared for a given user-defined function. All SQL Server datatypes are supported as parameters, except TIMESTAMP. Values returned by the function can be any datatype except TIMESTAMP, TEXT, NTEXT, or IMAGE. If an inline table value is required, the TABLE option without an accompanying column list may be used.

The ALTER FUNCTION and ALTER PROCEDURE statements support the full syntax provided by the corresponding CREATE statements. You can use the ALTER statements to change any of the attributes of an existing routine without changing permissions or affecting any dependent objects.


For UDFs, the code_block is either a single SELECT statement for an inline function, in the format RETURN (SELECT...), or a series of Transact-SQL statements following the AS clause for a multistatement operation. When using RETURN (SELECT), the AS clause is optional. Some other rules for SQL Server UDFs:

  • When using the AS clause, the code_body should be encapsulated in BEGIN...END delimiters.

  • UDFs cannot make any permanent changes to data or cause other lasting side effects. A number of other restrictions exist as a result. For example, INSERT, UPDATE, and DELETE statements may modify only TABLE variables local to a function.

  • When returning a scalar value, a SQL Server UDF must contain the clause RETURN datatype, where datatype is the same as that identified in the RETURNS clause.

  • The last statement of the code_block must be an unconditional RETURN that returns a single datatype value or TABLE value.

  • The code_block may not contain any global variables that return a perpetually changing value, such as @@CONNECTIONS or GETDATE. But it may contain those that return a single, unchanging value, such as @@SERVERNAME.

The following is an example of a scalar function that returns a single value. Once created, the scalar UDF can then be utilized in a query just like a system-supplied function. For example:

CREATE FUNCTION metric_volume -- Input dimensions in centimeters.

   (@length decimal(4,1),

   @width decimal(4,1),

   @height decimal(4,1) )

RETURNS decimal(12,3) -- Cubic Centimeters.

AS BEGIN

      RETURN ( @length * @width * @height )

   END

GO

SELECT project_name,

   metric_volume(construction_height,

      construction_length,

      construction_width)

FROM housing_construction

WHERE metric_volume(construction_height,

      construction_length,

      construction_width) >= 300000

GO

An inline table-valued UDF supplies values via a single SELECT statement using an AS RETURN clause. For example, we can supply a store ID and find all of their titles:

CREATE FUNCTION stores_titles (@stor_id varchar(30))

RETURNS TABLE

AS

RETURN (SELECT title, qty

   FROM sales AS s

   JOIN titles AS t ON t.title_id = s.title_id

   WHERE s.stor_id = @storeid )

Now, let's alter the UDF just a bit by changing the input argument datatype length and adding another condition to the WHERE clause (indicated in boldface):

ALTER FUNCTION stores_titles

(@stor_id VARCHAR(4))

RETURNS TABLE

AS

RETURN (SELECT title, qty

   FROM sales AS s

   JOIN titles AS t ON t.title_id = s.title_id

   WHERE s.stor_id = @storeid

AND s.city = 'New York')

User-defined functions that return TABLE values are often selected as result set values or are used in the FROM clause of a SELECT statement, just as a regular table is used. These multi-statement, table-valued functions can have very elaborate code bodies since the code_block is composed of many Transact-SQL statements that populate a TABLE return variable.

Here is an example invoking a multistatement, table-valued function in a FROM clause. Notice that a table alias is assigned, just as for a regular table:

SELECT co.order_id, co.order_price

FROM   construction_orders AS co,

       fn_construction_projects('Cancelled') AS fcp

WHERE  co.construction_id = fcp.construction_id

ORDER BY co.order_id

GO

For stored procedures, the code_block clause contains one or more Transact-SQL commands, up to a maximum size of 128 MB, delimited by BEGIN and END clauses. Some rules about Microsoft SQL Server stored procedures include:

  • The code_block allows most valid Transact-SQL statements, but SET SHOWPLAN_TEXT and SET SHOWPLAN_ALL are prohibited.

  • Some other commands have restricted usages within stored procedures, including ALTER TABLE, CREATE INDEX, CREATE TABLE, all DBCC statements, DROP TABLE, DROP INDEX, TRUNCATE TABLE, and UPDATE STATISTICS.

  • SQL Server allows deferred name resolution, meaning that a stored procedure compiles without an error even though it references an object that has not yet been created. SQL Server creates the execution plan and fails only when the object is actually invoked, for instance in a stored procedure, if the object still doesn't exist.

  • Stored procedures can be nested easily in SQL Server. Whenever a stored procedure invokes another stored procedure, the system variable @@NESTLEVEL is incremented by 1. It is decreased by 1 when the called procedure completes. Use SELECT @@NESTLEVEL inside a procedure or from an ad hoc query session to find the current nesting depth.

In the following example, a SQL Server stored procedure generates a unique 22-digit value (based on elements of the system date and time) and returns it to the calling process:

-- A Microsoft SQL Server stored procedure

CREATE PROCEDURE get_next_nbr

   @next_nbr CHAR(22) OUTPUT

AS

BEGIN

  DECLARE @random_nbr INT

  SELECT @random_nbr = RAND( ) * 1000000

SELECT @next_nbr =

  RIGHT('000000' + CAST(ROUND(RAND(@random_nbr)*1000000,0))

     AS CHAR(6), 6) +

  RIGHT('0000' + CAST(DATEPART (yy, GETDATE( ) )

     AS CHAR(4)), 2) +

  RIGHT('000'  + CAST(DATEPART (dy, GETDATE( ) )

     AS CHAR(3)), 3) +

  RIGHT('00'   + CAST(DATEPART (hh, GETDATE( ) )

     AS CHAR(2)), 2) +

  RIGHT('00'   + CAST(DATEPART (mi, GETDATE( ) )

     AS CHAR(2)), 2) +

  RIGHT('00'   + CAST(DATEPART (ss, GETDATE( ) )

     AS CHAR(2)), 2) +

  RIGHT('000'  + CAST(DATEPART (ms, GETDATE( ) )

     AS CHAR(3)), 3)

END

GO

See Also

CALL
RETURN
CREATE/ALTER INDEX Statement

Indexes are special objects built on top of tables that speed many data-manipulation operations, such as SELECT, UPDATE, and DELETE statements. The selectivity of a given WHERE clause and the available query plans the database query optimizer can choose from is usually based upon the quality of indexes that have been placed on the table in a given database.

The CREATE INDEX command is not a part of the ANSI SQL standard, and thus varies greatly among vendors.

Platform

Command

DB2

Supported, with variations

MySQL

Supported, with variations

Oracle

Supported, with variations

PostgreSQL

Supported, with variations

SQL Server

Supported, with variations


Common Vendor Syntax

CREATE [UNIQUE] INDEX index_name ON table_name

(column_name [, ...])

Keywords


CREATE [UNIQUE] INDEX index_name

Creates a new index named index_name in the current database and schema context. Since indexes are associated with specific tables (or sometimes views), the index_name need only be unique to the table it is dependent on. The UNIQUE keyword defines the index as a unique constraint for the table and disallows any duplicate values into the indexed column or columns of the table. (Refer to Section 2.4.)


ON table_name

Declares the pre-existing table that the index is associated with. The index is dependent upon the table. If the table is dropped, so is the index.


(column_name [, ...])

Defines one or more columns in the table that are indexed. The pointers derived from the indexed column or columns enable the database query optimizer to greatly speed up data manipulation operations like SELECT and DELETE statements. All major vendors support composite indexes, also known as concatenated indexes. These indexes are used when two or more columns are best searched as a unit-for example, last name and first name.

Rules at a Glance

Indexes are created on tables to speed data manipulation operations that go against the tables such as those in a WHERE or JOIN clause. Indexes may also speed other operations, like:

  • Identifying a MIN( ) or MAX( ) value in an indexed column.

  • Sorting or grouping columns of a table.

  • Searching based on IS NULL or IS NOT NULL.

  • Fetching data much more quickly when the indexed data is all that is requested. A SELECT statement that retrieves data from an index and not directly from the table itself is called a covering query. An index that answers a query in this way is a covering index.

After creating a table, you can create indexes on columns within the table. It is a good idea to create indexes on columns that are frequently part of the WHERE clause or JOIN clause of the queries that go against a table. For example, the following statement creates an index on a column in the sales table that is frequently used in the WHERE clause of queries against that table:

CREATE INDEX ndx_ord_date ON sales(ord_date);

In another case, we want to set up the pub_name and country as a unique index on the publishers table:

CREATE UNIQUE INDEX unq_pub_id ON publishers(pub_name, country);

Since the index is unique, any new record entered into the publishers table must have a unique combination of publisher name and country.

Some vendor platforms allow you to create indexes on views as well as tables.


Programming Tips and Gotchas

Concatenated indexes are most useful when queries address the columns of the index starting from the left. If you omit left-side columns in a query against a concatenated key, the query may not perform as well. For example, assume that we have a concatenated index on (last_name, first_name). If we query only by first_name, the concatenated index that starts with last_name and includes first_name may not be any good to us. Some of the vendor platforms have advanced their query engines to the point where this is much less of a problem.

Creating an index may take as much as 1.2 to 1.5 times more space than the table currently occupies. Make sure you have enough room! Most of that space is released after the index has been created.


You should be aware that there are situations in which too many indexes can actually slow down system performance. In general, indexes greatly speed lookup operations, especially in SELECT statements, against a table or view. However, every index you create adds overhead whenever you perform an UPDATE, DELETE, or INSERT operation because the database must then update all dependent indexes with the values that have changed in the table. As a rule of thumb, six to twelve indexes are about the most you might want to create on a single table.

In addition, indexes take up extra space within the database. The more columns in an index, the more space it consumes. This is not usually a problem, but sometimes catches novices off guard when developing a new database.

Most databases use indexes to create statistical samplings, usually just called statistics, so that the query engine can quickly determine which, if any, index or combination of indexes will be most useful for a query. These indexes are always fresh and useful when the index is first created, but may become stale and less useful over time as records are deleted, updated, and inserted within the table. Consequently, indexes, like day-old bread, are not guaranteed to be useful as they age. You need to be sure to refresh, rebuild, and maintain your databases regularly to keep index statistics fresh.

DB2

DB2 supports the CREATE INDEX statement, but not the ALTER INDEX statement. (DB2 does have the COMMENT ON INDEX statement to allow users to update the comment for an index without dropping and recreating the index. Also, DB2 has a RENAME INDEX statement to rename an index with having to drop and recreate it.) The CREATE INDEX statement has additional clauses that allow partitioning based upon indexed columns, as well as other clauses that impact how data is physically arranged on disk:

CREATE [UNIQUE] INDEX index_name

ON table_name ({column_name [ASC | DESC]} [, ...])

[SPECIFICATION ONLY]

[INCLUDE (column_name [ASC | DESC] [,...] )]

[{CLUSTER | EXTEND USING index_extension [(constant [,...]) ] } ]

[PCTFREE int] [MINPCTUSED int]

[[DIS]ALLOW REVERSE SCANS]

[COLLECT [SAMPLED [DETAILED] ] STATISTICS]

where:


ASC | DESC

Specifies that the values in the index are kept in either ascending (ASC) or descending (DESC) order. When ASC or DESC is omitted, ASC is used by default.


SPECIFICATION ONLY

Used to indicate that the value defined by table_name is a nickname; that is, it is the name of a table in a federated database. A DB2 federated database integrates data from heterogeneous data sources, such as tables on Oracle or SQL Server, and names them locally within the DB2 database as a nickname. To tell the DB2 optimizer about indexes on one of these nicknamed Oracle or SQL Server tables, create an index against the nickname and declare SPECIFICATION ONLY. DB2 then knows that the index exists and is available to the optimizer, but that it does not have to create the index.


INCLUDE (column_name [,...])

Adds extra columns to a unique index for added selectivity, but any such included columns are not counted towards uniqueness. The main use for INCLUDE columns is to build covering indexes. Any columns added with the INCLUDE clause count towards the column and byte maximum allowed by DB2. INCLUDE is mutually exclusive of EXTEND USING and SPECIFICATION ONLY clauses, and cannot be used when indexing temporary tables.


CLUSTER

Declares that the index is clustered. A clustered index specifically controls the physical arrangement of the rows in the table to speed query I/O. The cluster factor is maintained and improved dynamically as data is inserted into the table. Only one clustered index is allowed per table. CLUSTER is mutually exclusive of EXTEND USING and SPECIFICATION ONLY clauses, and cannot be used with temporary tables or tables in append mode.


EXTEND USING index_extension [(constant [,...]) ]

Names an index extension that manages the index. The index must be defined on a single column that is either a structured or a distinct type. One or more constants must be provided for any parameters required by the type. EXTEND cannot be used on a temporary table. Index extensions are very complex and somewhat uncommon. Refer to the vendor documentation for more detail.


PCTFREE int

Specifies a percentage (int) of space, which must be an integer of 0 to 99, to leave free on each index page of the index when it is created. When omitted, the default is 10. This option cannot be used on nicknames or temporary tables.


MINPCTUSED int

Defines the percentage (int) of free space, which must be an integer of 0 to 99, required on an index page before DB2 will consider merging index pages together. DB2 recommends a value of 50 or below so that the database will not spend excessive I/O merging index pages. This clause is usually effective only if background processes are able to gain an occasional table lock. If this is not possible due to heavy usage, consider using the DB2 command REORG INDEXES. This option cannot be used on nicknames or temporary tables.


[DIS]ALLOW REVERSE SCANS

Declares that the index can or cannot support scans under the order that the index was created in, with ALLOW and DISALLOW, respectively. The default is DISALLOW. This option cannot be used on nicknames.


COLLECT [SAMPLED [DETAILED] ] STATISTICS

Collects index statistics during index creation. If the SAMPLED and DETAILED clauses are left off, then basic index statistics are created. The DETAILED clause collects extra statistics information for the index, namely PAGE_FETCH_PAIRS and CLUSTERFACTOR. The SAMPLED clause tells DB2 that sampling, a shortcut, can be used on extra statistics information from the DETAILED clause.

DB2 will not create a new index where an identical index exists. DB2 considers an index identical to another when one index contains the same columns in the same order as the other.

DB2 allows online use of a table while a new index is being created. Read access is always available during the index creation process, but write access is temporarily locked at the end of the index build process. Use the DB2 command LOCK TABLE to temporarily lock the table and avoid read access. You should also use the DB2 command RUNSTATS to update index statistics whenever a great deal of data has changed or after an index is created without the COLLECT STATISTICS clause included in the statement. The following two index creation examples are functionally the same:

-- collect basic index statistics at index creation

CREATE INDEX ndx_ord_date ON sales(ord_date) COLLECT STATISTICS;

-- collect index statistics after index creation

LOCK TABLE sales IN EXCLUSIVE MODE;

CREATE INDEX ndx_ord_date ON sales(ord_date);

RUNSTATS ON TABLE sales AND INDEX ndx_ord_date;

Now, we'll collect detailed statistics using sampling on the publishers table:

CREATE UNIQUE INDEX unq_pub_id ON publishers(pub_name, country)

COLLECT SAMPLED DETAILED STATISTICS;

You may wish to create an index on a nicknamed object. In the example below, the publishers nickname represents the current_publishers table:

CREATE UNIQUE INDEX unq_pub_id ON publishers(pub_name, country)

SPECIFICATION ONLY;

The following example shows how to create an extended indextype on a structured type column. The coordinate_positions UDT requires a literal value to maintain the satellite_images column:

CREATE INDEX satellite_images ON gis_sites(coordinates)

EXTEND USING (coordinate_positions (x'00010010010000100020'));

DB2 also supports a statement called CREATE INDEX EXTENSION. It is used to enable user-defined indexing on typed tables. Refer to the vendor documentation for more details.


MySQL

MySQL supports a form of the CREATE INDEX statement, but not the ALTER INDEX statement. MySQL indexes are always stored in B-tree structures on the filesystem. Strings within an index are automatically prefix- and end-space-compressed. MySQL's CREATE INDEX syntax is:

CREATE [UNIQUE | FULLTEXT] INDEX index_name

   ON table_name (column_name(length) [,...])

where:


FULLTEXT

Creates a full-text search index against a column. Full-text indexes are only supported on MyISAM table types, CHAR, VARCHAR, or TEXT datatypes, and do not support the (length) clause.

MySQL supports the basic industry standard syntax for the CREATE INDEX statement. Interestingly, MySQL also lets you build an index on the first length characters of a CHAR or VARCHAR column. MySQL requires the (length) clause for BLOB and TEXT columns. Specifying a length can be useful when selectivity is sufficient in the first, say, 10 characters of a column, and in those situations where saving disk space is very important. For example:

CREATE UNIQUE INDEX unq_pub_id ON publishers(pub_name(25),

   country(10))

This example indexes only the first 25 characters of the pub_name column and the first 10 characters of the country column.

As a general rule, MySQL allows at least 16 keys per table with a total maximum length of at least 256 bytes. This can vary by storage engine, however.

Oracle

Oracle allows the creation of indexes on tables, partitioned tables, clusters, and index-organized tables, as well as on scalar type object attributes of a typed table or cluster, and on nested table columns using the CREATE INDEX statement. Oracle also allows several types of indexes, including normal B-tree indexes, BITMAP indexes (useful for columns that have each value repeated 100 or more times), partitioned indexes, function-based indexes (based on an expression rather than a column value), and domain indexes.

Oracle index names must be unique within a schema, not just to the table they are assigned to.


Oracle also supports the ALTER INDEX statement. It is used to change or rebuild an existing index without forcing the user to drop and recreate the index. Oracle's CREATE INDEX syntax is:

CREATE [UNIQUE | BITMAP] INDEX index_name

{ON

   {table_name ( {column | expression} [ASC | DESC] [,...]) [{INDEXTYPE IS

      index_type [PARALLEL [int] | NOPARALLEL] [PARAMETERS ('values') }] |

   CLUSTER cluster_name |

   FROM table_name WHERE condition [LOCAL partitioning] }

[ {LOCAL partitioning | GLOBAL partitioning} ]

[physical_attributes_clause] [{LOGGING | NOLOGGING}] [ONLINE]

[COMPUTE STATISTICS] [{TABLESPACE tablespace_name | DEFAULT}]

[{COMPRESS int | NOCOMPRESS}] [{NOSORT | SORT}] [REVERSE]

[{PARALLEL [int] | NOPARALLEL}]

The syntax for ALTER INDEX is:

ALTER INDEX index_name

{ {ENABLE | DISABLE} | UNUSABLE | RENAME TO new_index_name | COALESCE |

   [NO]MONITORING USAGE | UPDATE BLOCK REFERENCES |

   PARAMETERS ( 'ODCI_params') | alter_index_partitioning_clause |

   rebuild_clause |

      [DEALLOCATE UNUSED [KEEP int [K | M | G | T] ]

      [ALLOCATE EXTENT ( [SIZE int [K | M | G | T] ] [DATAFILE 'filename']

         [INSTANCE int] ) ]

      [SHRINK SPACE [COMPACT] [CASCADE] ]

      [{PARALLEL [int] | NOPARALLEL}]

      [{LOGGING | NOLOGGING}]

      [physical_attributes_clause] }

where the non-ANSI clauses are:


BITMAP

Creates an index bitmap for each index value, rather than indexing each individual row. Bitmaps are best for low concurrency tables, like read-intensive tables. BITMAP indexes are incompatible with global partitioned indexes, the INDEXTYPE clause, or index-organized tables without a mapping table association.


ASC | DESC

Specifies that the values in the index are kept in either ascending (ASC) or descending (DESC) order. When ASC or DESC is omitted, ASC is used by default. However, be aware that Oracle treats DESC indexes as function-based indexes, so there is some difference in functionality between ASC indexes and DESC indexes. You may not use ASC or DESC when also using the INDEXTYPE clause. DESC is ignored on BITMAP indexes.


INDEXTYPE IS index_type [PARAMETERS ('values')]

Creates an index on a user-defined type of index_type. Domain indexes require that the user-defined type already exists (refer to the CREATE/ALTER TYPE Statement section). If the user-defined type requires arguments, pass them in using the optional PARAMETERS clause. You may also optionally parallelize the creation of the type index using the PARALLEL clause (explained below in more detail).


CLUSTER cluster_name

Declares a clustering index based on the specified pre-existing cluster_name. On Oracle, a clustering index physically co-locates two tables that are frequently queried on the same columns, usually a primary key and a foreign key. (Clusters are created with the Oracle-specific command CREATE CLUSTER.) You do not declare a table or columns on a CLUSTER index, since both the tables involved and the columns indexed are already declared with the previously issued CREATE CLUSTER statement.


GLOBAL partitioning

Includes the full syntax of:

GLOBAL PARTITION BY 

   {RANGE (column_list) ( PARTITION [partition_name] VALUE LESS THAN 

      (value_list) [physical_attributes_clause] [TABLESPACE 

      tablespace_name] [LOGGING | NOLOGGING] } [,...] ), |

   HASH (column_list) ( PARTITION [partition_name] 

      {[TABLESPACE tablespace_name] [[OVERFLOW] TABLESPACE

         tablespace_name] [VARRAY varray_name STORE AS {LOB 

         lob_segment_name] [LOB (lob_name) STORE AS [lob_segment_name] 

         [TABLESPACE tablespace_name] } } |

      [STORE IN (tablespace_name [,...])] [OVERFLOW STORE IN 

         (tablespace_name [,...] ), } [,...] }

The GLOBAL PARTITION clause declares that the global index is manually partitioned via either range or hash partitioning onto partition_name. (The default is to partition the index equally in the same way the underlying table is partitioned, if at all.) You can specify a maximum of 32 columns, though none may be ROWID. You may also apply the [NO]LOGGING clause, TABLESPACE clause, and the physical_attributes_clause (defined earlier) to a specific partition. You cannot partition on ROWID. You may include one or more partitions, along with any attributes, in a comma-delimited list, according to the following:


RANGE

Creates a range-partitioned global index based on the range of values from the table columns listed in the column_list.


VALUE LESS THAN (value_list)

Sets an upper bound for the current partition of the global index. The values in the value_list correspond to the columns in the column_list, both of which are comma-delimited lists of columns. Both lists are prefix-dependent, meaning that for a table with columns (a, b, c), you could define partitioning on (a, b) or (a, b, c), but not (b, c). The last value in the list should always be the keyword MAXVALUE.


HASH

Creates hash-partitioned global index assigned rows in the index to each partition based on a hash function of the values of the columns in the column_list. You may specify the exact tablespace to store special database objects such as VARRAYs, and LOBs, and for any OVERFLOW of the specified (or default) tablespaces.


LOCAL partitioning

Supports local index partitioning on range-partitioned indexes, list-partitioned indexes, hash-partitioned indexes, and composite-partitioned indexes. You may include zero or more partitions, along with any attributes, in a comma-delimited list. When omitted, Oracle generates one or more partitions consistent with those of the table partition. Index partitioning is done in one of three ways:


Range- and list-partitioned indexes

Applied to regular or equipartitioned tables. Range- and list-partitioned indexes (synonyms for the same thing) follow the syntax:

LOCAL [ (PARTITION [partition_name] 

   { [physical_attributes_clause] [TABLESPACE tablespace_name]    

      [LOGGING | NOLOGGING] |   

   [COMPRESS | NOCOMPRESS] } [,...] ) ]

All of the options are the same as for GLOBAL PARTITION (earlier), except that the scope is for a local index.


Hash-partitioned indexes

Applied to hash-partitioned tables. Hash-partitioned indexes allow you to choose between the earlier syntax and the optional syntax:

 LOCAL {STORE IN (tablespace_name [,...] )  |

   (PARTITION [partition_name [TABLESPACE tablespace_name] ] } 

to store the index partition on a specific tablespace. When you supply more tablespace names than index partitions, Oracle will cycle through the tablespaces when it partitions the data.


Composite-partitioned indexes

Composite-partitioned indexes can be applied on composite-partitioned tables using the following syntax:

LOCAL [STORE IN (tablespace_name [,...] ) ]

PARTITION [partition_name 

   {[physical_attributes_clause] [TABLESPACE tablespace_name] 

   [LOGGING | NOLOGGING] |   

   [COMPRESS | NOCOMPRESS] }

      [ {STORE IN (tablespace_name [,...] ) |

      (SUBPARTITION [subpartition_name [TABLESPACE 

           tablespace_name]) } ]

You may use the LOCAL STORE clause shown under the hash-partitioned indexes entry or from the LOCAL clause under the range- and list-partitioned indexes entry. (When using the LOCAL clause, substitute the keyword SUBPARTITION for PARTITION.)


physical_attributes_clause

Establishes values for one or more of the following settings: PCTFREE int (discussed here), INITRANS int, and STORAGE (discussed in theCREATE/ALTER TABLE Statement section). When omitted, Oracle defaults to PCTFREE 10 and INITRANS 2. The default for MAXTRANS depends on the system block size, according to the following:


PCTFREE int

Designates the percentage of free space to leave on each block of the index as it is created. This speeds up new entries and updates on the table. However, PCTFREE is only applied when the index is created. It is not maintained over time. Therefore, the amount of free space can erode over time as records are inserted, updated, and deleted from the index. This clause is not allowed on index-organized tables.


INITRANS int

Designates the initial number of concurrent transactions allocated to each data block of the database. The value may range from 1 to 255. If a physical_attributes_clause is omitted, Oracle defaults to PCTFREE 10 and INITRANS 2.


LOGGING | NOLOGGING

Tells Oracle to log the creation of the index on the redo logfile (LOGGING), or to not log it (NOLOGGING). This clause also sets the default behavior for subsequent bulk loads using Oracle SQL* Loader. For partitioned indexes, this clause establishes the default value of all partitions, segments associated with the partitions, and the defaults used on any partitions or subpartitions later added with an ALTER TABLE...ADD PARTITION statement. (When using NOLOGGING, we recommend that you take a full backup after the index has been loaded in case the index must be rebuilt due to a failure.)


ONLINE

Allows data manipulation on the table while the index is being created. Even when ONLINE, there is a very small window at the end of the create index operation where the table will be locked while the index creation completes. Any changes made to the base table at that time will then be reflected in the newly created index. ONLINE is incompatible with bitmap, cluster, or parallel clauses. It also cannot be used on indexes on a UROWID column or on index-organized tables with more than 32 columns in their primary keys.


COMPUTE [STATISTICS]

Collects statistics while the index is created, when it can be done at relatively little cost. Otherwise, you will have to collect statistics after the index is created.


TABLESPACE tablespace_name | DEFAULT

Assigns the index to a specific tablespace. When omitted, the index is placed on the default tablespace. Use the DEFAULT keyword to explicitly place an index into the default tablespace. (When local partitioned indexes are placed in TABLESPACE DEFAULT, the index partition (or subpartition) is placed in the corresponding tablespace of the base table partition (or subpartition).


COMPRESS [int] | NOCOMPRESS

Enables or disables key compression, respectively. Compression eliminates repeated occurrences of key column values, yielding a substantial space savings at the cost of speed. The integer value, int, defines the number of prefix keys to compress. The value can range from 1 to the number of columns in the index for nonunique indexes, and from 1 to n-1 columns for unique indexes. The default is NOCOMPRESS, but if you specify COMPRESS without an int value, the default is COMPRESS n (for nonunique indexes) or COMPRESS n-1 (for unique indexes), where n is the number of columns in the index. COMPRESS can only be used on nonpartitioned and nonbitmapped indexes.


NOSORT | REVERSE

NOSORT an index to be created quickly for a column that is already sorted in ascending order. If the values of the column are not in perfect ascending order, the operation aborts, allowing a retry without the NOSORT option. REVERSE, by contrast, places the index blocks in storage by reverse order (excluding rowid). REVERSE is mutually exclusive of NOSORT and cannot be used on a bitmap index or an index-organized table. NOSORT is most useful for creating indexes immediately after a base table is loaded with data in pre-sorted order.


PARALLEL [int] | NOPARALLEL

Allows the parallel creation of the index using multiple server process, each operating on a distinct subset of the index, to speed up the operation. An optional integer value, int, may be supplied to define the exact number of parallel threads used in the operation. When omitted, Oracle calculates the number of parallel threads to use. NOPARALLEL, the default, causes the index to be created serially.


{ENABLE | DISABLE}

Enables or disables a pre-existing function-based index, respectively. You cannot specify any other clauses of the ALTER INDEX statement with ENABLE or DISABLE.


UNUSABLE

Marks the index (or index partition or subpartition) as unusable. When UNUSABLE, an index (or index partition or subpartition) may only be rebuilt or dropped and recreated before it can be used.


RENAME TO new_index_name

Renames the index from index_name to new_index_name.


COALESCE

Merges the contents of index blocks used to maintain the index-organized table so that the blocks can be reused. COALESCE is similar to SHRINK, though COALESCE compacts the segments less densely than does SHRINK, and it does not release unused space.


[NO]MONITORING USAGE

Declares that Oracle should clear existing information on index usage and monitor the index, posting information in the V$OBJECT_USAGE dynamic performance view, until ALTER INDEX ... NOMONITOR USAGE is executed.


UPDATE BLOCK REFERENCES

Updates all stale guess data block addresses stored as part of the index row on normal or domain indexes of an index-organized table. The guess data blocks contain the correct database addresses for the corresponding blocks identified by the primary key. This clause cannot be used with other clauses of the ALTER INDEX statement.


PARAMETERS ( 'ODCI_params')

Specifies a parameter string passed, without interpretation, to the ODCI indextype routine of a domain index. The parameter string, called 'ODCI_params', may be up to 1,000 characters long. Refer to the vendor documentation for more information on ODCI parameter strings.


alter_index_partitioning_clause

Refer to Oracle partitioned and subpartitioned tables in the CREATE/ALTER TABLE Statement section for more details.


rebuild_clause

Rebuilds the index or a specific partition (or subpartition) of the index. A successful rebuild marks an UNUSABLE index as USABLE. The syntax for the rebuild_clause is:

REBUILD {[NO]REVERSE | [SUB]PARTITION partn_name}

   [{PARALLEL [int] | NOPARALLEL}] [TABLESPACE tablespace_name]

   [PARAMETERS ( 'ODCI_params')] [ONLINE] [COMPUTE STATISTICS]

   [COMPRESS int | NOCOMPRESS] [[NO]LOGGING]

   [physical_attributes_clause]

where:


[NO]REVERSE

Stores the bytes of the index block in reverse order and excludes rows when the index is rebuilt (REVERSE) or stores the bytes of the index blocks in regular order (NOREVERSE).


DEALLOCATE UNUSED [KEEP int [K | M | G | T]

Deallocates unused space at the end of the index (or at the end of each range- or hash-partition of a partitioned index) and frees the space for other segments in the tablespace. The optional KEEP keyword defines how many bytes, int, above the high-water mark the index will keep after deallocation. You can append a suffix to the int value to indicate that the value equals kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T). When the KEEP clause is omitted, all unused space is freed.


ALLOCATE EXTENT ( [SIZE int [K | M | G | T] ] [DATAFILE 'filename'] [INSTANCE int] )

Explicitly allocates a new extent for the index using the specified parameters. You may mix and match any of the parameters. SIZE specifies the amount of next extent. The size of the extents may be in bytes (no suffix), kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T). DATAFILE allocates an entirely new datafile to the index extent. INSTANCE, used only on Oracle Real Application Clusters, makes a new extent available to a freelist group associated with the specified instance.


SHRINK SPACE [COMPACT] [CASCADE]

Shrinks the index segments, though only segments in tablespaces with automatic segment management may be shrunk. Shrinking a segment moves rows in the table, so make sure ENABLE ROW MOVEMENT is also used in the ALTER TABLE...SHRINK statement. Oracle compacts the segment, releases the emptied space, and adjusts the high-water mark unless the optional keywords COMPACT and/or CASCADE are applied. The COMPACT keyword only defragments the segment space and compacts the index, but it does not readjust the high-water mark nor empty the space immediately. The CASCADE keyword performs the same shrinking operation (with some restrictions and exceptions) on all dependent objects of the index. The statement ALTER INDEX ... SHRINK SPACE COMPACT is functionally equivalent to ALTER INDEX ... COALESCE.

By default, Oracle indexes are non-unique. It is also important to know that Oracle's regular B-tree indexes do not include records that have a null key value.

Oracle does not support indexes on columns with the following datatypes: LONG, LONG RAW, REF (with the SCOPE attribute), or user-defined datatypes. You may create indexes on functions and expressions, but they cannot allow null values or aggregate functions. When you create an index on a function, the function, if it has no parameters, should show an empty set. For example: function_name( ). If the function is a UDF, it must be DETERMINISTIC.

Oracle supports a special index structure called an index-organized table (IOT). IOTs combine the table data and primary key index on a single physical structure, instead of having separate structures for the table and for the index. IOTs are created using the CREATE TABLE...ORGANIZATION INDEX statement. Refer to CREATE/ALTER TABLE Statement for more information on making an IOT.

Oracle automatically creates any additional indexes on an index-organized table as secondary indexes. Secondary indexes do not support the REVERSE clause.

Oracle allows the creation of partitioned indexes and tables with the PARTITION clause. Consequently, Oracle's indexes also support partitioned tables. The LOCAL clause tells Oracle to create separate indexes for each partition of a table. The GLOBAL clause tells Oracle to create a common index for all the partitions.

Note that any time an object name is referenced in the syntax diagram, you may optionally supply the schema. This applies to indexes, tables, etc., but not to tablespaces. You must have the explicitly declared privilege to create an index in a schema besides the current one.

As an example, you can use a statement such as the following to create an Oracle index that is compressed, created in parallel, and with compiled statistics, but without logging the creation:

CREATE UNIQUE INDEX unq_pub_id ON publishers(pub_name, country)

COMPRESS 1 PARALLEL NOLOGGING COMPUTE STATISTICS;

As with other Oracle object creation statements, you can control how much space they consume and in what increments they grow. The following example constructs an index in Oracle on a specific tablespace with specific instructions for how the data is to be stored:

CREATE UNIQUE INDEX unq_pub_id ON publishers(pub_name, country)

STORAGE (INITIAL 10M NEXT 5M PCTINCREASE 0)

TABLESPACE publishers;

For example, when you create the housing_construction table as a partitioned table on an Oracle server, you should also create a partitioned index with its own index partitions:

CREATE UNIQUE CLUSTERED INDEX project_id_ind

ON housing_construction(project_id)

GLOBAL PARTITION BY RANGE (project_id)

   (PARTITION part1 VALUES LESS THAN ('H')

      TABLESPACE construction_part1_ndx_ts,

   PARTITION part2 VALUES LESS THAN ('P')

      TABLESPACE construction_part2_ndx_ts,

   PARTITION part3 VALUES LESS THAN (MAXVALUE)

      TABLESPACE construction_part3_ndx_ts);

If in fact the housing_construction table used a composite partition, we could accommodate that here:

CREATE UNIQUE CLUSTERED INDEX project_id_ind

ON housing_construction(project_id)

STORAGE (INITIAL 10M MAXEXTENTS UNLIMITED)

LOCAL (PARTITION part1 TABLESPACE construction_part1_ndx_ts,

       PARTITION part2 TABLESPACE construction_part2_ndx_ts

          (SUBPARTITION subpart10, SUBPARTITION subpart20,

           SUBPARTITION subpart30, SUBPARTITION subpart40,

           SUBPARTITION subpart50, SUBPARTITION subpart60),

       PARTITION part3 TABLESPACE construction_part3_ndx_ts);

In the following example, we could rebuild the project_id_ind index that was created earlier by using parallel execution processes to scan the old index and build the new index in reverse order:

ALTER INDEX project_id_ind

REBUILD REVERSE PARALLEL;

Similarly, we could split out an additional partition on project_id_ind:

ALTER INDEX project_id_ind

SPLIT PARTITION part3 AT ('S')

INTO (PARTITION part3_a TABLESPACE constr_p3_a LOGGING,

      PARTITION part3_b TABLESPACE constr_p3_b);

PostgreSQL

PostgreSQL allows the creation of ascending-order indexes, as well as UNIQUE indexes. Its implementation also includes a performance enhancement under the USING clause. PostgreSQL's CREATE INDEX syntax is:

CREATE [UNIQUE] INDEX index_name ON table_name

[USING {BTREE | RTREE | HASH} ]

{function_name | (column_name [,...] ) }

[WHERE condition]

where:


USING [BTREE | RTREE | HASH | GIST]

Specifies one of three dynamic access methods to optimize performance. Of particular importance is the fact that the indexes are fully dynamic and do not require periodic refreshes of their statistics. The USING options are as follows:


BTREE

Uses Lehman-Yao's high-concurrency B-tree structures to optimize the index. This is the default method when no other is specified. B-tree indexes, the default, can be invoked for comparisons using =, <, <=, >, and >=. B-tree supports multicolumn indexes.


RTREE

Uses Guttman's quadratic-split algorithm R-tree structures to optimize the index. R-tree indexes can be invoked for comparison using <<, &<, &>, >> @, ~=, and &&. R-tree indexes must be single-column indexes.


HASH

Uses Litwin's linear hashing algorithm to optimize the index. Hash indexes can be invoked for comparisons using =. Hash indexes must be single-column indexes.


GIST

Uses Generalized Index Search Trees (GISTs) to optimize the index. GIST indexes may be multicolumn.


function_name

Defines a user-defined function, rather than a column from the base table, as the basis of the index values. A function-based index is mutually exclusive of a regular column-based index.


WHERE condition

Defines a WHERE clause search condition, which is then used to generate a partial index. A partial index contains entries for a select set of records in the table, not all records of the table. You can get some interesting effects from this clause. For example, you can pair UNIQUE and WHERE to enforce uniqueness for a subset of the table rather than for the whole table. The WHERE clause must:

  • Reference columns in the base table (though they need not be columns of the index itself).

  • Not make use of aggregate functions.

  • Not use subqueries.

In PostgreSQL, a column may have an associated operator class based on the datatype of the column. An operator class specifies the operators for a particular index. Although users are free to define any valid operator class for a given column, the default operator class is the appropriate operator class for that column type.

In the following example, we create an index using the GIST indextype. We also make sure that uniqueness is only enforced for publishers outside of the USA:

CREATE UNIQUE INDEX unq_pub_id ON publishers(pub_name, country)

USING GIST

WHERE country <> 'USA';

SQL Server

SQL Server's CREATE INDEX syntax is:

CREATE [UNIQUE] [[NON]CLUSTERED] INDEX index_name

ON {table_name | view_name} (column [ASC | DESC] [,...])

[WITH [PAD_INDEX]

   [[,] FILLFACTOR = int]

   [[,] IGNORE_DUP_KEY]

   [[,] DROP_EXISTING]

   [[,] STATISTICS_NORECOMPUTE] ]

   [[,] SORT_IN_TEMPDB] ]

[ON filegroup]

where:


[NON]CLUSTERED

Controls the physical ordering of data for the table using either a CLUSTERED or NONCLUSTERED index. The columns of a CLUSTERED index determine the order in which the records of the table are physically written. Thus, if you create an ascending clustered index on column A of table Foo, the records will be written to disk in ascending alphabetical order. The NONCLUSTERED clause, the default, when either value is omitted, creates a secondary index containing only pointers and has no impact on how the actual rows of the table are written to disk.


ASC | DESC

Specifies that the values in the index are kept in either ascending (ASC) or descending (DESC) order. When ASC or DESC is omitted, ASC is used by default.


WITH

Allows the specification of one or more optional attributes for the index.


PAD_INDEX

Specifies that space should be left open on each 8K index page, according to the value established by the FILLFACTOR setting.


FILLFACTOR = int

Declares a percentage value, int, from 1 to 100 that tells SQL Server how much of each 8K data page should be filled at the time the index is created. This is useful to reduce I/O contention and page splits when a data page fills up. Creating a clustered index with an explicitly defined fillfactor can increase the size of the index, but also speed up processing in certain circumstances.


IGNORE_DUP_KEY

Controls what happens when a duplicate record is placed into a unique index through an insert or update operation. If this value is set for a column, only the duplicate row is excluded from the operation. If this value is not set, then all records in the operation (even nonduplicate records) are rejected as duplicates.


DROP_EXISTING

Drops any pre-existing indexes on the table and rebuilds the specified index.


STATISTICS_NORECOMPUTE

Stops SQL Server from recomputing index statistics. This can speed the CREATE INDEX operation, but it may mean that the index is less effective.


SORT_IN_TEMPDB

Stores any intermediate results used to build the index in the system database, TEMPDB. This increases the space needed to create the index, but could speed processing if TEMPDB is on a different disk than the table and index.


ON filegroup

Creates the index on a given pre-existing filegroup. This enables the placing of indexes on a specific hard disk or RAID device. Issuing a CREATE CLUSTERED INDEX...ON FILEGROUP effectively moves a table to the new filegroup, since the leaf level of the clustered index is the same as the actual data pages of the table.

SQL Server allows the creation of a unique clustered index on a view, effectively materializing the view. This can greatly speed up data retrieval operations against the view. Once a view has a unique clustered index, nonclustered indexes also can be added to the view. Note that the view also must be created using the SCHEMABINDING option. Indexed views are only allowed in SQL Server 2000 Enterprise Edition, unless you add a NOEXPAND hint to the view. Indexed views support data retrieval, but not data modification. (See the SQL Server section of CREATE/ALTER VIEW Statement" for specific restrictions on indexed views.)

SQL Server allows up to 249 nonclustered indexes (unique or non-unique) on a table, as well as one primary key index. Index columns may not be of datatype NTEXT, TEXT, or IMAGE. Concatenated keys may contain up to 16 columns and/or a total of 900 bytes across all fixed-length columns.

SQL Server automatically parallelizes the creation of the index according to the configuration option max degree of parallelism.

It is often necessary to build indexes that span several columns-i.e., a concatenated key. Here is an example:

CREATE UNIQUE INDEX project2_ind

ON housing_construction(project_name, project_date)

WITH PAD_INDEX, FILLFACTOR = 80

ON FILEGROUP housing_fg

GO

Adding the PAD_INDEX clause and setting the FILLFACTOR to 80 tells SQL Server to leave the index and data pages 80% full, rather than 100% full. The example also tells SQL Server to create the index on the housing_fg filegroup, rather than the default filegroup.

See Also

CREATE/ALTER TABLE
DROP
CREATE/ALTER METHOD Statement

The CREATE/ALTER METHOD statements allow the creation of a new database method or the alteration of an already existing database method. An easy (but loose) way to think of a method is that it is a user-defined function associated with a user-defined type. For example, a method called Office, of type Address, can accept a VARCHAR input parameter and passes out a result of Address.

An implicitly defined method is created every time a structured type is created (see CREATE/ALTER TYPE Statement" for more details). Using a combination of the CREATE TYPE statement and the CREATE METHOD statement creates user-defined methods.

Platform

Command

DB2

Supported, with variations

MySQL

Not supported

Oracle

Not supported

PostgreSQL

Not supported

SQL Server

Not supported


SQL2003 Syntax

{CREATE | ALTER} [INSTANT | STATIC] METHOD method_name

   ( [ [{IN | OUT | INOUT}] param datatype [AS LOCATOR] [RESULT] [,...] )

RETURNS datatype

FOR udt_name

[SPECIFIC specific_name]

code_body

Keywords


CREATE | ALTER [INSTANT | STATIC] method_name

Creates a new method or alters an existing method and, optionally, specifies it as an INSTANT or STATIC method.


([IN | OUT | INOUT] param datatype [,...] )

Declares one or more parameters to be passed into the method in a comma-delimited list enclosed in parentheses. Parameters used with a method may pass a value IN, OUT, or both in and out via INOUT. The syntax for the parameter declaration is:

[{IN | OUT | INOUT}] parameter_name1 datatype, 

[{IN | OUT | INOUT}] parameter_name2 datatype,[...]

Make sure the name is unique within the method. When used with ALTER, this clause adds parameters to a pre-existing method. Refer to Chapter 2 for details on datatypes.


AS LOCATOR

The optional AS LOCATOR clause is used to validate an external routine with a RETURNS parameter that is a BLOB, CLOB, NCLOB, ARRAY, or user-defined type. In other words, the locator (i.e., a pointer) for the LOB is returned but not the entire value of the LOB.


RESULT

Designates a user-defined type, but is not needed for standard datatypes.


RETURNS datatype

Declares the datatype of the results returned by a method. The key purpose of a user-defined method is to return a value. If you need to change the datatype of a RETURNS parameter on the fly, use the CAST clause (refer to the function CAST). For example, RETURNS VARCHAR(12) CAST FROM DATE.


FOR udt_name

Associates the method with a specific, pre-existing user-defined type, created using CREATE TYPE.


SPECIFIC specific_name

Uniquely identifies the function generally used with user-defined types.

Rules at a Glance

User-defined methods are essentially a different approach to the same output provided by user-defined functions. For example, consider the following two pieces of code:

CREATE FUNCTION my_fcn (order_udt)

RETURNS INT;

CREATE METHOD my_mthd ( )

RETURNS INT

FOR order_udt;

Although the code sections for the function and method are different, they do exactly the same thing.

The rules for use and invocation of methods are otherwise the same as for functions.

Programming Tips and Gotchas

The main difficulty with methods is that they are an object-oriented approach to the same sort of functionality provided by user-defined functions. Since they accomplish the same work, using a different approach, it can be hard to decide which approach to use.

DB2

DB2 supports both the CREATE METHOD and ALTER METHOD statements:

CREATE [SPECIFIC] METHOD method_name

   ( [ [{IN | OUT | INOUT}] [param] datatype [AS LOCATOR] [RESULT] [,...] )

[RETURNS datatype [{AS LOCATOR | CAST FROM datatype [AS LOCATOR] } ]

FOR udt_name

EXTERNAL [NAME 'name'] [TRANSFORM GROUP group_name]

code_body

The syntax for ALTER METHOD is quite a bit simpler:

ALTER METHOD method_name

FOR udt_name

EXTERNAL NAME 'name'

where:


[SPECIFIC] METHOD method_name

Defines the method being created or altered. The optional SPECIFIC keyword identifies a method using the name assigned (either implicitly or explicitly) using the CREATE TYPE statement. The method must exist in the named or current schema.


CAST FROM datatype

Returns a different datatype to the invoking statement from the datatype that was returned by the method.


EXTERNAL [NAME 'external_name'] [TRANSFORM GROUP group_name]

Indicates that the statement is registering an external method, rather than creating an internal (SQL) method. The user-defined type created using the CREATE TYPE statement must be defined with a LANGUAGE other than SQL.


NAME 'name'

Defines the name of the external code that implements the method. The name may be up to 254 characters long. The name must be appropriate for the type of LANGUAGE associated with the user-defined type. This clause may also define the name of an internal (SQL) method specification for user-defined types defined with LANGUAGE SQL.


TRANSFORM GROUP group_name

Specifies a transform group for user-defined structure type transformations when the method is invoked. When omitted, the transform group DB2_FUNCTION is the default.

The method specification is determined by the LANGUAGE setting of the CREATE TYPE statement associated with the method. For LANGUAGE SQL, the method specification is SQL. For any other LANGUAGE setting, the method specification is external.

The following example method, called office_zip, checks to see if a ZIP Code is valid based on the user-defined type address_type:

CREATE METHOD office (address address_type)

RETURNS INTEGER

FOR address_type

RETURN

(CASE

   WHEN (self..zip = address.zip) THEN 1 -- valid

   ELSE 0                                -- invalid

END);

In the next example, the method distance uses and external routine and transform group to process the between two address_types:

CREATE METHOD distance (address_type)

FOR address_type

EXTERNAL NAME 'addrlib!distance'

TRANSFORM GROUP method_group;

Later, we could change the method so that it uses a different external routine:

ALTER METHOD distance ( )

FOR TYPE address_type

EXTERNAL NAME 'newaddrlib!distance_2';

MySQL

Not supported.

Oracle

Not supported.

PostgreSQL

Not supported.

SQL Server

Not supported.

See Also

CREATE/ALTER TYPE
CREATE ROLE Statement

CREATE ROLE allows the creation of a named set of privileges that may be assigned to users of a database. When a role is granted to a user, that user gets all the privileges and permissions of that role. Roles are generally accepted as one of the best means for maintaining security and controlling privileges within a database.

Platform

Command

DB2

Not supported

MySQL

Not supported

Oracle

Supported, with variations

PostgreSQL

Not supported

SQL Server

Not supported


SQL2003 Syntax

CREATE ROLE role_name [WITH ADMIN {CURRENT_USER | CURRENT_ROLE}]

Keywords


CREATE ROLE role_name

Creates a new role and differentiates that role from a host DBMS user and other roles. A role can be assigned any permission that a user can be assigned. The important difference is that a role can then be assigned to one or more users, thus giving them all the permissions of that role.


WITH ADMIN {CURRENT_USER | CURRENT_ROLE}

Assigns a role immediately to the currently active user or currently active role along with the privilege to pass the use of the role on to other users. By default, the statement defaults to WITH ADMIN CURRENT_USER.

Rules at a Glance

Using roles for database security can greatly ease administration and user maintenance. The general steps for using roles in database security are:

  1. Assess the needs for roles and pick the role names (e.g., administrator, manager, data_entry, report_writer, etc.).

  2. Assign permissions to each role as if it were a standard database user using the GRANT statement. For example, the manager role might have permissions to read and write from all user tables in a database, while the report_writer role only has permissions to execute read-only reports against certain reporting tables in the database.

  3. Use the GRANT statement to grant roles to users of the system according to the types of work they will perform.

Permissions can be disabled using the REVOKE command.

Programming Tips and Gotchas

The main problem with roles is that occasionally a database administrator will provide redundant permissions to a role and separately to a user. If you ever need to prevent a user's access to the resource in situations like this, you usually will need to REVOKE the permissions twice. The role must be revoked from the user and then the specific user-level privilege must also be revoked from the user.

DB2

Not supported.

Instead, DB2 uses operating system groups, so you can achieve similar functionality but you need to:

  1. Create an OS group.

  2. Grant or revoke permissions to the group.

  3. Add users to the group at the OS level.

DB2 allows OS groups to be assigned special admin roles at the instance level using the sysadm_group, sysctrl_group, and sysmaint_group configuration parameters.

MySQL

Not supported.

Oracle

Although it is not currently supported by the ANSI standard, Oracle also offers an ALTER ROLE statement. Oracle supports the concept of roles, though Oracle's implementation of the commands is very different from the ANSI SQL standard:

{CREATE | ALTER} ROLE role_name

   [NOT IDENTIFIED |

    IDENTIFIED {BY password | EXTERNALLY | GLOBALLY |

       USING package_name}]

where:


CREATE | ALTER ROLE role_name

Identifies the name of the new role being created or the pre-existing role being modified.


NOT IDENTIFIED

Declares that no password is needed for the role to receive authorization to the database. This is the default.


IDENTIFIED

Declares that the users of the role must authenticate themselves by the method indicated before the role is enabled via the SET ROLE command, where:


BY password

Creates a local role authenticated by the string value of password. Only single-byte characters are allowed in the password even when using a multibyte character set.


EXTERNALLY

Creates an external role that is authenticated by the operating system or a third-party provider. In either case, the external authentication service will likely require a password.


GLOBALLY

Creates a global role that is authenticated by an enterprise directory service, such as an LDAP directory.


USING package_name

Creates an application role that enables a role only through an application that uses a PL/SQL package of package_name. If you omit the schema, Oracle assumes that the package is in your schema.

In Oracle, the role is created first, then granted privileges and permissions as if it is a user via the GRANT command. When users want to get access to the permissions of a role protected by a password, they use the SET ROLE command. If a password is placed on the role, any user wishing to access it must provide the password with the SET ROLE command.

Oracle ships with several preconfigured roles. CONNECT, DBA, and RESOURCE are available in all versions of Oracle. EXP_FULL_DATABASE and IMP_FULL_DATABASE are newer roles used for import and export operations. The GRANT statement reference has a more detailed discussion of all of the preconfigured roles available in Oracle.

The following example uses CREATE to specify a new role in Oracle, GRANTs it privileges, assigns it a password with ALTER ROLE, and GRANTs that role to a couple of users:

CREATE ROLE boss;

GRANT ALL ON employee TO boss;

GRANT CREATE SESSION, CREATE DATABASE LINK TO boss;

ALTER ROLE boss IDENTIFIED BY le_grande_fromage;

GRANT boss TO emily, jake;

PostgreSQL

Although PostgreSQL does not support the CREATE ROLE command, it offers a nearly identical facility of its own called CREATE GROUP. PostgreSQL also offers an ALTER GROUP statement to modify existing groups. In PostgreSQL, a group and a role are identical:

{CREATE | ALTER} GROUP name

[ [WITH] {SYSID int | USER username [,...] }]

[ {DROP | ADD} username [,...] }

where:


{CREATE | ALTER} GROUP name

Specifies if a new group (i.e., role) is created or if an existing group is modified where name is the name of the group to create or modify.


WITH {SYSID int | USER username [,...]

Assigns an explicit group ID to the new group, with the SYSID clause, or assigns a list of one or more pre-existing users to the group. When omitted, PostgreSQL will create the group using the highest assigned group ID plus one (starting at 1). The WITH clause is only used with the CREATE GROUP statement.


{DROP | ADD} username

Drops or adds one or more pre-existing users to the group. Used only with the ALTER GROUP clause.

Use the DROP GROUP clause to drop a group you no longer want.

SQL Server

Microsoft SQL Server does not support the CREATE ROLE command, but has the equivalent capability via the system stored procedure sp_add_role.

See Also

GRANT
REVOKE
CREATE SCHEMA Statement

This statement creates a schema-i.e., a named group of related objects. A schema is a collection of tables, views, and permissions granted to specific users or roles. According to the ANSI standard, specific object permissions are not schema objects in themselves and do not belong to a specific schema. However, roles are sets of privileges that do belong to a schema.

Platform

Command

DB2

Supported, with limitations

MySQL

Not supported

Oracle

Supported, with variations

PostgreSQL

Not supported

SQL Server

Supported, with limitations


SQL2003 Syntax

CREATE SCHEMA [schema_name] [AUTHORIZATION owner_name]

[DEFAULT CHARACTER SET char_set_name]

[PATH schema_name [,...] ]

   [ ANSI CREATE statements [...] ]

   [ ANSI GRANT statements [...]  ]

Keywords


CREATE SCHEMA [schema_name]

Creates a schema called schema_name. When omitted, the database will create a schema name for you using the name of the user who owns the schema.


AUTHORIZATION owner_name

Sets the owner_name as the user who owns the schema. When omitted, the current user is set as the owner. The ANSI standard allows you to omit either the schema_name or the AUTHORIZATION clause, or to use them both together.


DEFAULT CHARACTER SET char_set_name

Declares a default character set of char_set_name for all objects created within the schema.


PATH schema_name [,...]

Optionally declares a file path and filename for any unqualified routines (i.e., stored procedures, user-defined functions, user-defined methods) in the schema.


ANSI CREATE statements [...]

Contains one or more CREATE statements. No commas are used between the CREATE statements.


ANSI GRANT statements [...]

Contains one or more GRANT statements to previously defined objects. Usually, the objects were created earlier in the same CREATE SCHEMA statement, but they may be any previously created object. No commas are used between the GRANT statements.

Rules at a Glance

The CREATE SCHEMA statement is a container that can hold many other CREATE and GRANT statements. The most common way to think of a schema is as all of the objects that a specific user owns. For example, the user jake may own several tables and views including the table, publishers, in his own schema. Meanwhile, the user dylan may own several other tables and views in his schema, but may also own his own separate copy of the publishers table.

The ANSI standard requires that all CREATE statements are allowed in a CREATE SCHEMA statement. In practice, most implementations of CREATE SCHEMA only allow three subordinate statements: CREATE TABLE, CREATE VIEW, and GRANT. The order of the commands is not important, meaning you can grant privileges on tables or views whose CREATE statements appear later in the CREATE SCHEMA statement.

Programming Tips and Gotchas

It is not required, but is considered a best practice, to arrange the objects and grants within a CREATE SCHEMA statement in an order that will execute naturally. In other words, CREATE VIEW statements should follow the CREATE TABLE statements that they depend on, and then GRANT statements should come last.

If your database system uses schemas, we recommend that you always reference your objects by schema and then object name (as in jake.publishers). If you do not include a schema qualifier, the database platform will typically assume the default schema for the current user connection.

Some database platforms do not explicitly support the CREATE SCHEMA command. However, they implicitly create a schema when a user creates database objects. For example, Oracle creates a schema whenever a user is created. The CREATE SCHEMA command is simply a single-step method of creating all the tables, views, and other database objects along with their permissions.

DB2

DB2 supports the basic elements of the CREATE SCHEMA statement. It does not support the PATH or DEFAULT CHARACTER SET clauses:

CREATE SCHEMA [schema_name] [AUTHORIZATION owner_name]

   [ ANSI CREATE statements [...] ]

   [ ANSI GRANT statements [...]  ]

The syntax and usage is otherwise identical to the ANSI standard.

DB2 creates a schema implicitly whenever a new schema is referenced in a GRANT or CREATE statement.

DB2 does not support an ALTER SCHEMA statement.

MySQL

Not supported.

Oracle

In Oracle, the CREATE SCHEMA does not create a schema-only the CREATE USER statement does that. CREATE SCHEMA allows a user to perform multiple CREATEs and GRANTs in a previously created schema in one SQL statement:

CREATE SCHEMA AUTHORIZATION schema_name

   [ ANSI CREATE statements [...] ]

   [ ANSI GRANT statements [...]  ]

Note that Oracle only allows ANSI standard CREATE TABLE, CREATE VIEW, and GRANT statements within a CREATE SCHEMA statement. You should not use any of Oracle's extensions to these commands when using the CREATE SCHEMA statement.

The following Oracle example places the permissions before the objects within the CREATE SCHEMA statement:

CREATE SCHEMA AUTHORIZATION emily

   GRANT SELECT, INSERT ON view_1 TO sarah

   GRANT ALL ON table_1 TO sarah

   CREATE VIEW view_1 AS

      SELECT column_1, column_2

      FROM table_1

      ORDER BY column_2

   CREATE TABLE table_1(column_1 INT, column_2 CHAR(20));

As the example above shows, the order of the statements within the CREATE SCHEMA statement is unimportant. Oracle commits the CREATE SCHEMA statement only if all CREATE and GRANT statements in the statement complete successfully.

PostgreSQL

Not supported.

SQL Server

SQL Server supports the basic CREATE SCHEMA statement without support for the PATH clause or the DEFAULT CHARACTER SET clause:

CREATE SCHEMA AUTHORIZATION owner_name

   [ ANSI CREATE statements [...] ]

   [ ANSI GRANT statements [...]  ]

If any statement fails within the CREATE SCHEMA statement, then the entire statement fails.

SQL Server does not require that the CREATE or GRANT statements be in any particular order, except that nested views must be declared in their logical order. Thus, if view_100 references view_10, then view_10 must appear in the CREATE SCHEMA statement before view_100.

For example:

CREATE SCHEMA AUTHORIZATION katie

   GRANT SELECT ON view_10 TO public

   CREATE VIEW view_10(col1) AS SELECT col1 FROM foo

   CREATE TABLE foo(col1 INT)

   CREATE TABLE foo

      (col1 INT PRIMARY KEY,

       col2 INT REFERENCES foo2(col1))

   CREATE TABLE foo2

      (col1 INT PRIMARY KEY,

       col2 INT REFERENCES foo(col1))

See Also

CREATE/ALTER TABLE
CREATE/ALTER VIEW
GRANT
CREATE/ALTER TABLE Statement

Manipulating tables is one of the most common activities that database administrators and programmers perform when working with database objects. This section details how to create and modify tables.

The ANSI standard represents a sort of least common denominator among the vendors, though not every option of the ANSI standard version of CREATE TABLE and ALTER TABLE is offered by each of the vendors. However, the ANSI standard does represent the basic form that can be used across all of the platforms. In turn, the vendor platforms offer a variety of extensions and additions to the ANSI standards for CREATE and ALTER TABLE.

Typically, a great deal of consideration goes into the design and creation of a table. This discipline is known as database design. The discipline of analyzing the relationship of a table to its own data and to other tables within the database is known as normalization. We recommend that database programmers and administrators alike study both database design and normalization principles thoroughly before issuing CREATE TABLE commands.


Platform

Command

DB2

Supported, with variations

MySQL

Supported, with variations

Oracle

Supported, with variations

PostgreSQL

Supported, with variations

SQL Server

Supported, with variations


SQL2003 Syntax

The SQL2003 statement CREATE TABLE creates a permanent or temporary table within the database where the command is issued. The syntax is as follows:

CREATE [{LOCAL TEMPORARY| GLOBAL TEMPORARY}] TABLE table_name

   (column_name datatype attributes [,...] ) |

   [column_name WITH OPTIONS options] |

   [LIKE  table_name] |

   [REF IS column_name

     {SYSTEM GENERATED | USER GENERATED | DERIVED} ]

   [CONSTRAINT constraint_type [constraint_name] [,...] ]

[OF type_name [UNDER super_table] [table_definition] ]

[ON COMMIT {PRESERVE ROWS | DELETE ROWS}

The SQL2003 statement ALTER TABLE allows many useful modifications to be made to an existing table without dropping any existing indexes, triggers, or permissions assigned to it. Following is the ALTER TABLE syntax:

ALTER TABLE table_name

[ADD [COLUMN] column_name datatype attributes]

| [ALTER [COLUMN] column_name SET DEFAULT default_value]

| [ALTER [COLUMN] column_name DROP DEFAULT]

| [ALTER [COLUMN] column_name ADD SCOPE table_name

| [ALTER [COLUMN] column_name DROP SCOPE {RESTRICT | CASCADE}]

| [DROP [COLUMN] column_name {RESTRICT | CASCADE}]

| [ADD table_constraint]

| [DROP CONSTRAINT table_constraint_name {RESTRICT | CASCADE}]

Keywords


[LOCAL | GLOBAL] TEMPORARY

Declares a permanent table or a TEMPORARY table of LOCAL or GLOBAL scope. Local temporary tables are only accessible to the session that created them and are automatically dropped when the session that created them terminates. Global temporary tables are accessible by all active sessions, but are automatically dropped when the session that created them terminates. Do not qualify a temporary table with a schema name.


(column_name datatype attributes [,...] )

Defines a comma-delimited list of one or more columns, their datatypes, and any additional attributes such as nullability. Every table declaration must contain at least one column, which may include:


Column_name

Specifies a name for a column. The name must be a valid identifier according to the rules of the specific DBMS. Make sure the name makes sense!


Datatype

Associates a specific datatype with the column of column_name. An optional length may be specified for datatypes that allow user-defined lengths, for example VARCHAR(255). It must be a valid datatype on the specific DBMS. Refer to Chapter 2 for a full discussion of acceptable datatypes and vendor variations.


Attributes

Associates specific constraint attributes with the column_name. Many attributes may be applied to a single column_name, no commas required. Typical ANSI attributes include:


NOT NULL

Tells the column to reject null values or accept null values, when NOT NULL is omitted. Any INSERT or UPDATE statement that attempts to place a null value in a NOT NULL column will fail and roll back.


DEFAULT expression

Tells the column to use the value of expression when no value is supplied by an INSERT or UPDATE statement. The expression must be acceptable according to the datatype of the column; for example, no alphabetic characters may be used in an INTEGER column. Expression may be a string or numeric literal, but you may also define a user-defined function or system function. SQL2003 allows these system functions in a DEFAULT expression: NULL, USER, CURRENT_USER, SESSION_USER, SYSTEM_USER, CURRENT_PATH, CURRENT_DATE, CURRENT_TIME, LOCALTIME, CURRENT_TIMESTAMP, LOCALTIMESTAMP, ARRAY, or ARRAY[ ].


COLLATE collation_name

Defines a specific collation, or sort order, for the column it is assigned to. The name of the collation is platform dependent. If you do not define a collation, the columns of the table default to the collation of the character set used for the column.


REFERENCES ARE [NOT] CHECKED [ON DELETE {RESTRICT | SET NULL}]

Indicates whether references are to be checked on a REF column defined with a scope clause. The optional ON DELETE clause tells whether any values in records referenced by a deleted record should set to NULL or whether the operation should be restricted.


CONSTRAINT constraint name [constraint_type [constraint]]

Assigns a constraint and, optionally a constraint name, to the specific column. Constraint types are discussed in Chapter 2. Because the constraint is associated with a specific column, the constraint declaration assumes that the column is the only one in the constraint. After the table is created, the constraint is treated as a table-level constraint.


column_name [WITH OPTIONS options]

Defines a column with special options, such as a scope clause, a default clause, a column-level constraint, or a COLLATE clause. For many implementations, the WITH OPTIONS clause is restricted to the creation of typed tables.


LIKE table_name

Creates a new table with the same column definitions as the pre-existing table of table_name.


REF IS column_name {SYSTEM GENERATED | USER GENERATED | DERIVED}

Defines the object identifier column (OID) for a typed table. An OID is necessary for the root table of a table hierarchy. Based on the option, the REF might be automatically generated by the system (SYSTEM GENERATED), manually provided by the user when inserting the row (USER GENERATED), or derived from another REF (DERIVED). Requires the inclusion of a REFERENCES column attribute for column_name.


CONSTRAINT constraint_type [constraint_name] [,...]

Assigns one or more constraints to the table. This option is noticeably different than the CONSTRAINT option at the column level because column-level constraints are assumed to apply only to the column they are associated with. Table-level constraints, however, give the option of associating multiple columns with a constraint. For example, in a sales table you might wish to declare a unique constraint on a concatenated key of store_id, order_id, and order_date. This can only be done using a table-level constraint. Refer to Chapter 2 for a full discussion of constraints.


OF type_name [UNDER super_table] [table_definition]

Declares that the table is based upon a pre-existing user-defined type (see CREATE/ALTER TYPE Statement"). In this situation, the table may have only a single column for each attribute of the structured type, plus an additional column as defined in the REF IS clause. The REF datatype is described in greater detail in the section CREATE/ALTER TYPE Statement. This clause is incompatible with the LIKE table_name clause.

where:


UNDER super_table [table_definition]

Declares the direct supertable of the currently declared table within the same schema, if any exists. The table being created is thus a direct subtable of the supertable. You may optionally provide a complete table_definition of the new subtable, complete with columns, constraints, etc.


ON COMMIT {PRESERVE ROWS | DELETE ROWS}

ON COMMIT PRESERVE ROWS preserves data rows in a temporary table on issuance of a COMMIT statement. ON COMMIT DELETE ROWS deletes all data rows in a temporary table on COMMIT.


ADD [COLUMN] column_name datatype attributes

Adds a column to a table, along with the appropriate datatype and attributes.


ALTER [COLUMN] column_name SET DEFAULT default_value

Adds a default value to the column if none exists, and resets the default value if a previous one exists.


ALTER [COLUMN] column_name DROP DEFAULT

Completely removes a default from the named column.


ALTER [COLUMN] column_name ADD SCOPE table_name

Adds a scope to the named column. A scope is a reference to a user-defined datatype (see CREATE/ALTER TYPE Statement").


ALTER [COLUMN] column_name DROP SCOPE [RESTRICT | CASCADE]

Drops a scope from the named column. RESTRICT and CASCADE clauses are defined at the end of this list.


DROP COLUMN column_name [RESTRICT | CASCADE]

Drops the named column from the table. RESTRICT and CASCADE clauses are defined at the end of this list.


ADD table_constraint

Adds a table constraint of the specified name and characteristics to the table.


DROP CONSTRAINT constraint_name [RESTRICT | CASCADE]

Drops a previously defined constraint from the table.


RESTRICT

Tells the DBMS to abort the command if it finds any other objects in the database that depend on the object.


CASCADE

Tells the DBMS to drop any other objects that depend on the object.

Rules at a Glance

The typical CREATE TABLE statement is very simple. Generally, it names the table and any columns contained in the table. Many table definitions also include a nullability constraint for most of the columns, as in this SQL Server example:

CREATE TABLE housing_construction

   (project_number      INT          NOT NULL,

   project_date         DATE         NOT NULL,

   project_name         VARCHAR(50)  NOT NULL,

   construction_color   NCHAR(20)   ,

   construction_height  DECIMAL(4,1),

   construction_length  DECIMAL(4,1),

   construction_width   DECIMAL(4,1),

   construction_volume  INT         )

This example adds a foreign key to the example table:

-- Creating a column-level constraint

CREATE TABLE favorite_books

   (isbn         CHAR(100)    PRIMARY KEY,

   book_name     VARCHAR(40)  UNIQUE,

   category      VARCHAR(40)  ,

   subcategory   VARCHAR(40)  ,

   pub_date      DATETIME     NOT NULL,

   purchase_date DATETIME     NOT NULL,

      CONSTRAINT fk_categories FOREIGN KEY (category)

         REFERENCES category(cat_name));

The foreign key on the categories column relates it to the cat_name table in the category table. All the vendors mentioned in this book support this syntax.

Examples for creating a table with each constraint type are shown in Chapter 2. Similarly, the foreign key could be added after the fact as a multicolumn key including both the category and subcategory columns:


ALTER TABLE favorite_books ADD CONSTRAINT fk_categories

   FOREIGN KEY (category, subcategory)

   REFERENCES category(cat_name, subcat_name));

Now, we could use an ALTER TABLE statement to drop the constraint altogether:

ALTER TABLE favorite_books DROP CONSTRAINT fk_categories RESTRICT;

Listed here are more full examples from pubs, the sample database that ships with Microsoft SQL Server and Sybase Adaptive Server:

-- For a Microsoft SQL Server database

CREATE TABLE jobs

   (job_id  SMALLINT IDENTITY(1,1) PRIMARY KEY CLUSTERED,

   job_desc VARCHAR(50) NOT NULL DEFAULT 'New Position',

   min_lvl  TINYINT NOT NULL CHECK (min_lvl >= 10),

   max_lvl  TINYINT NOT NULL CHECK (max_lvl <= 250))

-- For a MySQL  database

CREATE TABLE employee

   (emp_id INT AUTO_INCREMENT CONSTRAINT PK_emp_id PRIMARY KEY,

   fname VARCHAR(20) NOT NULL,

   minit CHAR(1) NULL,

   lname VARCHAR(30) NOT NULL,

   job_id SMALLINT NOT NULL DEFAULT 1

      REFERENCES jobs(job_id),

   job_lvl TINYINT DEFAULT 10,

   pub_id CHAR(4) NOT NULL DEFAULT ('9952')

      REFERENCES publishers(pub_id),

   hire_date DATETIME NOT NULL DEFAULT (CURRENT_DATE( ));

CREATE TABLE publishers

   (pub_id char(4) NOT NULL

      CONSTRAINT UPKCL_pubind PRIMARY KEY CLUSTERED

      CHECK (pub_id IN ('1389', '0736', '0877', '1622', '1756')

      OR pub_id LIKE '99[0-9][0-9]'),

   pub_name varchar(40) NULL,

   city varchar(20) NULL,

   state char(2) NULL,

   country varchar(30) NULL DEFAULT('USA'))

Once you get into the vendor extensions, the CREATE TABLE command is no longer portable between database platforms. The following is an example of an Oracle CREATE TABLE statement with many storage properties:

CREATE TABLE classical_music_cds

   (music_id        INT,

   composition      VARCHAR2(50),

   composer         VARCHAR2(50),

   performer        VARCHAR2(50),

   performance_date DATE DEFAULT SYSDATE,

   duration         INT,

   cd_name          VARCHAR2(100),

CONSTRAINT pk_class_cds PRIMARY KEY (music_id)

   USING INDEX TABLESPACE index_ts

   STORAGE (INITIAL 100K NEXT 20K),

CONSTRAINT uq_class_cds UNIQUE

   (composition, performer, performance_date)

   USING INDEX TABLESPACE index_ts

   STORAGE (INITIAL 100K NEXT 20K))

TABLESPACE tabledata_ts;

When issuing a CREATE or ALTER statement, we recommend that it be the only statement in your transaction. For example, do not attempt to create a table and select from it in the same batch. Instead, (1) create the table, (2) verify the operation, (3) COMMIT, and then (4) perform any subsequent operations against the table.

Table_name is the name for a new or existing table. New table names should start with an alphabetic character and in general contain no other special symbol besides underscore ( _ ). Length of the name and exact composition is governed differently according to each vendor.

When creating or altering a table, the list of column definitions is always encapsulated within parentheses and separated by commas between each new column definition.

Programming Tips and Gotchas

The user issuing the CREATE TABLE command must have the appropriate permissions. Similarly, any user wishing to ALTER or DROP a table should own the table within his own schema or have adequate permissions to the alter or drop the table. Since the ANSI standard does not specify the privileges required, expect some variation between vendors.

You can encapsulate a CREATE TABLE or ALTER TABLE statement within a transaction, using a COMMIT or ROLLBACK statement to explicitly conclude the transaction. We recommend that it be the only command in the transaction.

You can have a great deal of control over the way that the records of a table are physically written to disk through extensions to the ANSI standard. DB2 and SQL Server use a technique called clustered indexes to control the way that records are written to disk. Oracle uses a technique that is functionally similar called an index-organized table.

Some databases will lock a table that is being modified by an ALTER TABLE statement. It is wise to issue this command only on tables that are not in use on a production database.

Some databases will lock the target and source tables when using the CREATE TABLE...LIKE statement.

DB2

DB2 supports a very rich and elaborate set of extensions to the CREATE TABLE statement:

CREATE TABLE table_name

   {(column_name datatype attributes [,...] ) |

   OF type_name [{UNDER super_table INHERIT SELECT PRIVILEGES |

      HIERARCHY hierarchy_name}] [table_definition] |

   AS subquery {derived_table_options |

      DEFINITION ONLY [copy_options] } |

   [LIKE  table_name] [copy_options] |

   [ [(staging_column [,...] ) ]

   FOR table_name PROPAGATE IMMEDIATE] }

[ORGANIZE BY [DIMENSTIONS] (column_name [,...] ) ]

[DATA CAPTURE {NONE | CHANGES} ]

[IN tablespace_name [INDEX IN tablespace_name]

   [LONG IN tablespace_name]]

[VALUE COMPRESSION]

[WITH RESTRICT ON DROP]

[NOT LOGGED INITIALLY]

[{REPLICATED | PARTITIONING KEY (column_name [,...] )

   [USING HASHING] } ]

[OPTIONS (REMOTE_SERVER 'server_name'

   [, REMOTE_SCHEMA 'schema_name']

   [, REMOTE_TABNAME 'table_name'] ]

Similarly rich, the DB2 statement ALTER TABLE allows many useful modifications to be made to an existing table without dropping any existing indexes, triggers, or permissions assigned to it:

ALTER TABLE table_name

{[ADD { {[COLUMN] column_name datatype attributes} |

   table_constraint | partitioning_key | RESTRICT_ON_DROP } |

{[ALTER { {CHECK | FOREIGN KEY} constraint_name constraint_definition] |

   [COLUMN] column_name column_definition } |

{[DROP constraint_type constraint_name] | partitioning_key |

   RESTRICT_ON_DROP } |

 [DATA CAPTURE {NONE | CHANGES [INCLUDE LONGVAR COLUMNS]} |

 [ACTIVATE NOT LOGGED INITIALLY [WITH EMPTY TABLE] ] |

 [PCTFREE int] |

 [LOCKSIZE {ROW | TABLE} ] |

 [APPEND {ON | OFF} ] |

 [ [NOT] VOLATILE [CARDINATITY] ] |

 [ [DE]ACTIVATE VALUE COMPRESSION] } [...] |

SET MATERIALIZED QUERY AS {DEFINITION ONLY | subquery]

The parameters for both commands are as follows:


(column_name datatype attributes [,...] )

Defines columns according to the ANSI standard. However, DB2 supports several additional attributes that are specific to special datatypes on DB2. All the ANSI standard attributes, such as NOT NULL, are supported. Refer to the section on datatypes in Chapter 2 for more details.


UNDER super_table INHERIT SELECT PRIVILEGES | HIERARCHY hierarchy_name

Similar to the ANSI standard OF clause in the CREATE TABLE command, with two added optional clauses - INHERIT and HIERARCHY. INHERIT tells DB2 that any user or group with read privileges on the super_table should also have read privileges on the new subtable. HIERARCHY associates the subtable with a table hierarchy, where hierarchy_name is the name of the root table of the hierarchy. When omitted, DB2 will generate its own hierarchy_name.


table_definition

Defines the elements of the typed table, including addition options for columns, an OID column on the root table, and table constraints.


AS subquery

Materializes the table from the results of a query. You may include a standard column definition list, but the columns must match the number and datatype of columns retrieved by the subquery.


derived_table_options

The full syntax for derived_table_options is:

DATA INITIALLY DEFERRED REFRESH {DEFERRED | IMMEDIATE} 

[ {ENABLE | DISABLE} QUERY OPTIMIZATION] 

[MAINTAINED BY {SYSTEM | USER} ]

The keywords have the following meanings:


DATA INITIALLY DEFERRED

Defers the insertion of data into the table until a DB2 REFRESH TABLE command is issued.


REFRESH {DEFERRED | IMMEDIATE}

Allows the table to be refreshed only when a DB2 REFRESH TABLE statement is issued (via DEFERRED) or immediate after any data manipulation operation (via IMMEDIATE).


{ENABLE | DISABLE} QUERY OPTIMIZATION

Enables or disables the derived table for query optimization when DB2 decides optimization is appropriate. Of course, the table is always available for direct queries.


MAINTAINED BY {SYSTEM | USER}

Declares that the derived table data is maintained automatically by the SYSTEM (the default) or manually by the USER via the DB2 REFRESH TABLE command. If you select MAINTAINED BY USER, the table must also be declared as REFRESH DEFERRED.


DEFINITION ONLY [copy options]

Defines the table without populating the table with a query result set.


copy_options

Allows the modification of the DEFINITION ONLY and LIKE clauses. Copy options include:


{INCLUDING | EXCLUDING} [COLUMN] DEFAULTS

Includes or excludes column defaults of the copied table, respectively. INCLUDING is the default for base tables or temporary tables. Otherwise, EXCLUDING is the default.


{INCLUDING | EXCLUDING} [IDENTITY] [COLUMN ATTRIBUTES]

Includes or excludes column attributes of the copied table, respectively. The IDENTITY attributes of the column may optionally be copied.


LIKE table_name [copy options]

Copies the entire set of column definitions from an existing table, table_name, though a view or nickname is also allowed. You may use the copy_options shown previously in the list to alter the default behavior of the LIKE clause.


[(staging_column [,...] ) ] FOR table_name PROPAGATE IMMEDIATE]

Defines an intermediate table (i.e., a staging table) between the base table(s) that define a derived table and the derived table itself. (Naturally, this clause should only be used with the AS subquery clause.)

The components of this clause are:


staging_column

Defines one or more staging columns. However, the list of staging columns will always contain two more columns than the number of columns in the derived table - GLOBALTRANSID and GLOBALTRANSTIME. The PROPAGATE clause, adds one more column - OPERATIONTYPE - which is used to maintain consistency in replicated a materialized query table. When omitted, DB2 will create the appropriate staging columns it needs for the operation.


FOR table_name

Names the table that defines the staging table. table_name must represent a derived table with REFRESH DEFERRED already existing in the database. Whenever a REFRESH TABLE command is issued, the contents of the staging table are used to refresh the derived table.


PROPAGATE IMMEDIATE

Specifies that data modifications to the underlying tables cascade immediately to the staging table.


ORGANIZE BY [DIMENSIONS] (column_name [,...] )

Defines a cluster or dimension on a column or group of columns, depending on whether the DIMENSIONS keyword is excluded or included, respectively. In effect, a clustered index is defined with the ORGANIZE BY clause, while the ORGANIZE BY DIMENSIONS clause is used to create a clustered index on more than one column (i.e., on a dimension).


DATA CAPTURE {NONE | CHANGES}

Writes extra data to the log in support of inter-database replication. NONE declares that no extra information will be stored, while CHANGES declares that changes are written to the log. The DATA CAPTURE CHANGES clause is required on replicated tables. This clause is incompatible when creating subtables.


IN tablespace_name [INDEX IN tablespace_name][LONG IN tablespace_name]

Declares a specific, pre-existing tablespace where the table is placed. This clause is incompatible when creating a subtable and in System Managed tablespaces. The components of the clause are:


INDEX IN tablespace_name

Declares a separate pre-existing tablespace where the indexes of the table will be placed. When omitted, the default is the same tablespace as the table data.


LONG IN tablespace_name

Declares a separate pre-existing tablespace where the data of long datatypes (LONG VARCHAR, LONG VARGRAPHIC, LOB, etc.) for the table will be placed. When omitted, the default is the same tablespace as the table data.


VALUE COMPRESSION

Enables high compression storage of NULL and 0-length data values.


WITH RESTRICT ON DROP

Restricts the table and its tablespace from being dropped.


NOT LOGGED INITIALLY

Declares that any changes to the data of the table that occur in the same batch as when the table is created are not logged. On the other hand, all catalog changes and storage changes are logged. This setting can cause the rollback of an entire batch of work under certain circumstances.


REPLICATED

Declares that the data in the table is replicated on each database partition of the database partition group where it is defined, in effect copying the data to all database partitions. This clause is incompatible with PARTITIONING KEY, but is required for derived tables.


PARTITIONING KEY (column_name [,...] ) [USING HASHING]

Defines a partitioning key for the table where column_name becomes the partitioning key. The column_name may not be a long or special datatype - LONG VARCHAR, LONG VARGRAPHIC, BLOB, CLOB, DBCLOB, DATALINK - or structured or distinct types built upon these datatypes. This clause is incompatible when creating subtables. When omitted and the table is defined on a database partition group, DB2 will attempt to find a method for partitioning the table. Otherwise, the table will be placed on a single-partition database partition group. USING HASHING declares that a hashing algorithm is used to distribute data among the partitions.


OPTIONS (REMOTE_SERVER 'server_name' [, REMOTE_SCHEMA 'schema_name'] [, REMOTE_TABNAME 'table_name']

Defines a remote operation, such as creating, altering, or dropping a table on a federated system. This is called transparent DDL. Federated systems are quite complex and are outside of the ANSI standard. Refer to the vendor documentation for more information.


ADD table_constraint

Adds a table-level constraint to an existing table.


ALTER {CHECK | FOREIGN KEY} constraint_name constraint_definition

Alters the attributes of an existing CHECK or FOREIGN KEY of constraint_name and assigns it a new constraint_definition. You may also apply these additional constraint characteristics:


[NOT] ENFORCED

Changes the constraint to ENFORCED or NOT ENFORCED. Under ENFORCED, the constraint is automatically enforced by the database. NOT ENFORCED causes the constraint to not be checked during data modification operations.


{ENABLE | DISABLE} QUERY OPTIMIZATION

Enables or disables query optimization on the constraint.


ALTER [COLUMN] column_name column_definition

Alters a specific column, column_name, in the table. You can change a number of column characteristics beyond the standard column definition options, including things like SCOPE, COMPRESS, and identity alterations. Refer to the material later in this section for information on type-related attributes and other alterable attributes. Some additional characteristics can be changed on a column-by-column basis, such as:


SET DATA TYPE VARCHAR (int)

Alters the length of the named VARCHAR column to int. The value of int should not increase the total row length or the total primary key length beyond the allowed maximum.


SET EXPRESSION AS (generation-expression)

Alters the original generated expression, a sort of auto-incrementing identity column, of the named column to a new generation-expression. The difference between a generated expression and an identity is that identities are automatically handled by DB2, but generated expressions give you full control over the values returned by the expression. Generated expressions can be quite complex and are covered in the vendor documentation. This clause requires the table be placed in "check pending state," where the data in the table is not verified against constraints, via DB2's SET INTEGRITY statement. Afterwards, the values must all be checked.


SET INLINE LENGTH int

Alters the inline length of the named structured type column to int, storing the values inline with the rest of the data in the row.


DROP constraint_type constraint_name

Drops a constraint of constraint_name from the table. The constraint_type may be any of the allowable types: primary key, foreign key, unique, check, as well as PARTITIONING KEY. You may also substitute constraint_type with RESTRICT ON DROP, to drop the RESTRICT ON DROP characteristic.


DATA CAPTURE {NONE | CHANGES [INCLUDE LONGVAR COLUMNS] }

Captures extra information to the log in support of replication. Usable with any non-typed table. The options for DATA CAPTURE are:


NONE

Specifies that no extra information is captured.


CHANGES

Writes extra information to the table in support of replication. This clause is required for replication. This clause is incompatible with tables that store data on non-catalog partitions. The INCLUDE LONGVAR COLUMNS clause includes LONG VARCHAR and LONG VARGRAPHIC columns in the data replication.


ACTIVATE NOT LOGGED INITIALLY [WITH EMPTY TABLE]

Disables logging of any transaction made in the same batch as the ALTER TABLE statements. Statements that are not logged include INSERT, DELETE, UPDATE, CREATE INDEX, DROP INDEX, or another ALTER TABLE statement. Logging returns to normal after the current SQL batch completes. The optional WITH EMPTY TABLE clause tells DB2 to empty the table of data. The data is not recoverable except through the DB2 RECOVER facility.


PCTFREE int

Declares a percentage of free space, int, that DB2 should leave on each page during load or reorganization of the table.


LOCKSIZE {ROW | TABLE}

Declares that locks should be taken at a ROW or TABLE level when reading or writing data in the table. The default is ROW. This clause is only supported in the root table of a typed-table hierarchy.


APPEND {ON | OFF}

Adds all new data to the end of the table when turned ON or puts data in the free space available within data pages throughout the table when turned OFF. The default is OFF. Setting this value to ON causes DB2 not to keep any free space information. The APPEND clause is not usable on tables with a clustered index.


[NOT] VOLATILE [CARDINALITY]

Declares whether the table cardinality varies greatly over time. When set to VOLATILE, tells DB2 to generally ignore statistics in favor of an index scan because the amount of data in the table change a great deal. VOLATILE is supported only on normal tables and the root table of a typed-table hierarchy. NOT VOLATILE tells DB2 that the amount of data in the table is generally static, so that it can use existing statistics and optimization paths. Adding the optional CARDINALITY keyword tells DB2 that the amount of data in the table may change but that the table itself is static.


[DE]ACTIVATE VALUE COMPRESSION

Deactivates or activates the compression of NULL and zero-length data values in the table for all datatypes of BLOB, CLOB, DBLOB, LONG VARCHAR, or LONG VARGRAPHIC.


SET MATERIALIZED QUERY {AS DEFINITION ONLY | subquery}

Alters the properties of a materialized query table. DEFINITION ONLY tells DB2 to consider the table as a normal table and not a materialized query table. When using DEFINITION ONLY, the materialized query table cannot be replicated. The subquery clause is any valid subquery used to define a materialized query table. The subquery redefines a regular table as a materialized query table during query optimization. When using the subquery clause, the table may not be a typed table, have constraints, unique indexes, or triggers, or be defined as or referenced in a materialized query table.

DB2 also has a number of special attributes that may be applied to columns over the standard constraints that the ANSI SQL standard provides. These optional attributes are specific to specific datatypes. The following are LOB-related attributes:


[NOT] LOGGED

Declares whether changes made to the column are written to the logfile (LOGGED) or not (NOT LOGGED). The default is LOGGED. However, any LOB values greater than 10 megabytes should not be logged and those over 1 gigabyte cannot be logged.


[NOT] COMPACT

Compresses the values of LOBs as much as possible, usually by freeing any extra space on the last group used by the LOB or allowing free space in the last group to go unused. COMPACT takes some extra processing and I/O overhead. NOT COMPACT is the default.

For example, you might have a table called emp_images, which stores the security ID images of your employees:

CREATE TABLE emp_images

   (emp_id          INT NOT NULL,

    emp_photo_image LONGVARGRAPHIC NOT LOGGED COMPACT)

DB2 supports the following datalink-related attributes:


LINKTYPE URL

Defines a URL as the type of link.


NO LINK CONTROL

Declares that there is no check for file existence.


FILE LINK CONTROL [options]

Declares that file existence will be checked. Additional options may impact the style of check, including:


INTEGRITY [ALL]

Sets the level of checks between the DATALINK value and an actual file. The optional ALL keyword disables operating system control for deleting or renaming the file.


READ PERMISSION {FS | DB}

Sets read permission on the file as either filesystem derived (FS) or database derived (DB).


WRITE PERMISSION {FS | BLOCKED | ADMIN}

Sets write permission on the file as either filesystem derived (FS), no writes allowed (BLOCKED), or determined by the Data Links Manager (ADMIN). The WRITE PERMISSION ADMIN clause is based on a passed token. You should further specify [NOT] REQUIRING TOKEN FOR UPDATE, which details whether a write token is needed to finish a file update operation.


RECOVERY {YES | NO}

Declares that DB2 will support point in time recovery of files referenced by the values in the column (YES) or not (NO). RECOVERY YES also requires the INTEGRITY ALL clause and either WRITE PERMISSION BLOCKED or WRITE PERMISSION ADMIN.


ON UNLINK {RESTORE | DELETE}

Declares that DB2 either return the file to its original permissions when the DATALINK value is changed or deleted (RESTORE) or that the file is deleted when unlinked (DELETE). ON UNLINK RESTORE requires the INTEGRITY ALL clause and either WRITE PERMISSION BLOCKED or WRITE PERMISSION ADMIN. ON UNLINK DELETE requires the READ PERMISSION DB clause and either WRITE PERMISSION BLOCKED or WRITE PERMISSION ADMIN.


MODE DB2OPTIONS

Defines a default group of file link options: INTEGRITY ALL, READ PERMISSION FS, WRITE PERMISSION FS, and RECOVERY NO.

DB2 supports the following type-related attributes:


SCOPE type_name

Declares the scope of a reference-type column, where type_name is the pre-existing typed table or view. It is required for columns that will be used as the left operand of a dereference operator or as the argument of a DEREF function.


INLINE LENGTH int

Declares a maximum byte size, int, for a structured-type column. If the structured type is too long, DB2 will automatically store the structured types in a separate table from the base table, similar to the way LOB values are stored.

DB2 supports just one storage-related attribute:


COMPRESS SYSTEM DEFAULT

Defines that the system default value for any column is compressed. It should not be used on columns of DATE, TIME, or TIMESTAMP datatypes. You gain some storage space at the sacrifice of performance.

Use the following DEFAULT-related attributes to set various defaults:


[WITH] DEFAULT {CURRENT SCHEMA | USER | NULL | constant}

Declares a default for the column. That is, whenever an INSERT or UPDATE (or LOAD) statement does not provide a value for the column, then DB2 will use the default value you specify. WITH is a noise word. When omitted, NULL is always the default. The options for the DEFAULT clause are:


CURRENT SCHEMA

Inserts the CURRENT SCHEMA system value. The column must have a character datatype of sufficient length to store CURRENT SCHEMA.


USER

Inserts the USER system value. The column must have a character datatype of sufficient length to store USER.


NULL

Inserts a null value, the default.


constant

Can be any constant string, date, or number of 254 characters or fewer.


GENERATED {ALWAYS | BY DEFAULT}

Tells DB2 to generate values for the column, in particular for IDENTITY columns, either every time a record is inserted in the table (ALWAYS) or whenever a value is not provided for the column (BY DEFAULT).


AS (expression)

Assigns the default value based on the evaluation of an expression. The expression might be something like an external user-defined function, a subquery, or a stored procedure. Refer to the ALTER COLUMN...generated expressions material earlier in this section.


AS IDENTITY [START WITH int | INCREMENT BY int}

Declares that the column is an auto-incrementing identity for a column of a number datatype. Identities can be either ascending or descending in nature. DB2 allows only one identity column per table. All identity columns are implicitly NOT NULL. Identities are further defined by these optional characteristics:


START WITH int

Declares the seed value (i.e., the starting value), int, of the identity column. The default is MINVALUE for ascending identities and MAXVALUE for descending identities.


INCREMENT BY int

Declares the amount each entry to the identity will increase (if positive) or decrease (if negative). The default is 1. A negative INCREMENT BY value tells DB2 that the identity is descending in nature.


[NO] {MINVALUE | MAXVALUE} [int]

Declares the value, int, at which the identity either cycles to the beginning or stops generating values. Both clauses may appear as attributes of an identity. They are not mutually exclusive. NO MINVALUE, the default minimum value setting, tells DB2 to start ascending identities at the START WITH value or 1, if omitted. MINVALUE int tells DB2 the lowest allowable value for a descending identity. NO MAXVALUE, the default maximum value setting, tells DB2 to stop or recycle ascending identities at maximum value allowed for the datatype. For descending identities, the default is the START WITH value or -1, when omitted. MINVALUE int tells DB2 the highest allowable value for an ascending identity.


[NO] CYCLE

Declares that DB2 should recycle the identity values (CYCLE) when the maximum value is exceeded on ascending identities (or the minimum value is decremented on a descending identity) or that DB2 should stop generating identities (NO CYCLE) once the minimum or maximum is reached. NO CYCLE is the default. DB2 will generate duplicate values under the CYCLE setting.


[NO] CACHE [int]

Tells DB2 to cache some pre-allocated values in memory (CACHE) or not (NO CACHE). You may optionally tell DB2 how many identity values, int, to cache using CACHE int.


[NO] ORDER

Tells DB2 whether identity values must be generated in the order they were requested (ORDER) or not (NOT ORDER). When omitted, NOT ORDER is the default.

For example, our company has acquired another company with a whole roster of employees. We want to assign the new employees a new emp_id based on our current highest emp_id identity column value:

CREATE TABLE temp_emp

  (new_emp_id INT NOT NULL GENERATED ALWAYS AS IDENTITY

      (START WITH 500, INCREMENT BY 1, NO CYCLE, CACHE),

   dept       VARCHAR (50) NOT NULL,

   mgr_id     INT,

   location   CHAR(30))

DB2 supports the creation of temporary tables, but not in the CREATE TABLE statement. Instead, use the DECLARE GLOBAL TEMPORARY TABLE statement described in the DB2 documentation.


However, be extra careful whenever altering a table. You should generally expect that any procedural objects that are dependent on the table, such as procedures or functions, will become invalid.

-- Creating a column-level constraint

CREATE TABLE favorite_books

   (isbn         CHAR(100)    PRIMARY KEY,

   book_name     VARCHAR(40)  UNIQUE,

   category      VARCHAR(40)  NULL,

   subcategory   VARCHAR(40)  NULL,

   pub_date      DATETIME     NOT NULL,

   purchase_date DATETIME     NOT NULL,

      CONSTRAINT fk_categories FOREIGN KEY (category)

         REFERENCES category(cat_name));

In the following example, we alter our example table, favorite_books, to not log SQL changes for replication. We also assign some free space to the data pages of the table:

ALTER TABLE favorite_books

   PCTFREE 20

   DATA CAPTURE NONE

We also finally decide that although the records in the table change quite frequently, the table structure itself should be static:

ALTER TABLE favorite_books NO VOLATILE CARDINALITY

MySQL

The MySQL syntax for CREATE TABLE creates a permanent or local temporary table within the database in which the command is issued.

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] table_name

{(column_name datatype attributes

  constraint_type constraint_name [,...] )

 [constraint_type [constraint_name] [,...] ]

   [MATCH FULL | MATCH PARTIAL]

   [ON {DELETE | UPDATE} {RESTRICT | CASCADE | SET NULL |

    NO ACTION | SET DEFAULT}]

LIKE other_table_name }

{[TYPE = {ISAM | MyISAM | HEAP | BDB | InnoDB | MERGE |

  MRG_MyISAM} |

   AUTO_INCREMENT = int |

   AVG_ROW_LENGTH = int |

   CHECKSUM = {0 | 1} |

   COMMENT = "string" |

   DELAY_KEY_WRITE = {0 | 1} |

   MAX_ROWS = int |

   MIN_ROWS = int |

   PACK_KEYS = {0 | 1} |

   PASSWORD = "string" |

   ROW_FORMAT= { default | dynamic | static | compressed } |

   RAID_TYPE = {1 | STRIPED | RAID0} |

   RAID_CHUNKS = int |

   RAID_CHUNKSIZE = int |

   INSERT_METHOD = {NO | FIRST | LAST} |

   DATA DIRECTORY = "path to directory"

   INDEX DIRECTORY = " path to directory "] }

[[IGNORE | REPLACE] select_statement]

The MySQL syntax for ALTER TABLE allows modifications to a table or even renaming of a table:

ALTER [IGNORE] TABLE table_name

{[ADD [COLUMN] (column_name datatype attributes ]

[FIRST | AFTER column_name]]

| [ADD [UNIQUE | FULLTEXT] INDEX [index_name]

|    (index_col_name [,...]) ]

| [ADD PRIMARY KEY (index_col_name [,...]) ]

| [ALTER [COLUMN] column_name {SET DEFAULT literal |

|    DROP DEFAULT}]

| [CHANGE | MODIFY] [COLUMN] old_col_name new_column_name]

    [FIRST | AFTER column_name]

| [MODIFY] column_name datatype attributes

| [DROP [COLUMN] column_name]

| [DROP PRIMARY KEY]

| [DROP INDEX index_name]

| [{ENABLE | DISABLE} KEYS]

| [RENAME [TO] new_tbl_name]

| [table_options] } [,...]

Keywords and parameters are as follows:


TEMPORARY

Creates a table that persists for the duration of the connection under which it was created. Once that connection closes, the temporary table is automatically deleted.


IF NOT EXISTS

Prevents an error if the table already exists. A schema specification is not required.


constraint_type

Allows standard ANSI SQL constraints to be assigned at the column or table level. MySQL fully supports these constraints: primary key, unique, and default (must be a constant). MySQL provides syntax support for check, foreign key, and references constraints, but they are not functional except on InnoDB tables. MySQL also has three specialty constraints:


FULLTEXT [INDEX]

Creates a fulltext-search index to facilitate rapid searches of large blocks of text. Note that only MyISAM tables support FULLTEXT indexes and that they can only be made on CHAR, VARCHAR, and TEXT columns.


AUTO_INCREMENT

Sets up an integer column so that it automatically increases its value by 1 (starting with a value of 1). MySQL only allows one AUTO_INCREMENT column per table. When the maximum value is deleted, the value is reused. When all records are deleted (using DELETE or TRUNCATE), the values may start over. This option is allowed on ISAM tables, but not MyISAM and InnoDB tables.


[UNIQUE] INDEX

When an INDEX characteristic is assigned to a column, a name for the index also can be included. (A MySQL synonym for INDEX is KEY.) If a name is not assigned to the primary key, MySQL assigns a name of column_name plus a numeric suffix ( _2, _3,. . . ) to make it unique. All table types, except for the ISAM table type, support indexes on NULL columns, or on BLOB or TEXT datatype columns. Note that UNIQUE without INDEX is valid syntax on MySQL.


TYPE

Describe how the data should be physically stored. You can convert tables between types using the ALTER TABLE statement. Only InnoDB and BDB tables offer recoverability with the COMMIT or ROLLBACK statements. All other table types will result in the loss of data if the database crashes, but are much faster and take up less space. The default is MyISAM. Following is the list of MySQL table types:


BDB

Creates a transaction-safe table with page locking. Tables of this type are based on the BerkeleyDB transaction processing engine available at http://www.sleepycat.com. BDB maintains logfiles and keeps track of checkpoints and ROLLBACK and COMMIT statements. BDB tables must have a declared primary key. Some operations on BDB tables are slower than the same operations on MyISAM tables.


HEAP

Creates a memory resident table that uses hashed indexes. Since they are memory resident, they are not transaction safe. Any data that they contain will be lost if the server crashes. Think of HEAP tables as an alternative to temporary tables. If you use HEAP tables, always specify the MAX_ROWS option so that you do not use all available memory. HEAP tables also do not support BLOB columns, TEXT columns, AUTO_INCREMENT constraints, ORDER BY clauses, or variable-length record format.


InnoDB

Creates a transaction-safe table with row-level locking. It also provides an independently managed tablespace, checkpoints, non-locking reads and fast reads from large datafiles for heightened concurrency and performance. Requires the innodb_data_file_path startup parameter. InnoDB supports all ANSI constraints including CHECK and FOREIGN KEY. (InnoDB is a separate complete transaction processing engine available at http://www.innodb.com. Well-known developer web sites like Slashdot.org run on InnoDB.) InnoDB requires special setup, including a possible recompile of the MySQL kernel, init file parameters, and the creation of tablespaces. Although InnoDB is included by default in the binary distributions of MySQL 4.0 and greater, you should check with your DBA to ensure you can use InnoDB tables.


ISAM

Creates a table in the older ISAM style. ISAM is deprecated as a feature and will probably not be supported beyond MySQL v5.0.


MERGE | MRG_MyISAM

Collects several identically structured MyISAM tables for use as one table. The MERGE table type provides some of the performance benefits of a partitioned table. The two keywords, MERGE and MRG_MyISAM, are synonyms. SELECT, DELETE, and UPDATE statements operate against the collection of tables as if they were one table. Think of a merge table as the collection, but not as the table(s) containing the data. Dropping a merge table only removes it from the collection. It does not erase the table or data from the database. Specify a MERGE table by using the statement UNION=(table1, table2, ...).


MyISAM

Stores data in .MYD files and indexes in .MYI files. MyISAM is based on ISAM code with several extensions. MyISAM is a binary storage structure that is more portable than ISAM. MyISAM supports AUTO_INCREMENT columns, compressed tables (with the myisampack utility), and large table sizes. Under MyISAM, BLOB and TEXT columns can be indexes, and up to 32 indexes are allowed per table.


AUTO_INCREMENT = int

Sets the auto_increment value, int, for the table (MyISAM only).


AVG_ROW_LENGTH = int

Sets an approximate average row length for tables with variable-size records. MySQL uses avg_row_length * max_rows to decide how big a table may be.


CHECKSUM = {0 | 1}

When set to 1, maintains a checksum for all rows in the table (MyISAM only). Makes processing slower, but is less prone to corruption.


COMMENT = "string"

Allows a comment of up to 60 characters.


DELAY_KEY_WRITE = {0 | 1}

When set to 1, delays key table updates until the table is closed (MyISAM only).


MAX_ROWS = int

Sets a maximum number of rows to store in the table. The default maximum is 4 GB of space.


MIN_ROWS = int

Sets a minimum number of rows to store in the table.


PACK_KEYS = {0 | 1}

When set to 1, compacts the indexes of the table, making reads faster but updates slower (MyISAM and ISAM only). By default, only strings are packed. When set to 1, both strings and numeric values are packed.


PASSWORD = "string"

Encrypts the .FRM file with a password, "string", but not the table itself.


ROW_FORMAT = { default | dynamic | static | compressed }

Determines how future rows should be stored in a MyISAM table. DYNAMIC allows the rows to be of variable sizes (i.e., using VARCHAR) while FIXED expects fixed size columns (i.e., CHAR, INT, etc.).


RAID_TYPE = {1 | STRIPED | RAID0}

Enables tables to cross the 2 gigabyte/4 gigabyte size limit for MyISAM datafiles (but not index files) on operating systems that don't support very large files. The RAID_TYPE clause is intended as a workaround for database servers experiencing the aforementioned size limits, so you should not use RAID_TYPE on operating systems that support larger files. The keywords 1, STRIPED, and RAIDZERO are all synonyms, where STRIPED is the most commonly seen. The --with-raid init parameter is required. Currently, MySQL handles the RAID_CHUNKS and RAID_CHUNKSIZE clauses automatically.


RAID_CHUNKS = int

Overrides the default subdirectories used for the RAID_TYPE. MySQL usually creates subdirectories named 00, 01, and 02 in the database directory for all each MyISAM table. Each subdirectory will contain a file called my_table_name.MYD.


RAID_CHUNKSIZE = int

Sets a chunksize other than the default of 1,024 bytes. As the file size for the MyISAM table grows, MySQL will allocate additional space in int bytes in a round-robin fashion.


INSERT_METHOD = {NO | FIRST | LAST}

Required for MERGE tables. If no setting is specified for a MERGE table or the value is NO, then INSERTS are disallowed. FIRST inserts all records to the first table in the collection, while LAST inserts them all to the last table of the collection


DATA DIRECTORY = "path to directory"

Overrides the default path and directory that MySQL should use for MyISAM table storage.


INDEX DIRECTORY = "path to directory"

Overrides the default path and directory that MySQL should use for MyISAM index storage.


[IGNORE | REPLACE] SELECT_statement

Creates a table with columns based upon the elements listed in the SELECT statement. The new table will be populated with the results of the SELECT statement if the statement returns a result set.


ALTER [IGNORE]

The altered table will include all duplicate records unless the IGNORE keyword is used. Otherwise, the statement will fail if a duplicate row is encountered, the table has a unique index or primary key, and IGNORE is not used.


{ADD | COLUMN} [ FIRST | AFTER column_name]

Adds or moves a column, index, or key to the table. When adding or moving columns, the new column appears as the last column on the table unless it is placed AFTER another named column.


ALTER COLUMN

Allows the definition or reset of a default value for a column. If you reset a default, MySQL will assign a new default value to the column.


CHANGE

Renames a column or changes its datatype.

MODIFY

Changes a column's datatype or attributes such as NOT NULL. Existing data in the column is automatically converted to the new datatype.


DROP

Drops the column, key, or index. A dropped column is also removed from any indexes it participated in. When dropping a primary key, MySQL will drop the first unique key if no primary key is present.


{ENABLE | DISABLE} KEYS

Enables or disables all non-unique keys on a MyISAM table simultaneously. This can be useful for bulk loads where you want to temporarily disable constraints until after the load is finished. It also speeds performance by finishing all index block flushing at the end of the operation.


RENAME [TO] new_tbl_name

Renames a table.

For example:

CREATE TABLE test_example

  (column_a INT NOT NULL AUTO_INCREMENT,

  PRIMARY KEY(column_a),

  INDEX(column_b))

  TYPE=HEAP

IGNORE

SELECT column_b,column_c FROM samples;

This creates a heap table with three columns: column_a, column_b, and column_c. Later on, we could change this table to the MyISAM type:

ALTER TABLE example TYPE=MyISAM;

Three operating-system files are created when MySQL creates a MyISAM table: a table definition file with the extension .FRM, a datafile with the extension .MYD, and an index file with the extension .MYI. The .FRM datafile is used for all other tables.

The following example creates two base MyISAM tables and then creates a MERGE table from them:

CREATE TABLE message1

   (message_id   INT AUTO_INCREMENT PRIMARY KEY,

    message_text CHAR(20));

CREATE TABLE message2

   (message_id   INT AUTO_INCREMENT PRIMARY KEY,

    message_text CHAR(20));

CREATE TABLE all_messages

   (message_id   INT AUTO_INCREMENT PRIMARY KEY,

    message_text CHAR(20))

    TYPE=MERGE UNION=(message1, message2) INSERT_METHOD=LAST;

The following example renames both a table and a column:

ALTER TABLE employee RENAME AS emp;

ALTER TABLE employee CHANGE employee_ssn emp_ssn INTEGER;

Since MySQL allows the creation of indexes on a portion of a column (for example, on the first ten characters of a column), you can also build short indexes on very large columns.

MySQL can redefine the datatype of an existing column. To avoid losing any data, the values contained in the column must be compatible with the new datatype. For example, a date column could be redefined to a character datatype, but not a character datatype to an integer. Here's an example:

ALTER TABLE mytable MODIFY mycolumn LONGTEXT

MySQL allows some additional flexibility in the ALTER TABLE statement by allowing users to issue multiple ADD, ALTER, DROP, and CHANGE clauses in a comma-delimited list in a single ALTER TABLE statement. However, be aware that the CHANGE column_name and DROP INDEX clauses are MySQL extensions not found in SQL2003. MySQL supports the clause MODIFY column_name to mimic the same feature found in Oracle.

Oracle

The Oracle syntax for CREATE TABLE creates a relational table either by declaring the structure or by referencing an existing table. You can modify a table after it is created using the ALTER TABLE statement. Oracle also allows the creation of a relational table that uses user-defined types for column definitions. You can also create an object table that is explicitly defined to hold a specific UDT, usually a VARRAY or NESTED TABLE type, as well as XMLType tables.

The standard ANSI style CREATE TABLE statement is supported, but Oracle has added many sophisticated extensions to the command. For example, Oracle allows significant control over the storage and performance parameters of a table. In both the CREATE TABLE and ALTER TABLE statements, you'll see a great deal of nesting and reusable clauses. To make this somewhat easier to read, we have broken Oracle's CREATE TABLE statement into three distinct variations (relational table, object table, and XML table) so that you can more easily follow the syntax.

The CREATE TABLE syntax for a standard relational table, which has no object or XML properties, is as follows:

CREATE [GLOBAL] [TEMPORARY] TABLE table_name

[ ( {column | attribute} [SORT] [DEFAULT expression] [{column_constraint |

      inline_ref_constraint} ] |

   {table_constraint_clause | table_ref_constraint} |

   {GROUP log_group (column [NO LOG] [,...]) [ALWAYS] | DATA

      (constraints [,...]) COLUMNS} ) ]

[ON COMMIT {DELETE | PRESERVE} ROWS]

[table_constraint_clause]

{  [physical_attributes_clause] [TABLESPACE tablespace_name]

      [storage_clause] [[NO]LOGGING] |

   [CLUSTER (column [,...] )] |

   {[ORGANIZATION

     {HEAP [physical_attributes_clause][TABLESPACE

        tablespace_name][storage_clause]

         [COMPRESS | NOCOMPRESS] [[NO]LOGGING] |

      INDEX [physical_attributes_clause][TABLESPACE 

         tablespace_name][storage_clause]

         [PCTTHRESHOLD int] [COMPRESS [int] | NOCOMPRESS]

         [MAPPING TABLE | NOMAPPING][...] [[NO]LOGGING]

         [[INCLUDING column] OVERFLOW

            [physical_attributes_clause][TABLESPACE tablespace_name]

            [storage_clause] [[NO]LOGGING] } ] |

      EXTERNAL ( [TYPE driver_type] ) DEFAULT DIRECTORY directory_name

         [ACCESS PARAMETERS {USING CLOB subquery | ( opaque_format ) } ]

         LOCATION ( [directory_name:]'location_spec' [,...] )

         [REJECT LIMIT {int | UNLIMITED} ] } }

[{ENABLE | DISABLE} ROW MOVEMENT]

[[NO]CACHE] [[NO]MONITORING] [[NO]ROWDEPENDENCIES]

[PARALLEL int | NOPARALLEL] [NOSORT] [[NO]LOGGING]]

[COMPRESS [int] | NOCOMPRESS]

[{ENABLE | DISABLE} [[NO]VALIDATE]

   {UNIQUE (column [,...] | PRIMARY KEY | CONSTRAINT constraint_name} ]

   [USING INDEX  {index_name | CREATE_INDEX_statement} ] [EXCEPTIONS INTO]

   [CASCADE] [{KEEP | DROP} INDEX] ]  |

[partition_clause]

[AS subquery]

The relational table syntax contains a large number of optional clauses. However, the table definition must contain, at a minimum, either column names and datatypes specifications or the AS subquery clause.

The Oracle syntax for an object table follows:

CREATE [GLOBAL] [TEMPORARY] TABLE table_name

AS object_type [[NOT] SUBSTITUTABLE AT ALL LEVELS]

[ ( {column | attribute} [DEFAULT expression] [{column_constraint |

      inline_ref_constraint} ] |

   {table_constraint_clause | table_ref_constraint } |

   {GROUP log_group (column [NO LOG] [,...]) [ALWAYS] | DATA

      (constraints [,...]) COLUMNS} ) ]

[ON COMMIT {DELETE | PRESERVE} ROWS]

[OBJECT IDENTIFIER IS {SYSTEM GENERATED | PRIMARY KEY}]

[OIDINDEX [index_name] ([physical_attributes_clause] [storage_clause]) ]

[physical_attributes_clause] [TABLESPACE tablespace_name] [storage_clause]

The Oracle syntax for an XMLType table follows:

CREATE [GLOBAL] [TEMPORARY] TABLE table_name

OF XMLTYPE

[ ( {column | attribute} [DEFAULT expression] [{column_constraint |

      inline_ref_constraint} ] |

   {table_constraint_clause | table_ref_constraint } |

   {GROUP log_group (column [NO LOG] [,...]) [ALWAYS] | DATA

      (constraints [,...]) COLUMNS} ) ]

[XMLTYPE {OBJECT RELATIONAL [xml_storage_clause] |

   CLOB [lob_segname] [lob_params]}] [xml_schema_spec]

[ON COMMIT {DELETE | PRESERVE} ROWS]

[OBJECT IDENTIFIER IS {SYSTEM GENERATED | PRIMARY KEY}]

[OIDINDEX index_name ([physical_attributes_clause] [storage_clause]) ]

[physical_attributes_clause] [TABLESPACE tablespace_name] [storage_clause]

The Oracle syntax for ALTER TABLE changes the table or column properties, storage characteristics, LOB or VARRAY properties, partitioning characteristics, and integrity constraints associated with a table and/or its columns. The statement does other things like move an existing table into a different tablespace, free recuperated space, compact the table segment, and adjust the "high-water mark."

The ANSI SQL standard uses the ALTER keyword to modify existing elements of a table, while Oracle uses MODIFY to mean the same thing. Since they are essentially the same thing, please consider the behavior of otherwise identical clauses (for example, ANSI's ALTER TABLE...ALTER COLUMN to Oracle's ALTER TABLE...MODIFY COLUMN) to be functionally equivalent.

Oracle's ALTER TABLE syntax is:

ALTER TABLE table_name

-- alter table characteristics

   [physical_attributes_clause] [storage_clause]

   [[NO]LOGGING] [[NO]CACHE] [[NO]MONITORING] [[NO]COMPRESS]

   [SHRINK SPACE [COMPACT] [CASCADE] ]

   [UPGRADE [[NOT] INCLUDING DATA] column_name datatype attributes]

   [[NO]MINIMIZE RECORDS_PER_BLOCK]

   [PARALLEL int | NOPARALLEL]

   [{ENABLE | DISABLE} ROW MOVEMENT]

   [{ADD | DROP} SUPPLEMENTAL LOG

      {GROUP log_group [(column_name [NO LOG] [,...] ) [ALWAYS] ] |

      DATA ( {ALL | PRIMARY KEY | UNIQUE | FOREIGN KEY} [,...] ) COLUMNS} ]

   [ALLOCATE EXTENT

      [( SIZE int[K|M|G|T] ] [DATATILE 'filename'] [INSTANCE int} ] )]

   [DEALLOCATE UNUSED [KEEP int[K|M|G|T] ] ]

   [ORGANIZATION INDEX ...

      [COALESCE] [MAPPING TABLE | NOMAPPING] [{PCTTHRESHOLD int]

         [COMPRESS int | NOCOMPRESS]

      [ { ADD OVERFLOW [TABLESPACE tablespace_name] [[NO]LOGGING]

            [physical_attributes_clause]] ] |

          OVERFLOW { [ALLOCATE EXTENT (SIZE int [K | M]] [DATAFILE

                'filename'] [INSTANCE int] ) |

             [DEALLOCATE UNUSED [KEEP int [K | M]] } ] ]

   [RENAME TO new_table_name]

-- alter column characteristics

   [ADD (column_name datatype attributes [,...] ) ]

   [DROP { {UNUSED COLUMNS | COLUMNS CONTINUE} [CHECKPOINT int] |

      {COLUMN column_name | (column_name [,...] ) } [CHECKPOINT int]

         [{CASCADE CONSTRAINTS | INVALIDATE}] } ]

   [SET UNUSED {COLUMN column_name | (column_name [,...] ) }

      [{CASCADE CONSTRAINTS | INVALIDATE}]

   [MODIFY { (column_name datatype attributes [,...] ) |

      COLUMN column_name [NOT] SUBSTITUTABLE AT ALL LEVELS [FORCE] } ]

   [RENAME COLUMN old_column_name TO new_column_name]

   [MODIFY {NESTED TABLE | VARRAY} collection_item [RETURN AS {LOCATOR |

      VALUE}]]

-- alter constraint characteristics

   [ADD CONSTRAINT constraint_name table_constrain_clause]

   [MODIFY CONSTRAINT constraint_name constraint_state_clause]

   [RENAME CONSTRAINT old_constraint_name TO new_constraint_name]

   [DROP { { PRIMARY KEY | UNIQUE (column [,...]) } [CASCADE]

         [{KEEP | DROP} INDEX] |

      CONSTRAINT constraint_name [CASCADE] } ]

-- alter table partition characteristics

   [alter partition clauses]

-- alter external table characteristics

   DEFAULT DIRECTORY directory_name

      [ACCESS PARAMETERS {USING CLOB subquery | ( opaque_format ) } ]

      LOCATION ( [directory_name:]'location_spec' [,...] )

   [ADD (column_name ...)][DROP column_name ...][MODIFY (column_name ...)]

   [PARALLEL int | NOPARALLEL]

   [REJECT LIMIT {int | UNLIMITED} ]

   [PROJECT COLUMN {ALL | REFERENCED} ]} }

-- move table clauses

   [MOVE [ONLINE] [physical_attributes_clause]

      [TABLESPACE tablespace_name] [[NO]LOGGING] [PCTTHRESHOLD int]

      [COMPRESS int | NOCOMPRESS] [MAPPING TABLE | NOMAPPING]

      [[INCLUDING column] OVERFLOW

         [physical_attributes_clause] [TABLESPACE tablespace_name]

         [[NO]LOGGING]] ]

      [LOB ...] [VARRAY ...] [PARALLEL int | NOPARALLEL] ]

-- enable/disable attributes and constraints

   [{ {ENABLE | DISABLE} [[NO]VALIDATE]] {UNIQUE (column [,...] ) |

      PRIMARY KEY | CONSTRAINT constraint_name} ]

      [USING INDEX  {index_name | CREATE_INDEX_statement |

         [TABLESPACE tablespace_name] [physical_attributes_clause]

         [storage_clause]

         [NOSORT] [[NO]LOGGING]] [ONLINE] [COMPUTE STATISTICS]

         [COMPRESS | NOCOMPRESS] [REVERSE]

         [{LOCAL | GLOBAL} partition_clause]

         [EXCEPTIONS INTO table_name] [CASCADE] [{KEEP | DROP} INDEX] ] |

   [{ENABLE | DISABLE}] [{TABLE LOCK | ALL TRIGGERS}] } ]

The parameters are as follows:


column_constraint

Specifies a column constraint using the syntax found in the description later.


GROUP log_group (column [NO LOG] [,...] ) [ALWAYS] | DATA (constraints [,...] ) COLUMNS

Specifies a log group rather than a single logfile for the table.


ON COMMIT {DELETE | PRESERVE} ROWS

Declares whether a declared temporary table should keep the data in the table active for the entire session (PRESERVE) or only for the transaction that the temporary table is created in (DELETE).


table_constraint_clause

Specifies a table constraint using the syntax found in the description later.


physical_attributes_clause

Specifies the physical attributes of the table using the syntax found in the description later.


TABLESPACE tablespace_name

Specifies the name of the tablespace where the table you are creating will be stored. If omitted, the default tablespace for the schema owner will be used. See below for specifics. See the Oracle Concepts manual to learn about tablespaces and their use.


storage_clause

Specifies physical storage characteristics of the table using the syntax found in the description later.


[NO]LOGGING

Specifies that redo log records will be written during object creation (LOGGING) or not (NOLOGGING). LOGGING is the default. In case of database failure under the NOLOGGING option, the operation cannot be recovered by applying logfiles, and the object must be recreated. NOLOGGING can speed the creation of database objects. The LOGGING clause replaces the older RECOVERABLE clause, which is deprecated.


CLUSTER (column [,...] )

Declares that the table is part of a clustered index. The column list should correspond, one to one, with the columns in a previously declared clustered index. Because it uses the clustered indexes space allocation, the CLUSTER clause is compatible with the physical_attributes_clause, storage_clause, or TABLESPACE clause. Tables containing LOBs are incompatible with the CLUSTER clause.


ORGANIZATION HEAP

Declares how the data of the table should be recorded to disk. HEAP, the default for an Oracle table, declares that no order is associated with the storage of rows of data (i.e., the physical order in which records are written to disk) for this table. The ORGANIZATION HEAP clause allows several optional clauses, described in detail elsewhere in this list, control storage, logging, and compression for the table.


ORGANIZATION INDEX

Declares how the data of the table should be recorded to disk. INDEX declares that the records of the table are physically written to disk in the sort order defined by the primary key of the table. Oracle calls this an index-organized table. A primary key is required. Note that the physical_attributes_clause, the TABLESPACE clause, and the storage_clause - all described in greater detail elsewhere in this section - as well as the [NO]LOGGING keyword may all be associated with the new INDEX segment as you create it. In addition, the following subclauses may also be associated with an ORGANIZATION INDEX clause:


PCTTHRESHOLD int

Declares the percentage, int, of space in each index block preserved for data. Data, on a record by record basis, that cannot fit in this space will be placed in the overflow segment.


INCLUDING column

Declares the point at which a record is to split between index and overflow portions. All columns that follow the specified column will be stored in the overflow segment. The column cannot be a primary key column.


MAPPING TABLE | NOMAPPING

Tells the database to create a mapping of local to physical ROWIDs. This mapping is required to create a bitmap index on an IOT. Mappings are also partitioned identically if the table is partitioned. NOMAPPING tells the database not to create the ROWID map.


[INCLUDING column] OVERFLOW

Declares that a record that exceeds the PCTTHRESHOLD value be placed in a segment described in this clause. The physical_attributes_clause, the TABLESPACE clause, the storage_clause - all described elsewhere in the list in greater detail - and the [NO]LOGGING keyword may all be associated with a specific OVERFLOW segment when you create it. The optional INCLUDING column clause defines a column at which to divide an IOT row into index and overflow portions. Primary key columns are always stored in the index. However, all non-primary key columns that follow column are stored in the overflow data segment.


ORGANIZATION EXTERNAL

Declares how the data of the table should be recorded to disk. EXTERNAL declares that the table stores its data outside of the database and is usually read-only. Its metadata is stored in the database but its data is stored outside of the database. There are some restrictions on external tables. They cannot be temporary. They cannot have constraints. They can only have column, datatype, and attribute column-descriptors. LOB and LONG datatypes are disallowed. No other ORGANIZATION clauses are allowed with EXTERNAL. The following subclauses may be used with the ORGANIZATION EXTERNAL clause:


TYPE driver_type

Defines the access driver API for the external table. The default is ORACLE_LOADER.


DEFAULT DIRECTORY directory_name

Defines the default directory on the filesystem where the external table resides.


ACCESS PARAMETERS {USING CLOB subquery | ( opaque_format ) }

Assigns and passes specific parameters to the access driver. Oracle does not interpret this information. USING CLOB subquery tells Oracle to derive the parameters and their values from a subquery that returns a single row with a single column of datatype CLOB. The subquery cannot contain an ORDER BY, UNION, INTERSECT, or MINUS/EXCEPT. The opaque_format clause allows you to list parameters and their values as described in the ORACLE LOADER section of the "Oracle9i Database Utilities" guide.


LOCATION ( directory_name:'location_spec' [,...])

Defines one or more external data sources, usually as files. Oracle does not interpret this information.


REJECT LIMIT {int | UNLIMITED}

Defines the number of conversion errors, int, that are allowed during the query to the external data source before Oracle aborts the query and returns an error. UNLIMITED tells Oracle to continue with the query no matter how many errors are encountered. The default is 0.


{ENABLE | DISABLE} ROW MOVEMENT

Specifies that a row may be moved to a different partition or subpartition if required due to an update of the key (ENABLE) or not (DISABLE). The DISABLE keyword also specifies that Oracle return an error if an update to a key would require a move.


[NO]CACHE

Buffers a table for rapid reads, while NOCACHE turns off this behavior. Index-organized tables offer CACHE behavior.


[NO]MONITORING

Specifies that modification statistics can be collected for this table (MONITORING) or not (NOMONITORING). NOMONITORING is the default.


[NO]ROWDEPENDENCIES

Specifies whether a table will use row-level dependency tracking, a feature that applies a system change number (SCN) greater than or equal to the last time of the transaction affecting the row. The SCN adds 6 extra bytes of space to each record. Row-level dependency tracking is most useful in replicated environments with parallel data propagation. NOROWDEPENDENCIES is the default.


PARALLEL int | NOPARALLEL

Allows for the parallel creation of the table by distinct CPUs to speed the operation. It also enables parallelism for queries and other data-manipulation operations against the table after its creation. An optional integer value may be supplied to define the exact number of parallel threads used to create the table in parallel, as well as the parallel threads allowed to service the table in the future. (Oracle calculates the best number of threads to use in a given parallel operation, so the PARALLEL clause is an optional feature.) NOPARALLEL, the default, creates the table serially and disallows future parallel queries and data-manipulation operations.


COMPRESS [int] | NOCOMPRESS

Specifies if the table should be compressed or not. On index-organized tables, only the key is compressed; on heap-organized tables, the entire table is compressed. This can greatly reduce the amount of space consumed by the table. NOCOMPRESS is the default. In index-organized tables, you can specify the number of prefix columns, int, to compress. The default value for int is the number of keys in the primary key minus one. You need not specify an int value on other clauses such as ORGANIZATION. When you omit the int value, Oracle will apply compression to the entire table.


{ENABLE | DISABLE} [[NO]VALIDATE]] {UNIQUE (column [,...] | PRIMARY KEY | CONSTRAINT constraint_name}

Declares whether the named key or constraint applies to all of the data in the new table. ENABLE specifies that the key or constraint applies to all new data in the table. DISABLE specifies that the key or constraint is disabled for the new table, with the following options:.


[NO]VALIDATE

Verifies that all existing data in the table complies with the key or constraint (VALIDATE) or not (NOVALIDATE). When NOVALIDATE is specified with ENABLE, Oracle does not verify that existing data in the table complies with the key or constraint, but ensures that new data added to the table does comply with the constraint.


{UNIQUE (column [,...] | PRIMARY KEY | CONSTRAINT constraint_name}

Declares the unique constraint, primary key, or constraint that is enabled or disabled.


USING INDEX index_name | CREATE_INDEX_statement

Declares the name, index_name, of a pre-existing index (and its characteristics) used to enforce the key or constraint, or creates a new index, CREATE_INDEX_statement. If neither are declared, Oracle creates a new index.


EXCEPTIONS INTO

Specifies the name of a table into which Oracle places information about rows violating the constraint. Run the utlexpt1.sql script before using this keyword to explicitly create this table.


CASCADE

Cascades the disablement/enablement to any integrity constraints that depend on the constraint named in the clause. Usable only with the DISABLE clause.


{KEEP | DROP} INDEX

Lets you keep (KEEP) or drop (DROP) an index used to enforce a unique or primary key. You can drop the key only when disabling it.


partition_clause

Declares partitioning and subpartitioning of a table. Partitioning syntax can be quite complex. Refer to the material later in this section under Oracle partitioned and subpartitioned tables for the full syntax and examples.


AS subquery

Declares a subquery that inserts rows into the table upon creation. The column names and datatypes used in the subquery can act as substitutes for column name and attribute declarations for the table.


AS object_type

Declares that the table is based on a pre-existing object type.


[NOT] SUBSTITUTABLE AT ALL LEVELS

Declares whether row objects corresponding to subtypes can be inserted into the type table or not. When this clause is omitted, the default is SUBSTITUTABLE AT ALL LEVELS.


inline_ref_constraint and table_ref_constraint

Declares a reference constraint used by an object-type table or XMLType table. These clauses are described in greater detail later in this section under Oracle XMLType and object-type tables.


OBJECT IDENTIFIER IS {SYSTEM GENERATED | PRIMARY KEY}

Declares whether the object ID (OID) of the object-type table is SYTEM GENERATED or based on the PRIMARY KEY. When omitted, the default is SYSTEM GENERATED.


OIDINDEX [index_name]

Declares an index, and possibly a name for the index, if the OID is system generated. You may optionally apply a physical_attributes_clause and a storage_clause to the OIDINDEX. If the OID is based on the primary key, then this clause is unnecessary.


OF XMLTYPE

Declares that the table is based on Oracle's XMLTYPE datatype.


XMLTYPE {OBJECT RELATIONAL [xml_storage_clause] | CLOB [lob_segname] [lob_params]}

Declares how the underlying storage of the XMLTYPE is handled. OBJECT RELATIONAL stores the data in object-relational columns. This subclause requires an xml_schema_spec and a schema that has been preregistered using the DBMS_XMLSCHEMA package. CLOB specifies that the XMLTYPE data will be stored in a LOB column. You may optionally specify the LOB segment name and/or the LOB storage parameters.


xml_schema_spec

Allows you to specify the URL of a registered XML schema and an XML element name. The element name is required but the URL is optional.


ADD ...

Adds a new column, constraint, overflow segment, or supplemental log group to an existing table.


MODIFY ...

Changes an existing column, constraint, or supplemental log group on an existing table.


DROP ...

Drops an existing column, constraint, or supplemental log group from an existing table. You can explicitly drop columns marked as unused from a table with DROP UNUSED COLUMNS; however, Oracle will also drop all unused columns when any other column is dropped. The INVALIDATE keyword causes any object that depends on the dropped object to become invalid and unusable until it is recompiled or when it is next used. The COLUMNS CONTINUE clause is used only when a DROP COLUMN statement failed with an error and you wish to continue where it left off.


RENAME ...

Renames an existing table, column, or constraint on an existing table.


SET UNUSED ...

Declares a column or columns to be unused. The column or columns are no longer accessible from SELECT statements, though they still count toward the maximum number of columns allowed per table (1000). SET UNUSED is the fastest way to render a column unusable within a table, but it is not the best way. Only use SET UNUSED as a shortcut until you can actually use ALTER TABLE...DROP to drop the column.


COALESCE

Merges the contents of index blocks used to maintain the index-organized table so that the blocks can be reused. COALESCE is similar to SHRINK, though COALESCE compacts the segments less densely than does SHRINK and it does not release unused space.


ALLOCATE EXTENT

Explicitly allocates a new extent for the table using the specified parameters. You may mix and match any of the parameters. The size of the extents may be in bytes (no suffix), kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T).


DEALLOCATE UNUSED [KEEP int[K | M | G | T] ]

Deallocates unused space at the end of the table, LOB segment, partition, or subpartition. The deallocated space is then usable by other objects in the database. The KEEP keyword tells how much space you want to have left over after deallocation is complete.


SHRINK SPACE [COMPACT] [CASCADE]

Shrinks the table, index-organized table, index, partition, subpartition, materialized view, or materialized log view, though only segments in tablespaces with automatic segment management may be shrunk. Shrinking a segment moves rows in the table, so make sure ENABLE ROW MOVEMENT is also used in the ALTER TABLE...SHRINK statement. Oracle compacts the segment, releases the emptied space, and adjusts the high-water mark unless the optional keywords COMPACT and/or CASCADE are applied. The COMPACT keyword only defragments the segment space and compacts the table row for subsequent release, but it does not readjust the high-water mark nor empty the space immediately. The CASCADE keyword performs the same shrinking operation (with some restrictions and exceptions) on all dependent objects of the table, including secondary indexes on index-organized tables. Used only with ALTER TABLE.


UPGRADE [NOT] INCLUDING DATA

Converts the metadata of object tables and relational tables with object columns to the latest version for each referenced type. The INCLUDING DATA clause will convert the data to the latest type format (INCLUDING DATA) or leave it unchanged (NOT INCLUDING DATA).


MOVE ...

Moves the tablespace, index-organized table, partition, or subpartition to a new location on the filesystem.


[NO]MINIMIZE RECORDS_PER_BLOCK

Tells Oracle to restrict or leave open the number of records allowed per block. The MINIMIZE keyword tells Oracle to calculate the maximum number of records per block and set the limit at that number. (Best to do this when a representative amount of data is already in the table.) This clause is incompatible with nested tables and index-organized tables. NOMINIMIZE is the default.


PROJECT COLUMN {REFERENCE | ALL}

Determines how the driver for the external data source validates the rows of the external table in subsequent queries. REFERENCE processes only those columns in the select item list. ALL processes the values in all columns, even those not in the select item list, and validates rows with full and valid column entries. Under ALL, rows are rejected when errors occur, even on columns that are not selected. ALL returns consistent results, while REFERENCE returns varying numbers of rows depending on the columns referenced.


{ENABLE | DISABLE} {TABLE LOCK | ALL TRIGGERS}

Enables or disables table-level locks and all triggers on the table, respectively. ENABLE TABLE LOCK is required if you wish to change the structure against an existing table, but it is not required when changing or reading the data of the table.

A global temporary table is available to all user sessions, but the data stored within a global temporary table is visible only to the session that inserted it. The ON COMMIT clause, which is allowed only when creating temporary tables, tells Oracle to either truncate the table after each commit against the table (DELETE ROWS) or to truncate the table when the session terminates (PRESERVE ROWS). For example:

CREATE GLOBAL TEMPORARY TABLE shipping_schedule

  (ship_date DATE,

   receipt_date DATE,

   received_by VARCHAR2(30),

   amt NUMBER)

ON COMMIT PRESERVE ROWS;

The CREATE TABLE statement shown above creates a global temporary table, shipping_schedule, which retains inserted rows across multiple transactions.

The Oracle physical_attributes_clause

The physical_attributes_clause (as shown in the following code block) defines storage characteristics for an entire local table, or if the table is partitioned, for a specific partition (discussed later). To declare the physical attributes of a new table or change the attributes on an existing table, simply declare the new values:

-- physical_attributes_clause

[{PCTFREE int | PCTUSED int | INITRANS int |

  MAXTRANS int | storage_clause}]

where:


PCTFREE int

Defines the percentage of free space reserved for each data block in the table. For example, a value of 10 reserves 10% of the data space for new rows to be inserted.


PCTUSED int

Defines the minimum percentage of space allowed in a block before it can receive new rows. For example, a value of 90 means new rows are inserted in the data block when the space used falls below 90%. The sum of PCTFREE and PCTUSED cannot exceed 100.


INITRANS int

Rarely tinkered with; it defines the allocation of from 1 to 255 initial transactions to a data block.


MAXTRANS int

Defines the maximum number of concurrent transactions on a data block.

The Oracle storage_clause and LOBs

The storage_clause controls a number of attributes governing the physical storage of data:

-- storage_clause

STORAGE ( [ {INITIAL int [K | M]

            | NEXT int [K | M]

            | MINEXTENTS int

            | MAXEXTENTS { int | UNLIMITED}

            | PCTINCREASE int

            | FREELISTS int

            | FREELIST GROUPS int

            | BUFFER_POOL {KEEP | RECYCLE | DEFAULT} ] [...] )

When delineating the storage clause attributes, enclose them in parentheses and separate them with spaces-for example, (INITIAL 32M NEXT8M). The attributes are as follows:


INITIAL int [K | M]

Sets the initial extent size of the table in bytes, kilobytes (K), or megabytes (M). Oracle 10g allows [K|M|G|T] to describe the size allocation in bytes, kilobytes (K), megabytes (M), gigabytes (G), and terabytes (T).


NEXT int [K | M]

Tells how much additional space to allocate after INITIAL is filled.


MINEXTENTS int

Tells Oracle to create a minimum number of extents. By default, only one is created, but more can be created when the object is initialized.


MAXEXTENTS int

Tells Oracle the maximum extents allowed. This value may be set to UNLIMITED. (Note that UNLIMITED should be used with caution since a table could grow until it consumes all free space on a disk.)


PCTINCREASE int

Controls the growth rate of the object after the first growth. The initial extent gets allocated as specified. The second extent is the size specified by NEXT. The third extent is NEXT + (NEXT * PCTINCREASE). When PCTINCREASE is set to 0, NEXT is always used. Otherwise, each added extent of storage space is PCTINCREASE larger than the previous extent.


FREELISTS int

Establishes the number of freelists for each group, defaulting to 1.


FREELIST GROUPS int

Sets the number of groups of freelists, defaulting to 1.


BUFFER_POOL {KEEP | RECYCLE | DEFAULT}

Specifies a default buffer pool or cache for any non-cluster table where all object blocks are stored. Index-organized tables may have a separate buffer pool for the index and overflow segments. Partitioned tables inherit the buffer pool from the table definition unless they are specifically assigned a separate buffer pool.


KEEP

Puts object blocks into the KEEP buffer pool; that is, directly into memory. This enhances performance by reducing I/O operations on the table. KEEP takes precedence over the NOCACHE clause.


RECYCLE

Puts object blocks into the RECYCLE buffer pool.


DEFAULT

Puts object blocks into the DEFAULT buffer pool. When omitted, DEFAULT is the default buffer pool behavior.

For example, the table books_sales is defined on the sales tablespace as consuming an initial 8 MB of space, to grow by no less than 8 MB when the first extent is full. The table has no less than 1 and no more than 8 extents, limiting its maximum size to 64 MB:

CREATE TABLE book_sales

  (qty NUMBER,

   period_end_date DATE,

   period_nbr NUMBER)

TABLESPACE sales

STORAGE (INITIAL 8M NEXT 8M MINEXTENTS 1 MAXEXTENTS 8);

An example of a LOB table called large_objects with special handling for text and image storage might look like:

CREATE TABLE large_objects

  (pretty_picture   BLOB,

   interesting_text CLOB)

STORAGE (INITIAL 256M NEXT 256M)

LOB (pretty_picture, interesting_text)

   STORE AS (TABLESPACE large_object_segment

      STORAGE (INITIAL 512M NEXT 512M)

      NOCACHE LOGGING);

The exact syntax used to define a LOB, CLOB, or NCLOB column is defined by the lob_parameter_clause. LOBs can appear at many different levels within an Oracle table. For instance, separate LOB definitions could exist in a single table in a partition definition, a subpartition definition, and at the top table-level. The syntax of lob_parameter_clause follows:

{TABLESPACE tablespace_name] [{ENABLE | DISABLE} STORAGE IN ROW]

 [storage_clause] [CHUNK int] [PCTVERSION int]

 [RETENTION] [FREEPOOLS int]

[{CACHE | {NOCACHE | CACHE READS} [{LOGGING | NOLOGGING}] }] }

In the lob_parameter_clause, each parameter is identical to those of the wider CREATE TABLE LOB-object level. However, the following four parameters are unique to LOBs:


{ENABLE | DISABLE} STORAGE IN ROW

Defines whether the LOB value is stored inline with the other columns of the row and the LOB locator (ENABLE), when it is smaller than approximately 4,000 bytes or less, or outside of the row (DISABLE). This setting cannot be changed once it is set.


CHUNK int

Allocates int number of bytes for LOB manipulation. int should be a multiple of the database blocksize, otherwise Oracle will round up. int should also be less than or equal to the value of NEXT, from the storage_clause, or else an error results. When omitted, the default chunk size is one block. This setting cannot be changed once it is set.


PCTVERSION int

Defines the maximum percentage, as int, of the overall LOB storage dedicated to maintaining old versions of the LOB. When omitted, the default is 10%.


RETENTION

Used in place of PCTVERSION on databases in automatic undo mode. RETENTION tells Oracle to retain old versions of the LOB.

The following example shows our large_objects LOB table with added parameters to control inline storage and retention of old LOBs:

CREATE TABLE large_objects

  (pretty_picture   BLOB,

   interesting_text CLOB)

STORAGE (INITIAL 256M NEXT 256M)

LOB (pretty_picture, interesting_text)

   STORE AS (TABLESPACE large_object_segment

      STORAGE (INITIAL 512M NEXT 512M)

      NOCACHE LOGGING

      ENABLE STORAGE IN ROW

      RETENTION);

The earlier example added parameter values for STORAGE IN ROW and RETENTION. But since we did not set one for CHUNK, that value is set to the Oracle default for the LOB.

Oracle nested tables

Oracle allows the declaration of a NESTED TABLE in which a table is virtually stored within a column of another table. The STORE AS clause enables a proxy name for the table within a table, but the nested table must be created initially as a user-defined datatype. This capability is valuable for sparse arrays of values, but we don't recommend it for day-to-day tasks. For example:

CREATE TYPE prop_nested_tbl AS TABLE OF props_nt;

CREATE TABLE proposal_types

   (proposal_category VARCHAR2(50),

   proposals          PROPS_NT)

NESTED TABLE props_nt STORE AS props_nt_table;

This example creates a table called proposal_types along with a nested table called props_nt, which is stored as props_nt_table.

Oracle compressed tables

Oracle 10g (and Oracle 9i Release 2) allows compression of both keys and entire tables. (Oracle 9i allowed only key compression.) Although compression adds a tiny bit of overhead, it significantly reduces that amount of disk space consumed by a table. This is especially useful for databases pushing the envelop in terms of size. Key compression is handled in the ORGANIZE INDEX clause, while table compression is handled in the ORGANIZE HEAP clause.

Oracle partitioned and subpartitioned tables

Oracle allows tables to be partitioned and subpartitioned. You can also break out LOBs onto their own partition(s). A partitioned table may be broken into distinct parts, possibly placed on separate disk subsystems to improve I/O performance, based on four strategies: range, hash, list, and a composite of the first three. Partitioning syntax is quite elaborate:

{  PARTITION BY RANGE (column [,...]) (PARTITION [partition_name]

      VALUES LESS THAN ({MAXVALUE | value} [,...])

      [table_partition_description] ) |

   PARTITION BY HASH (column [,...])

      {(PARTITION [partition_name] [partition_storage_clause] [,...] |

         PARTITIONS hash_partition_qty [STORE IN (tablespace [,...])]

         [OVERFLOW STORE IN (tablespace [,...])]} |

   PARTITION BY LIST (column [,...]) (PARTITION [partition_name]

      VALUES ({MAXVALUE | value} [,...])

      [table_partition_description] |

   PARTITION BY RANGE (column [,...])

      {subpartition_by_list | subpartition_by_hash}

      (PARTITION [partition_name] VALUES LESS THAN

         ({MAXVALUE | value} [,...])

      [table_partition_description] )  }

The following example code shows the orders table partitioned by range:

CREATE TABLE orders

   (order_number NUMBER,

   order_date    DATE,

   cust_nbr      NUMBER,

   price         NUMBER,

   qty           NUMBER,

   cust_shp_id   NUMBER)

PARTITION BY RANGE(order_date)

   (PARTITION pre_yr_2000 VALUES LESS THAN

      TO_DATE('01-JAN-2000', 'DD-MON-YYYY'),

   PARTITION  pre_yr_2004 VALUES LESS THAN

      TO_DATE('01-JAN-2004', 'DD-MON-YYYY'

   PARTITION post_yr_2004 VALUES LESS THAN

      MAXVALUE) ) ;

This example creates three partitions on the orders table - one for the orders taken before the year 2000 (pre_yr_2000), one for the orders taken before the year 2004 (pre_yr_2004), and another for the orders taken after the year 2004 (post_yr_2004) - all based on the range of dates that appear in the order_date column.

The next example creates the orders table based on a hash value in the customer_shipping_id:

CREATE TABLE orders

   (order_number NUMBER,

   order_date    DATE,

   cust_nbr      NUMBER,

   price         NUMBER,

   qty           NUMBER,

   cust_shp_id   NUMBER)

PARTITION BY HASH (cust_shp_id)

   (PARTITION shp_id1 TABLESPACE tblspc01,

   PARTITION  shp_id2 TABLESPACE tblspc02,

   PARTITION  shp_id3 TABLESPACE tblspc03)

ENABLE ROW MOVEMENT;

The big difference in how the records are divided among partitions between the hash partition example and the range partition example is that the range partition code explicitly defines where each record goes, while the hash partition example allows Oracle to decide (by applying a hash algorithm) in which partition to place the record. (Note that we also enabled row movement for the table.)

Examples of list and composite partitioning are shown with the subpartitioning information detailed in the next paragraph. In addition to breaking tables apart into partitions (for easier backup, recovery, or performance reasons), you may further break it apart into subpartitions. The subpartition_by_list clause syntax follows:

SUBPARTITION BY LIST (column)

[SUBPARTITION TEMPLATE

   { (SUBPARTITION subpartition_name

         [VALUES {DEFAULT | {val | NULL} [,...] }

         [partitioning_storage_clause] ) |

      hash_subpartition_qty } ]

For example, we'll recreate the orders table once again, this time using a range-hash composite partition. In a range-hash composite partition, the partitions are broken apart by range values, while the subpartitions are broken apart by hashed values. List partitions and subpartitions are broken apart by a short list of specific values. Because you must list out all the values by which the table is partitioned, the partition value is best taken from a small list of values. In this example, we've added a column (shp_region_id) that allows four possible regions:

CREATE TABLE orders

   (order_number NUMBER,

   order_date    DATE,

   cust_nbr      NUMBER,

   price         NUMBER,

   qty           NUMBER,

   cust_shp_id   NUMBER,

   shp_region    VARCHAR2(20) )

PARTITION BY RANGE(order_date)

SUBPARTITION BY LIST(shp_region)

   SUBPARTITION TEMPLATE(

         (SUBPARTITION shp_region_north

            VALUES ('north','northeast','northwest'),

         SUBPARTITION shp_region_south

            VALUES ('south','southeast','southwest'),

         SUBPARTITION shp_region_central

            VALUES ('midwest'),

         SUBPARTITION shp_region_other

            VALUES ('alaska','hawaii','canada')

   (PARTITION pre_yr_2000 VALUES LESS THAN

      TO_DATE('01-JAN-2000', 'DD-MON-YYYY'),

   PARTITION  pre_yr_2004 VALUES LESS THAN

      TO_DATE('01-JAN-2004', 'DD-MON-YYYY'

   PARTITION post_yr_2004 VALUES LESS THAN

      MAXVALUE) )

ENABLE ROW MOVEMENT;

This code example not only sends the records of the table to one of three partitions based on the order_date, it further partitions the records into one of four subpartitions based on the region where the order is being shipped and on the value of the shp_region column. By using the SUBPARTITION TEMPLATE, you apply the same set of subpartitions to each partition. You can manually override this behavior by specifying subpartitions for each partition.

You may also subpartition using a hashing algorithm. The subpartition_by_hash clause follows:

SUBPARTITION BY HASH (column [,...])

   {SUBPARTITIONS qty [STORE IN (tablespace_name [,...]) ] |

   SUBPARTITION TEMPLATE

      { (SUBPARTITION subpartition_name [VALUES {DEFAULT | {val | NULL}

            [,...] } [partitioning_storage_clause] ) |

         hash_subpartition_qty }

The table_partition_description clause referenced in the partitioning syntax (in the earlier section Oracle partitioned and subpartitioned tables) is, in itself, very flexible and supports precise handling of LOB and VARRAY data:

[segment_attr_clause] [[NO] COMPRESS [int]] [OVERFLOW segment_attr_clause]

[partition_level_subpartition_clause]

[{ LOB { (lob_item [,...] ) STORE AS lob_param_clause |

      (lob_item) STORE AS {lob_segname (log_param_clause) |

         log_segname | (log_param_clause) } } |

   VARRAY varray_item {[{[ELEMENT] IS OF [TYPE] (ONLY type_name) |

         [NOT] SUBSTITUTABLE AT ALL LEVELS}] STORE AS LOB { log_segname |

            [log_segname] (log_param_clause) } |

      [{[ELEMENT] IS OF [TYPE] (ONLY type_name) |

         [NOT] SUBSTITUTABLE AT ALL LEVELS}]

The partition_level_subpartition_clause syntax follows:

{SUBPARTITIONS hash_subpartition_qty [STORE IN (tablespace_name [,...])] |

   SUBPARTITION subpartition_name [VALUES {DEFAULT | {val | NULL} [,...] ]

      [partitioning_storage_clause] }

The partition_storage_clause (see the earlier section Oracle partitioned and subpartitioned tables), like the table-level storage_clause defined earlier, defines how elements of a partition (or subpartition) are stored. The syntax follows:

[{TABLESPACE tablespace_name] | [OVERFLOW TABLESPACE tablespace_name] |

   VARRAY varray_item STORE AS LOB log_segname |

   LOB (lob_item) STORE AS { (TABLESPACE tablespace_name) |

      Log_segname [(TABLESPACE tablespace_name)] }]

In this final partitioning example, we'll again recreate the orders table using a composite range-hash partition, this time with LOB (actually, an NCLOB column) and storage elements:

CREATE TABLE orders

   (order_number NUMBER,

   order_date    DATE,

   cust_nbr      NUMBER,

   price         NUMBER,

   qty           NUMBER,

   cust_shp_id   NUMBER,

   shp_region    VARCHAR2(20),

   order_desc    NCLOB )

PARTITION BY RANGE(order_date)

SUBPARTITION BY HASH(cust_shp_id)

   (PARTITION pre_yr_2000 VALUES LESS THAN

      TO_DATE('01-JAN-2000', 'DD-MON-YYYY') TABLESPACE tblspc01

         LOB (order_desc) STORE AS (TABLESPACE tblspc_a01

            STORAGE (INITIAL 10M NEXT 20M) )

         SUBPARTITIONS subpartn_a,

   PARTITION  pre_yr_2004 VALUES LESS THAN

      TO_DATE('01-JAN-2004', 'DD-MON-YYYY') TABLESPACE tblspc02

         LOB (order_desc) STORE AS (TABLESPACE tblspc_a02

            STORAGE (INITIAL 25M NEXT 50M) )

      SUBPARTITIONS subpartn_b TABLESPACE tblspc_x07,

   PARTITION post_yr_2004 VALUES LESS THAN

      MAXVALUE (SUBPARTITION subpartn_1,

         SUBPARTITION subpartn_2,

         SUBPARTITION subpartn_3

         SUBPARTITION subpartn_4) )

ENABLE ROW MOVEMENT;

In this somewhat more complex example, we now define the orders table with the added NCLOB table called order_desc. In the pre_yr_2000 and pre_yr_2004 partitions, we specify that all of the non-LOB data goes to tablespaces tblspc01 and tblspc02, respectively. However, the NCLOB values of the order_desc column will be stored in the tblespc_a01 and tblspc_a02, respectively, with their own unique storage characteristics. Note that the subpartition subpartn_b under partition pre_yr_2004 is also stored in its own tablespace, tblspc_x07. Finally, the last partition (post_yr_2004) and its subpartitions are stored in the default tablespace for the orders table because no partition- or subpartition-level TABLESPACE clause overrides the default.

Altering partitioned and subpartition tables

Anything about partitions and subpartitions that is explicitly set by the CREATE TABLE statement may be altered after the table is created. Many of the clauses shown later are merely repetitions of clauses that are described in the earlier section about creating partitioned tables; for example, the SUBPARTITION TEMPLATE clause or the MAPPING TABLE clause. Consequently, these clauses will not be repeated. Altering the partitions and/or subpartitions of an Oracle table is governed by this syntax:

ALTER TABLE table_name

   [MODIFY DEFAULT ATTRIBUTES [FOR PARTITION partn_name]

      [physical_attributes_clause] [storage_clause] [PCTTHRESHOLD int]

      [{ADD OVERFLOW ... | OVERFLOW ...}] [[NO]COMPRESS]

      [{LOB (lob_name) | VARRAY varray_name} [(lob_parameter_clause)] ]

      [COMPRESS int | NOCOMPRESS]

    [SET SUBPARTITION TEMPLATE {hash_subpartn_quantity |

      (SUBPARTITION subpartn_name [partn_list]

[storage_clause])}]

    [MODIFY PARTITION partn_name

      { [table_partition_description] |

         [[REBUILD] UNUSABLE LOCAL INDEXES] |

         [ADD [subpartn specification] ] |

         [COALESCE SUBPARTITION [[NO]PARALLEL] [update_index_clause] ] |

         [{ADD | DROP} VALUES (partn_value [,...] ) ] |

         [MAPPING TABLE {ALLOCATE EXTENT ... | DEALLOCATE UNUSUED ...} ]

    [MODIFY SUBPARTITION subpartn_name {hash_subpartn_attributes |

      list_subpartn_attributes} ]

    [MOVE {PARTITION | SUBPARTITION} partn_name

      [MAPPING TABLE] [table_partition_description] [[NO]PARALLEL]

      [update_index_clause] ]

    [ADD PARTITION [partn_name] [p table_partition_description]

      [[NO]PARALLEL] [update_index_clause] ]

    [COALESCE PARTITION [[NO]PARALLEL] [update_index_clause] ]

    [DROP {PARTITION | SUBPARTITION} partn_name [[NO]PARALLEL]

      [update_index_clause] ]

    [RENAME {PARTITION | SUBPARTITION} old_partn_name TO 

new_partn_name]

    [TRUNCATE {PARTITION | SUBPARTITION} partn_name

      [{DROP | REUSE} STORAGE] [[NO]PARALLEL] [update_index_clause] ]

    [SPLIT {PARTITION | SUBPARTITION} partn_name {AT | VALUES}

       (value [,...])

      [INTO (PARTITION [partn_name1] 

[table_partition_description] ,

         (PARTITION [partn_name2] 

[table_partition_description] ) ]

         [[NO]PARALLEL] [update_index_clause] ]

    [MERGE {PARTITION | SUBPARTITION} partn_name1 , partn_name2

      [INTO PARTITION [partn_name] [partn_attributes] ] [[NO]PARALLEL]

      [update_index_clause] ]

    [EXCHANGE {PARTITION | SUBPARTITION} partn_name WITH TABLE table_name

      [{INCLUDING | EXCLUDING} INDEXES] [{WITH | WITHOUT} VALIDATION]

      [[NO]PARALLEL] [update_index_clause] [EXCEPTIONS INTO table_name] ]

where:


MODIFY DEFAULT ATTRIBUTES [FOR PARTITION partn_name]

Modifies a wide variety of attributes for the current partition or a specific partition of partn_name. Refer to the earlier section Oracle partitioned and subpartitioned tables for all the details on partition attributes.


SET SUBPARTITION TEMPLATE {hash_subpartn_quantity | (SUBPARTITION subpartn_name [partn_list] [storage_clause] ) }

Sets a new subpartition template for the table.


MODIFY PARTITION partn_name

Changes a wide variety of physical and storage characteristics, including the storage properties of LOB and VARRAY columns, of a pre-existing partition or subpartition called partn_name. Additional syntax may be appended to the MODIFY PARTITION partn_name clause:

{ [table_partition_description] | [[REBUILD] UNUSABLE LOCAL INDEXES] |

   [ADD [subpartn specification] ] | 

   [COALESCE SUBPARTITION [[NO]PARALLEL] [update_index_clause]

      { [{UPDATE | INVALIDATE} GLOBAL INDEXES] |

         UPDATE INDEXES [ (index_name ( 

         {index_partn | index_subpartn} ) ) [,...] ] } ] |

   [{ADD | DROP} VALUES (partn_value [,...] ) ] |

   [MAPPING TABLE {ALLOCATE EXTENT ... | DEALLOCATE UNUSUED ...}

where:


table_partition_description

Described in the earlier section Oracle partitioned and subpartitioned tables. This clause may be used on any partitioned table.


[REBUILD] UNUSABLE LOCAL INDEXES

Marks the local index partition as UNUSABLE. Adding the optional REBUILD keyword tells Oracle to rebuild the unusable local index partition as part of the operation performed by the MODIFY PARTITION statement. This clause may not be used with any other subclause of the MODIFY PARTITION statement nor may it be used on tables with subpartitions. This clause may be used on any partitioned table.


ADD [subpartn specification]

Adds a hash or list subpartition specification, as described in the earlier section Oracle partitioned and subpartitioned tables, to an existing range partition. This clause may be used to define range-hash or range-list composite partitions only. Oracle populates the new subpartition with rows from other subpartitions using either the hash function or the list values you specify. We recommend the total number of subpartitions be set to a power of 2 for optimal load balancing. You may add range-list subpartitions only if the table does not already have a DEFAULT subpartition. When adding range-list subpartitions, the list value clause is required but it cannot duplicate values found in any other subpartition of the current partition. The only storage or physical attribute you may couple with this clause for both range-hash and range-list subpartitions is the TABLESPACE clause.


COALESCE SUBPARTITION [[NO]PARALLEL] [update_index_clause]

Coalesces the subpartition of a range-hash composite partitioned table. This clause tells Oracle to distribute the contents of the last hash subpartitions to one or more remaining subpartition in the set, and then drop the last hash subpartition. Oracle also drops local index subpartitions corresponding to the subpartition you are coalescing. The update_index_clause is described later in this list. Global indexes may be updated or invalidated using the syntax {UPDATE | INVALIDATE} GLOBAL INDEXES. In addition, local indexes, index partitions, or index subpartitions may be updated using the syntax UPDATE INDEXES (index_name ({index_partn | index_subpartn}].


{ADD | DROP} VALUES (partn_value [,...] )

Adds a new value (or values) or drops existing values on an existing list-partitioned table, respectively. Local and global indexes are not affected by this clause. Values cannot be added to or dropped from a DEFAULT list partition.


MAPPING TABLE {ALLOCATE EXTENT ... | DEALLOCATE UNUSUED ...}

Defines a mapping table for a partitioned table that is an IOT. The ALLOCATE EXTENT and DEALLOCATE UNUSED clauses are described earlier in the syntax description list of the "CREATE TABLE" statement. This clause may be used on any type of partitioned table, as long as the table is an index-organized table.


MODIFY SUBPARTITION subpartn_name {hash_subpartn_attributes | list_subpartn_attributes}

Modifies a specific hash or list subpartition according to the subpartition attributes described in the earlier section Oracle partitioned and subpartitioned tables.


[MOVE {PARTITION | SUBPARTITION} partn_name [MAPPING TABLE] [table_partition_description] [[NO]PARALLEL] [update_index_clause] ]

Moves a specified partition (or subpartition) of partn_name to another partition (or subpartition) described in the table_partition_description clause, which is described in the earlier section Oracle partitioned and subpartitioned tables. Moving a partition is I/O intensive, so the optional PARALLEL clause may be used to parallelize the operation. When omitted, NOPARALLEL is the default. In addition, you may optionally update or invalidate the local and global index as described in the update_index_clause shown below in this list.


ADD PARTITION [partn_name] [table_partition_description] [[NO]PARALLEL]

Adds a new partition (or subpartition) of partn_name to the table. The ADD PARTITION clause supports all aspects of creating a new partition or subpartition, via the table_partition_description clause, which is described in the earlier section Oracle partitioned and subpartitioned tables. Adding a partition may be I/O intensive, so the optional PARALLEL clause may be used to parallelize the operation. When omitted, NOPARALLEL is the default. In addition, you may optionally update or invalidate local and global indexes on the table using the update_index_clause shown earlier in this list.


update_index_clause

Controls the status assigned to indexes once the partitions and/or subpartitions of a table are altered. By default, Oracle invalidates the entire index(es) of a table, not just those portions of the index on the partition and/or subpartition being altered. You may update or invalidate global indexes on the table OR update one or more specific index(es) on the table, respectively, using this syntax:

{ UPDATE | INVALIDATE} GLOBAL INDEXES] | 

  UPDATE INDEXES [ (index_name ( {index_partn|index_subpartn} ) ) [,...] }


COALESCE PARTITION [[NO]PARALLEL] [update_index_clause]

Takes the contents of the last partition of a set of hash partitions and rehashes the contents to one or more of the other partitions in the set. The last partition is then dropped. Obviously, this is only for use with hash partitions. The update_index_clause, shown earlier in this list, may be applied to update or invalidate the local and/or global indexes of the table being coalesced.


DROP {PARTITION | SUBPARTITION} partn_name [[NO]PARALLEL] [update_index_clause]

Drops an existing range or list partition or subpartition of partn_name from the table. The data within the partition is also dropped. If you want to keep the data, use the MERGE PARTITION clause. If you want to get rid of a hash partition or subpartition, use the COALESCE PARTITION clause instead. Tables with only a single partition are not affected by the ALTER TABLE...DROP PARTITION statement; instead, use the DROP TABLE statement.


RENAME {PARTITION | SUBPARTITION} old_partn_name TO new_partn_name

Renames an existing partition or subpartition of old_partn_name to a new name of new_partn_name.


TRUNCATE {PARTITION | SUBPARTITION} partn_name [{DROP | REUSE} STORAGE] [[NO]PARALLEL] [update_index_clause]

Removes all of the rows of a partition or subpartition of partn_name. If you truncate a composition partition, all the rows of the subpartition(s) are also dropped. On IOTs, mapping table partitions and overflow partitions are also truncated. LOB data and index segments, if the table has any LOB columns, are also truncated. Finally, disable any existing referential integrity constraints on the data, or else delete the rows from the table first, then truncate the partition or subpartition. The optional DROP STORAGE and REUSE STORAGE subclauses define whether the space freed by the truncated data is made available for other objects in the tablespace or still allocated to the original partition or subpartition, respectively.


SPLIT {PARTITION | SUBPARTITION} partn_name {AT | VALUES} (value [,...]) [INTO (PARTITION [partn_name1] [table_partition_description], (PARTITION [partn_name2] [table_partition_description]) ] [ [NO]PARALLEL] [update_index_clause] ]

Creates from the current partition (or subpartition) of partn_name two new partitions (or subpartitions) called partn_name1 and partn_name2. These new partitions may have their own complete specification, as defined by the table_partition_description clause. When omitted, the new partitions inherit all physical characteristics of the current partition. When splitting a DEFAULT partition, all of the split values go to partn_name1 while all of the default values go to partn_name2. For IOTs, Oracle splits any mapping table partition in a manner corresponding to the split. Oracle also splits LOB and OVERFLOW segments, but you may also specify your own LOB and OVERFLOW storage characteristics, described in the earlier section Oracle partitioned and subpartitioned tables. Additional syntax for this clause is described below:


{AT | VALUES} (value [,...] )

Splits range partitions (using AT) or list partitions (using VALUES) according to the value or values you specify. The AT (value) clause defines the new noninclusive upper range for the first of the two new partitions. The new value should be less than the partition bound of the current partition, but greater than the partition bound of the next lowest partition (if one exists). The VALUES (value1, value2, [,...]) clause defines the values going into the first of the two new list partitions. The first new list partition is built from value1 and the second is built from the remaining partition values in the current partition of partn_name. The value list must include values that already exist in the current partition, but it cannot contain all of the values of the current partition.


INTO

Defines the two new partitions that result from the split. At a minimum, the two PARTITION keywords, in parentheses, are required. Any characteristics not explicitly declared for the new partitions are inherited from the current partition of partn_name, including any subpartitioning. There are a few restrictions to note. When subpartitioning range-hash composition partitioned tables, only the TABLESPACE value is allowed for the subpartitions. Subpartitioning is not allowed at all when splitting range-list composite partitioned tables. Any indexes on heap-organized tables are invalidated by default when the table is split. You must use the update_index_clause to update their status.


[MERGE {PARTITION | SUBPARTITION} partn_name1, partn_name2 [INTO PARTITION [partn_name] [partn_attributes]] [[NO]PARALLEL] [update_index_clause] ]

Merges the contents of two or more partitions or subpartitions of a table into a single new partition. Oracle then drops the two original partitions. Merged range partitions must be adjacent and are then bound by the higher boundary of the original two partitions when merged. Merged list partitions need not be adjacent and result in a single new partition with a union of the two sets of partition values. If one of the list partitions was the DEFAULT partition, then the new partition will be the default. Merged range-list composite partitions are allowed but may not have a new subpartition template. Oracle creates a subpartition template from the existing one(s) or, if none exist, creates a new DEFAULT subpartition. Physical attributes not defined explicitly are inherited from the table-level settings. By default, Oracle makes all local index partitions and global indexes UNUSABLE unless you override this behavior using the update_index_clause. (The exception to this rule is with IOTs, which, being index-based, will remain USABLE throughout the merge operation.) Merge operations are not allowed on hash-partitioned tables, so use the COALESCE PARTITION clause instead.


EXCHANGE {PARTITION | SUBPARTITION} partn_name WITH TABLE table_name [{INCLUDING | EXCLUDING} INDEXES] [{WITH | WITHOUT} VALIDATION] [[NO]PARALLEL] [update_index_clause] [EXCEPTIONS INTO table_name]

Exchanges the data and index segments of a nonpartitioned table with a partitioned table, or of a partitioned table of one type to another partitioned type. The structure of the tables in the exchange must be identical, including the same primary key. All segment attributes (like tablespaces, logging, and statistics) of the current partitioned table, called partn_name, and the table it is being exchanged with, called table_name, are exchanged. Tables containing LOB columns will also exchange LOB data and index segments. Additional syntax details, which are not previously defined elsewhere in this list, follow:


WITH TABLE table_name

Defines the table that will exchange with the current partition or subpartition.


{INCLUDING | EXCLUDING} INDEXES

Exchanges local index partitions or subpartitions with the table index (on nonpartitioned tables) or the local index (on hash-partitioned tables), using the INCLUDING INDEXES clause. Alternately, marks all index partitions and subpartitions as well as regular indexes and partitioned indexes of the exchanged table to be marked with UNUSABLE status, using the EXLCUDING INDEXES clause.


{WITH | WITHOUT} VALIDATION

Returns errors when any rows in the current table fail to map into a partition or subpartition of the exchanged table, using the WITH VALIDATION clause. Otherwise, the WITHOUT VALIDATION clause may be included to skip checking of row mapping between the tables.


EXCEPTIONS INTO table_name

Places the ROWIDs of all rows violating a UNIQUE constraint (in DISABLE VALIDATE state) on the partitioned table. When omitted, Oracle assumes a table in the current schema called EXCEPTIONS. The EXCEPTIONS table is defined in the utlexcpt.sql and utlexpt1.sql scripts that ship with Oracle. Refer to the Oracle documentation if you need these scripts.

There are a couple of notes to remember about altering a partitioned table. First, altering a partition on a table that serves as the source for one or more materialized views requires that the materialized views be refreshed. Second, bitmap join indexes defined on the partitioned table being altered will be marked UNUSABLE. Third, several restrictions apply if the partitions (or subpartitions) are ever spread across tablespaces that use different block sizes. Refer to the Oracle documentation when attempting these sorts of alterations to a partitioned table.

In the next few examples, assume we are using the orders table partitioned as shown below:

CREATE TABLE orders

   (order_number NUMBER,

   order_date    DATE,

   cust_nbr      NUMBER,

   price         NUMBER,

   qty           NUMBER,

   cust_shp_id   NUMBER)

PARTITION BY RANGE(order_date)

   (PARTITION pre_yr_2000 VALUES LESS THAN

      TO_DATE('01-JAN-2000', 'DD-MON-YYYY'),

   PARTITION  pre_yr_2004 VALUES LESS THAN

      TO_DATE('01-JAN-2004', 'DD-MON-YYYY'

   PARTITION post_yr_2004 VALUES LESS THAN

      MAXVALUE) ) ;

The following statement will mark all of the local index partitions as UNUSABLE in the orders table for the post_yr_2004 partition:

ALTER TABLE orders MODIFY PARTITION post_yr_2004

   UNUSABLE LOCAL INDEXES;

However, we've decided to now split the orders table partition post_yr_2004 into two all new partitions, pre_yr_2008 and post_yr_2008. Values that are now less than MAXVALUE will be stored in the post_yr_2008 partition, while values less than `01-JAN-2008' will be stored in pre_yr_2008:

ALTER TABLE orders SPLIT PARITION post_yr_2004

   AT (TO_DATE('01-JAN-2008','DD-MON-YYYY'))

   INTO (PARTITION pre_yr_2008, PARTITION post_yr_2008);

Assuming that the orders table contained a LOB or a VARRAY column, we could further refine the alteration by including additional details for handling these columns, while also updating the global indexes as the operation completes:

ALTER TABLE orders SPLIT PARITION post_yr_2004

   AT (TO_DATE('01-JAN-2008','DD-MON-YYYY'))

   INTO

      (PARTITION pre_yr_2008

         LOB (order_desc) STORE AS (TABLESPACE order_tblspc_a1),

      PARTITION post_yr_2008)

         LOB (order_desc) STORE AS (TABLESPACE order_tblspc_a1) )

   UPDATE GLOBAL INDEXES;

Now, assuming the orders table has been grown at the upper end, lets merge together the partitions at the lower end:

ALTER TABLE orders

   MERGE PARTITIONS pre_yr_2000, pre_yr_2004

   INTO PARTITION yrs_2004_and_earlier;

After a few years more, we might want to even get rid of the oldest partition, or if not get rid of it, at least give it a better name:

ALTER TABLE orders DROP PARTITION yrs_2004_and_earlier;

ALTER TABLE orders RENAME PARTITION yrs_2004_and_earlier TO pre_yr_2004;

Finally, let's truncate a table partition, delete all of its data, and return the empty space for use by other objects in the tablespace:

ALTER TABLE orders

   TRUNCATE PARTITION pre_yr_2004

   DROP STORAGE;

As the examples illustrate, anything relating to partitioning and subpartitioning that can be created with the Oracle CREATE TABLE statement can later be changed, augmented, or cut down using the Oracle ALTER TABLE statement.

Organized tables: heaps, IOTs, and external tables

Oracle 10g allows powerful means of controlling the physical storage behavior of tables.

The most useful aspect of the ORGANIZATION HEAP clause is that you can now compress an entire table within Oracle. This is extremely useful for reducing disk storage costs in database environments with multi-terabyte tables. The following example creates the orders table in a compressed and logged heap along with a primary key constraint and storage details:

CREATE TABLE orders

   (order_number NUMBER,

   order_date    DATE,

   cust_nbr      NUMBER,

   price         NUMBER,

   qty           NUMBER,

   cust_shp_id   NUMBER,

   shp_region    VARCHAR2(20),

   order_desc    NCLOB,

CONSTRAINT ord_nbr_pk PRIMARY KEY (order_number) )

ORGANIZATION HEAP

   COMPRESS LOGGING

PCTTHRESHOLD 2

STORAGE

   (INITIAL 4M NEXT 2M PCTINCREASE 0 MINEXTENTS 1 MAXEXTENTS 1)

OVERFLOW STORAGE

   (INITIAL 4M NEXT 2M PCTINCREASE 0 MINEXTENTS 1 MAXEXTENTS 1)

ENABLE ROW MOVEMENT;

To define the same table using an index-organized table based on the order_date column, we would use this syntax:

CREATE TABLE orders

   (order_number NUMBER,

   order_date    DATE,

   cust_nbr      NUMBER,

   price         NUMBER,

   qty           NUMBER,

   cust_shp_id   NUMBER,

   shp_region    VARCHAR2(20),

   order_desc    NCLOB,

CONSTRAINT ord_nbr_pk PRIMARY KEY (order_number) )

ORGANIZATION HEAP

   INCLUDING order_date

PCTTHRESHOLD 2

STORAGE

   (INITIAL 4M NEXT 2M PCTINCREASE 0 MINEXTENTS 1 MAXEXTENTS 1)

OVERFLOW STORAGE

   (INITIAL 4M NEXT 2M PCTINCREASE 0 MINEXTENTS 1 MAXEXTENTS 1)

ENABLE ROW MOVEMENT;

Finally, we will create an external table that stores our customer shipping information called cust_shipping_external. The code shown in bold is the opaque_format_spec:

CREATE TABLE cust_shipping_external

   (external_cust_nbr NUMBER(6),

   cust_shp_id        NUMBER,

   shipping_company   VARCHAR2(25) )

ORGANIZATION EXTERNAL

   (TYPE oracle_loader

   DEFAULT DIRECTORY dataloader

   ACCESS PARAMETERS

      (RECORDS DELIMITED BY newline

      BADFILE 'upload_shipping.bad'

      DISCARDFILE 'upload_shipping.dis'

      LOGFILE 'upload_shipping.log'

      SKIP 20

      FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"'

         (client_id INTEGER EXTERNAL(6),

         shp_id CHAR(20),

         shipper CHAR(25) ) )

   LOCATION ('upload_shipping.ctl') )

REJECT LIMIT UNLIMITED;

Examining this example, we see that the external table type is ORACLE_LOADER and the default directory is DATALOADER. The example illustrates the fact that you define the metadata of the table within Oracle and then describe how that metadata references a data source outside of the Oracle database server itself.

Oracle XMLType and object-type tables

When an Oracle XMLType table is created, Oracle automatically stores the data in a CLOB column, unless you create an XML schema-based table. (For details on Oracle's XML support, see Oracle's XMLDB Developer's Guide.) The following code example first creates an XMLType table, distributors, with the implicit CLOB data storage, and followed by a second code example, suppliers, with a more sophisticated XML-schema definition:

CREATE TABLE distributors OF XMLTYPE;

CREATE TABLE suppliers OF XMLTYPE

XMLSCHEMA "http://www.lookatallthisstuff.com/suppliers.xsd"

ELEMENT "vendors";

A key advantage of a table based on an XML schema is that you can create B-Tree indexes on them. In the following example, we create an index on suppliercity:

CREATE INDEX supplier-city-index

ON suppliers

(S."XMLDATA"."ADDRESS"."CITY");

You may similarly create tables using a mix of standard and XMLTYPE columns. In this case, the XMLTYPE column may store its data as a CLOB, or it may store its data in an object-relational column of a structure determined by your specification. For example, we'll recreate the distributors table (this time with some added storage specifications) and the suppliers table with columns of both standard and XMLTYPE:

CREATE TABLE distributors

   (distributor_id NUMBER,

   distributor_spec XMLTYPE)

XMLTYPE distributor_spec

STORE AS CLOB

   (TABLESPACE tblspc_dist

   STORAGE (INITIAL 10M NEXT 5M)

   CHUNK 4000

   NOCACHE

   LOGGING);

CREATE TABLE suppliers

   (supplier_id NUMBER,

   supplier_spec XMLTYPE)

XMLTYPE supplier_spec STORE AS OBJECT RELATIONAL

   XMLSCHEMA "http://www.lookatallthisstuff.com/suppliers.xsd"

   ELEMENT "vendors"

OBJECT IDENTIFIER IS SYSTEM GENERATED

OIDINDEX vendor_ndx TABLESPACE tblspc_xml_vendors;

When creating XML and object tables, you may refer to inline_ref_constraint and table_ref_constraint clauses. The syntax for an inline_ref_constraint clause is:

{SCOPE IS scope_table |

   WITH ROWID |

   [CONSTRAINT constraint_name] REFERENCES object [ (column_name) ]

      [ON DELETE {CASCADE | SET NULL} ]

      [constraint_state] }

The only difference between an inline reference constraint and a table reference constraint is that inline reference constraints operate at the column level and table reference constraints operate at the table level, respectively. (This is essentially the same behavior and coding rule as standard relational constraints like PRIMARY KEY or FOREIGN KEY.) The syntax for a table_ref_constraint follows:

{SCOPE FOR (ref_col | ref_attr) IS scope_table |

   REF (ref_col | ref_attr) WITH ROWID |

   [CONSTRAINT constraint_name] FOREIGN KEY (ref_col | ref_attr)

      REFERENCES object [ (column_name) ]

      [ON DELETE {CASCADE | SET NULL} ]

      [constraint_state] }

The constraint_state clause contains a number of options that have already been defined earlier in the Oracle CREATE TABLE statement. However, these options are only applied to the condition of the scope reference:

[NOT] DEFERRABLE

INITIALLY {IMMEDIATE | DEFERRED}

{ENABLE | DISABLE}

{VALIDATE | NOVALIDATE}

{RELY | NORELY}

EXCEPTIONS INTO table_name

USING INDEX {index_name | ( create_index_statement ) | index_attributes}

Object-type tables are useful for creating tables containing user-defined types. For example, the following code creates the building_type type:

CREATE TYPE OR REPLACE building_type AS OBJECT

   (building_name VARCHAR2(100),

   building_address VARCHAR2(200) );

We can then create a table called offices_object_table that contains the object and defines some of its characteristics, such as OID information. In addition, we'll create two more tables, based upon building_type, that reference the object type as an inline_ref_constraint and a table_ref_constraint, respectively:

CREATE TABLE offices_object_table

   OF building_type (building_name PRIMARY KEY)

OBJECT IDENTIFIER IS PRIMARY KEY;

CREATE TABLE leased_offices

   (office_nbr NUMBER,

   rent        DEC(9,3),

   office_ref  REF building_type

      SCOPE IS offices_object_table);

CREATE TABLE owned_offices

   (office_nbr NUMBER,

   payment     DEC(9,3),

   office_ref  REF building_type

      CONSTRAINT offc_in_bld REFERENCES offices_object_table);

In these examples, the SCOPE IS clause defines the inline_ref_constraint, while the CONSTRAINT clause defines the table_ref_constraint.

Oracle ALTER TABLE

When using the Oracle command ALTER TABLE, you are able to ADD, DROP, or MODIFY every aspect of each element of the table. For example, the syntax diagram shows that the method for adding or modifying an existing column includes its attributes, but we need to explicitly state that the attributes include any Oracle-specific extensions. So while the ANSI standard only lets you modify attributes such as DEFAULT or NOT NULL, as well as column-level constraints assigned to the column, Oracle also allows you to alter any special characteristics like LOB, VARRAY, NESTED TABLE, index-organized table, CLUSTER, or PARTITION settings that might exist.

For example, the following code adds a new column to a table in Oracle, and also adds a new, unique constraint to that table:

ALTER TABLE titles

ADD subtitle VARCHAR2(32) NULL

CONSTRAINT unq_subtitle UNIQUE;

When a foreign key constraint is added to a table, the DBMS verifies that all existing data in the table meets that constraint. If they do not, the ALTER TABLE fails.

Any queries that use SELECT * return the new columns, even if this was not planned. Precompiled objects, such as stored procedures, can return any new columns if they use the %ROWTYPE attribute. Otherwise, a precompiled object may not return any new columns.


Oracle also allows multiple actions, such as ADD or MODIFY, to multiple columns to be performed by enclosing the actions within parentheses. For example, the following command adds several columns to a table with a single statement:

ALTER TABLE titles

ADD (subtitles VARCHAR2(32) NULL,

   year_of_copyright INT,

   date_of_origin DATE);

PostgreSQL

PostgreSQL supports the ANSI standards for CREATE and ALTER TABLE with a couple of extensions that enable you to quickly build a new table from existing table definitions. Following is the syntax for CREATE TABLE:

CREATE [LOCAL][[TEMP]ORARY TABLE table_name

(column_name datatype attributes [,...]

| CONSTRAINT constraint_name [{NULL | NOT NULL}]

  {[UNIQUE] | [PRIMARY KEY (column_name [,...])] | [CHECK (expression) ]

  | REFERENCES reference_table (reference_column [,...])

     [MATCH {FULL | PARTIAL | default}]

     [ON {UPDATE | DELETE}

        {CASCADE | NO ACTION | RESTRICT | SET NULL | SET  DEFAULT value}]

     [[NOT] DEFERRABLE] [INITIALLY {DEFERRED | IMMEDIATE}] } [,...]

| [table_constraint][,...]

[WITH[OUT] OIDE]

[INHERITS (inherited_table [,...])]

[ON COMMIT {DELETE | PRESERVE} ROWS]

[AS select_statement]

The PostgreSQL syntax for ALTER TABLE is:

ALTER TABLE [ONLY] table_name [*]

[ADD [COLUMN] column_name datatype attributes [...] ]

| [ALTER [COLUMN] column_name

     {SET DEFAULT value | DROP DEFAULT | SET STATISTICS int}]

| [RENAME [COLUMN] column_name TO new_column_name]

| [RENAME TO new_table_name]

| [ADD table_constraint]

| [DROP CONSTRAINT constraint_name RESTRICT ]

| [OWNER TO new_owner]

The parameters are as follows:


REFERENCES...MATCH...ON{UPDATE | DELETE} ...

Checks a value inserted into the column against the values of a column in another table. It also can be used as part of a FOREIGN KEY declaration. The MATCH options are FULL, PARTIAL, and the default where MATCH has no other keyword. Full match forces all columns of a multicolumn foreign key either to be NULL or to contain a valid value. The default allows mixed nulls and values. Partial matching is a valid syntax, but is not supported. The REFERENCES clause also allows several different behaviors to be declared for ON DELETE and/or ON UPDATE referential integrity as follows:


NO ACTION

Produces an error when the foreign key is violated (the default).


RESTRICT

A synonym for NO ACTION.


CASCADE

Sets the value of the referencing column to the value of the referenced column.


SET NULL

Sets the referencing column value to NULL.


SET DEFAULT value

Sets the referencing column to its declared default value or NULL, if no default value exists.


NOT DEFERRABLE [INITIALLY {DEFERRED | IMMEDIATE}]

The DEFERRABLE option of the REFERENCES clause tells PostgreSQL to defer evaluation of all constraints to the end of a transaction. NOT DEFERRABLE is the default behavior for the REFERENCES clause. Similar to the DEFERRABLE clause is the INITIALLY clause. Specifying INITIALLY DEFERRED checks constraints at the end of a transaction; INITIALLY IMMEDIATE checks constraints after each statement (the default).


FOREIGN KEY

Can be declared only as a table-level constraint and not as a column-level constraint. All options for the REFERENCES clause are supported as part of the FOREIGN KEYS clause. The syntax follows:

[FOREIGN KEY (column_name [,...]) REFERENCES...]


WITH[OUT] OIDS

Specifies that rows of the new table should have automatically assigned object IDs (WITH OIDS) or not (WITHOUT OIDS). The default is WITH OIDS. OIDs are assigned based on a 32-bit counter. Once the counter is surpassed, the OID numbers cycle over and uniqueness can no longer be guaranteed. We recommend that you add a unique index to any OID columns you specify to avoid an error with duplicate OIDs on very large tables. A table with an inherited structure receives the OID setting of its parent table.


INHERITS inherited_table

Specifies a table or tables from which the table you are creating inherits all columns. The newly created table also inherits functions attached to tables higher in the hierarchy. If any inherited column appears more than once, the statement fails.


ON COMMIT {DELETE | PRESERVE} ROWS

Used only with temporary tables. This clause controls the behavior of the temporary table after records are committed to the table. ON COMMIT DELETE ROWS clears the temporary table of all rows after each commit. This is the default if the ON COMMIT clause is omitted. ON COMMIT PRESERVE ROWS saves the rows in the temporary table after the transaction has committed.


AS select_statement

Enables you to create and populate a table with data from a valid SELECT statement. The column names and datatypes do not need to be defined, since they are inherited from the query. The CREATE TABLE...AS statement has similar functionality to SELECT...INTO, but is more readable.


ONLY

Specifies that only the named table is affected by the ALTER TABLE statement and not any parent or subtables in a table hierarchy.


OWNER TO new_owner

Changes the owner of the table to the user identified by new_owner.

A PostgreSQL table cannot have more than 1,600 columns. However, you should limit the number of columns to well below 1,600 for performance reasons. For example:

CREATE TABLE distributors

   (name    VARCHAR(40) DEFAULT 'Thomas Nash Distributors',

    dist_id INTEGER DEFAULT NEXTVAL('dist_serial'),

    modtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP);

Unique to PostgreSQL is the ability to create column-level constraints with multiple columns. Since PostgreSQL also supports standard table-level constraints, the ANSI-standard approach is still the recommended approach.


PostgreSQL's implementation of ALTER TABLE allows the addition of extra columns using the ADD keyword. Existing columns may have new default values assigned to them using ALTER COLUMN...SET DEFAULT, while ALTER COLUMN...DROP DEFAULT allows the complete erasure of a column-based default. In addition, new defaults may be added to columns using the ALTER clause, but only newly inserted rows will be affected by such new default values. RENAME allows new names for existing columns and tables.

SQL Server

SQL Server offers a plethora of options when defining or altering a table, its columns, and its table-level constraints. Its CREATE TABLE syntax is:

CREATE TABLE table_name

({column_name datatype [ [DEFAULT default_value]

   | {IDENTITY [(seed,increment) [NOT FOR REPLICATION]]]

   [ROWGIDCOL][NULL | NOT NULL]

   | [{PRIMARY KEY | UNIQUE}

        [CLUSTERED | NONCLUSTERED]

        [WITH FILLFACTOR = int] [ON {filegroup | DEFAULT}] ]

   | [[FOREIGN KEY]

        REFERENCES reference_table[(reference_column[,...])]

        [ON {DELETE | UPDATE} {CASCADE | NO ACTION}]

        [NOT FOR REPLICATION]

   | [CHECK [NOT FOR REPLICATION] (expression)

   | [COLLATE collation_name]

| column_name AS computed_column_expression }

[,...]

| [table_constraint] [,...] )

[ON {filegroup | DEFAULT} ]

[TEXTIMAGE_ON {filegroup | DEFAULT} ]

The SQL Server version of ALTER TABLE is:

ALTER TABLE table_name

[ALTER COLUMN column_name new_datatype attributes {ADD | DROP} ROWGUIDCOL]

| [ADD [COLUMN] column_name datatype attributes][,...]

| [WITH CHECK | WITH NOCHECK] ADD table_constraint][,...]

| [DROP { [ CONSTRAINT ] constraint_name | COLUMN column_name }] [,...]

| [{ CHECK | NOCHECK } CONSTRAINT { ALL | constraint_name [,...] }]

| [{ ENABLE | DISABLE } TRIGGER { ALL | trigger_name [,...] }]

The parameters are as follows:


IDENTITY [(seed, increment)]

Creates and populates the column with a monotonically increasing number when applied to an integer column. The IDENTITY starts counting at the value of seed and increases by the value of increment. When either are omitted, the default is 1.


NOT FOR REPLICATION

Specifies that the values of an IDENTITY or FOREIGN KEY are not replicated to subscribing servers. This helps in situations in which different servers require the same table structures, but not the exact same data.


ROWGUIDCOL

Identifies a column as a global unique identifier, which ensures no two values are ever repeated across any number of servers. Only one such column may be identified per table. It does not, however, create the unique values itself. They must be inserted using the NEWID function.


DEFAULT

Applies to any column except those with a TIMESTAMP datatype or an IDENTITY property. The DEFAULT must be a constant value such as a character string or a number, and a system function such as GETDATE( ) or NULL.


PRIMARY KEY

Defines a primary key constraint for the table. The primary key declaration differs from the ANSI standard by allowing you to assign the clustered or nonclustered attributes on the primary key index, as well as a starting fillfactor. (Refer to the CREATE/ALTER INDEX Statement for more information.) The attributes of a primary key include:


CLUSTERED

Declares that the column or columns of the primary key set the physical sort order of the records in the table. CLUSTERED is the default when the clustered or nonclustered keywords are omitted.


NONCLUSTERED

Declares that the primary key index maintains pointers to all of the records of the table.


WITH FILLFACTOR = int

Declares that a percentage of space, int, should remain free on each data page when the table is created. SQL Server does not maintain FILLFACTOR over time. You should rebuild the index on a regular basis.


ON {filegroup | DEFAULT}

Specifies that the primary key is located either on the pre-existing, named filegroup or is assigned to the DEFAULT filegroup.


FOREIGN KEY

Checks values as they are inserted into the table against a column in another table in order to maintain referential integrity. Foreign keys are described in detail in Chapter 2. A foreign key can only reference columns that are defined as a PRIMARY KEY or UNIQUE index on the referencing table. A referential action may be specified to take place on the reference_table when the record is deleted or updated, according to the following:


ON {DELETE | UPDATE}

Specifies that an action needs to happen in the local table when either (or both) an UPDATE or DELETE occur on the referenced table.


CASCADE

Specifies that any DELETE or UPDATE also takes place on the referring table to any records dependent on the value of the FOREIGN KEY.


NO ACTION

Specifies that no action occur on the referring table when a record on the current table is deleted or updated.


NOT FOR REPLICATION

Specifies that an IDENTITY property should not be enforced when the data is replicated from another database. This ensures that data from the published server are not assigned new identity values.


CHECK

Ensures that a value inserted into the specified column of the table is a valid value based on the CHECK expression. For example, the following shows a table with two column-level CHECK constraints.

CREATE TABLE people

    (people_id     CHAR(4)     

        CONSTRAINT pk_dist_id PRIMARY KEY CLUSTERED 

        CONSTRAINT ck_dist_id CHECK (dist_id LIKE '

         [A-Z][A-Z][A-Z][A-Z]'),

     people_name   VARCHAR(40) NULL,

     people_addr1  VARCHAR(40) NULL,

     people_addr2  VARCHAR(40) NULL,

     city          VARCHAR(20) NULL,

     state         CHAR(2)     NULL 

        CONSTRAINT def_st DEFAULT ("CA")

        CONSTRAINT chk_st REFERENCES states(state_ID),

     zip           CHAR(5)     NULL 

        CONSTRAINT ck_dist_zip 

        CHECK(zip LIKE '[0-9][0-9][0-9][0-9][0-9]'),

     phone         CHAR(12)    NULL,

     sales_rep     empid       NOT NULL DEFAULT USER)

GO

The CHECK constraint on the people_id ensures an all-alphabetic ID, while the one on zip ensures an all-numeric value. The REFERENCES constraint on state performs a look-up on the states table. The REFERENCES constraint is essentially the same as a CHECK constraint, except that it derives its list of acceptable values from the values stored in another column. This example illustrates how column-level constraints are named using the CONSTRAINT constraint_name syntax.


COLLATE

Allows programmers to change, on a column-by-column basis, the sort order and character set that is used by the column.


TEXTIMAGE_ON {filegroup | DEFAULT}

Controls the placement of text, ntext, and image columns allowing you to place LOB data on the pre-existing filegroup of your choice. When omitted, these columns are stored in the default filegroup with all other tables and database objects.


WITH [NO]CHECK

Tells SQL Server whether the data in the table should be validated against any newly added constraints or keys. When constraints are added using WITH NOCHECK, the query optimizer ignores them until they are enabled via ALTER TABLE table_name CHECK CONSTRAINT ALL. When constraints are added using WITH CHECK, the constraints are checked immediately against all data already in the table.


[NO]CHECK CONSTRAINT

Enables an existing constraint with CHECK CONSTRAINT or disables one with NOCHECK CONSTRAINT.


{ENABLE | DISABLE} TRIGGER { ALL | trigger_name [,...] }

Enables or disables the specified trigger or triggers, respectively. All triggers on the table may be enabled or disabled by substituting the keyword ALL for the table name, as in ALTER TABLE employee DISABLE TRIGGER ALL. You may, alternately, disable or enable a single trigger_name or more than one trigger by placing each trigger_name in a comma-delimited list.

SQL Server allows any column-level constraint to be named by specifying CONSTRAINT constraint_name..., and then the text of the constraint. Several constraints may be applied to a single column, as long as they are not mutually exclusive (for example, PRIMARY KEY and NULL).

SQL Server also allows a local temporary table to be created, but not using ANSI syntax. A local temporary table, which is stored in the tempdb database, requires a prefix of a single pound sign (#) to the name of the table. The local temporary table is usable by the person or process that created it, and is deleted when the person logs out or the process terminates. A global temporary table, which is usable to all people and processes that are currently logged in, can be established by prefixing two pound signs (##) to the name of the table. The global temporary table is deleted when its process terminates or its creator logs out.

SQL Server also allows the creation of tables with columns that contain a computed value. Such a column does not actually contain data. Instead, it is a virtual column containing an expression using other columns already in the table. For example, a computed column could have an expression, such as order_cost AS (price * qty). Computed columns also can be constants, functions, variables, noncomputed columns, or any of these combined with each other using operators.

Any of the column-level constraints shown earlier also may be declared at the table level. That is, PRIMARY KEY constraints, FOREIGN KEY constraints, CHECK constraints, and others may be declared after all the columns have been defined in the CREATE TABLE statement. This is very useful for constraints that cover more than one column. For example, a column-level UNIQUE constraint can be applied only to that column. However, declaring the constraint at the table level allows it to span several columns. Here is an example of both column-level and table-level constraints:

-- Creating a column-level constraint

CREATE TABLE favorite_books

    (isbn          CHAR(100)    PRIMARY KEY NONCLUSTERED,

     book_name     VARCHAR(40)  UNIQUE,

     category      VARCHAR(40)  NULL,

     subcategory   VARCHAR(40)  NULL,

     pub_date      DATETIME     NOT NULL,

     purchase_date DATETIME     NOT NULL)

GO

-- Creating a table-level constraint

CREATE TABLE favorite_books

    (isbn          CHAR(100)    NOT NULL,

     book_name     VARCHAR(40)  NOT NULL,

     category      VARCHAR(40)  NULL,

     subcategory   VARCHAR(40)  NULL,

     pub_date      DATETIME     NOT NULL,

     purchase_date DATETIME     NOT NULL,

        CONSTRAINT pk_book_id   PRIMARY KEY NONCLUSTERED (isbn)

           WITH FILLFACTOR=70,

        CONSTRAINT unq_book     UNIQUE CLUSTERED (book_name,pub_date))

GO

These two commands provide nearly the same results, except that the table-level UNIQUE constraint has two columns, whereas only one column is included in the column-level UNIQUE constraint.

The following example adds a new CHECK constraint to a table, but does not check to ensure that the existing values in the table pass the constraint:

ALTER TABLE favorite_book WITH NOCHECK

ADD CONSTRAINT extra_check CHECK (ISBN > 1)

GO

In this example, we further add a new column with an assigned DEFAULT value that is placed in each existing record in the table:

ALTER TABLE favorite_book ADD reprint_nbr INT NULL

CONSTRAINT add_reprint_nbr DEFAULT 1 WITH VALUES

GO

-- Now, disable the constraint

ALTER TABLE favorite_book NOCHECK CONSTRAINT add_reprint_nbr

GO

See Also

CREATE SCHEMA
DROP
CREATE/ALTER TRIGGER Statement

A trigger is a special kind of stored procedure that fires automatically (hence the term "trigger") when a specific data-modification statement is executed against a table. The trigger is directly associated with the table and is considered a dependent object. For example, you might want all of the part_numbers in the sales table to be updated when a part_number is changed in the products table, thus ensuring that part numbers are always in sync.

ALTER TRIGGER is not an ANSI-supported statement.


Platform

Command

DB2

Supported, with variations

MySQL

Not supported

Oracle

Supported, with variations

PostgreSQL

Supported, with variations

SQL Server

Supported, with variations


SQL2003 Syntax

CREATE TRIGGER trigger_name

{BEFORE | AFTER} {DELETE | INSERT | UPDATE [OF column [,...]}

ON table_name

[REFERENCING {OLD {[ROW] | TABLE} [AS] old_name | NEW 

{ROW | TABLE} [AS] new_name}] [FOR EACH { ROW | STATEMENT }]

[WHEN (conditions)]

[BEGIN ATOMIC]

code_block

[END]

Keywords


CREATE TRIGGER trigger_name

Creates a trigger of trigger_name and associates it with a specific table.


BEFORE | AFTER

Declares that the trigger logic is fired either BEFORE or AFTER the data manipulation operation that invoked the trigger. BEFORE triggers perform their operations before the INSERT, UPDATE, or DELETE operation occurs, allowing you to do dramatic things like circumvent the data manipulation operation altogether. AFTER triggers fire after the data manipulation operation has completed, but are useful for after-the-fact operations like recalculating running totals.


DELETE | INSERT | UPDATE [OF column [,...] ]

Defines the data manipulation operation that causes the trigger to fire: DELETE statements, INSERT statements, or UPDATE statements. You may optionally chose which columns will trigger an update trigger using UPDATE OF column [,...]. If an update occurs on any columns not in the column list, the trigger will not fire.


ON table_name

Declares the pre-existing table that the trigger is dependent on.


REFERENCING {OLD {[ROW] | TABLE} [AS] old_name | NEW {ROW | TABLE} [AS] new_name}

Enables aliasing for the old or new ROW or TABLE acted upon by the trigger. Although the syntax shows the options as exclusive, you may have up to four aliasing references: one for old row, one for old table, one for new row, and one for new table. The alias OLD refers to the data contained in the table or row before the data manipulation operation that fired the trigger, while the alias NEW refers to the data that would be contained in the table or row after the data manipulation operation that fired the trigger. Note that the syntax indicates that ROW is optional, but TABLE is not. (That is, OLD ROW AS is the same as OLD AS, but for TABLE, the only valid option is OLD TABLE AS.) INSERT triggers do not have an OLD context, while DELETE triggers do not have a NEW context. The keyword AS is noise and may be omitted. If the REFERENCING clause specifies either OLD ROW or NEW ROW, then the FOR EACH ROW clause is required.


FOR EACH { ROW | STATEMENT }

Tells the database to apply the trigger for each row in the table that has changed (ROW) or for each SQL statement issued against the table (STATEMENT). For example, a single UPDATE statement will update the salaries of 100 employees. If you specify FOR EACH ROW, the trigger will execute 100 times. If you specify FOR EACH STATEMENT, the trigger will execute only once.


WHEN (conditions)

Allows you to define additional criteria for a trigger. For example, you might have a trigger called DELETE employee, which will fire whenever an employee is deleted. When a trigger fires, if the search conditions contained in the WHEN clause evaluate to TRUE, the trigger action will fire. Otherwise, the trigger will not fire.


BEGIN ATOMIC | code_block | END

The ANSI standard requires that the code_block should contain only one SQL statement or, for multiple SQL statements, put them in a BEGIN and END block.

Rules at a Glance

Triggers, by default, fire once at the statement level. That is, a single INSERT statement might insert 500 rows into a table, but an insert trigger on that table fires only one time. Some vendors allow a trigger to fire for each row of the data-modification operation. So, a statement that inserts 500 rows into a table that has a row-level insert trigger fires 500 times, once for each inserted row.

In addition to being associated with a specific data-modification statement (INSERT, UPDATE, or DELETE) on a given table, triggers are associated with a specific time of firing. In general, triggers can fire BEFORE the data-modification statement is processed, AFTER it is processed, or (when supported by the vendor) INSTEAD OF processing the statement. Triggers that fire before or instead of the data-modification statement do not see the changes that the statement renders, while those that fire afterwards can see and act upon the changes that the data-modification statement renders.

Triggers make use of two pseudotables. They are pseudotables in the sense that they are not declared with a CREATE TABLE statement, but they exist logically on the database. The pseudotables have different names on the different platforms, but we'll call them Before and After here. They are structured exactly the same as the table a trigger is associated with. However, they contain snapshots of the table's data. The Before table contains a snapshot of all the records in the table before the trigger fired, while the After table contains a snapshot of all the records in the table after the event occurred that fired the trigger. You can then use comparison operations to compare the data in the table before and after the event fired the trigger to determine exactly what you want to happen.

Here is an Oracle BEFORE trigger that uses the OLD and NEW pseudotables to compare values. (By way of comparison, SQL Server uses the DELETED and INSERTED pseudotables in the same way, while DB2 requires that you provide a REFERENCING clause to give names to the pseudotables.) This trigger creates an audit record before changing an employee's pay record:

CREATE TRIGGER if_emp_changes

BEFORE DELETE OR UPDATE ON employee

FOR EACH ROW

WHEN (new.emp_salary <> old.emp_salary)

BEGIN

  INSERT INTO employee_audit

  VALUES ('old', :old.emp_id, :old.emp_salary, :old.emp_ssn);

END;

You can also take advantage of capabilities within each database platform to make your triggers more powerful and easier to program. For example, Oracle has a special IF...THEN clause for use just in triggers. This IF...THEN clause takes the form: IF DELETING THEN, IF INSERTING THEN, or IF UPDATING THEN. The following example builds an Oracle DELETE and UPDATE trigger that uses the IF DELETING THEN clauses:

CREATE TRIGGER if_emp_changes

BEFORE DELETE OR UPDATE ON employee

FOR EACH ROW

BEGIN

  IF DELETING THEN

    INSERT INTO employee_audit

    VALUES ('DELETED', :old.emp_id, :old.emp_salary, :old.emp_ssn);

  ELSE

    INSERT INTO employee_audit

    VALUES ('UPDATED', :old.emp_id, :new.emp_salary, :old.emp_ssn);

  END IF;

END;

This SQL Server example adds a new table called contractor to the database. All records in the employee table that indicate that the employee is a contractor were moved into the contractor table. Now all new employees inserted into the employee table will go into the contractor table instead through an INSTEAD OF INSERT trigger:

CREATE TRIGGER if_emp_is_contractor

INSTEAD OF INSERT ON employee

BEGIN

  INSERT INTO contractor

  SELECT * FROM inserted WHERE status = 'CON'

  INSERT INTO employee

  SELECT * FROM inserted WHERE status = 'FTE'

END

GO

Adding triggers to a table that already has data in it does not cause the triggers to fire. A trigger will fire only for data-modification statements declared in the trigger definition that occur after the trigger is created.

A trigger generally ignores structural changes to tables, such as an added column or an altered datatype on an existing column, after the trigger has been created unless a table modification directly interferes with the operation of the trigger. For example, adding a new column to a table will result in any existing trigger ignoring the new column, except for UPDATE triggers. On the other hand, removing a column from a table that is used by a trigger will cause the trigger to fail every time it executes.

Programming Tips and Gotchas

One of the key programming issues associated with triggers is the inappropriate and uncontrolled use of nested triggers and recursive triggers. A nested trigger is a trigger that invokes a data-manipulation operation that causes other triggers to fire. For example, assume we have three tables, T1, T2, and T3. Table T1 has a BEFORE INSERT trigger that inserts a record into table T2. Table T2 also has a BEFORE INSERT trigger that inserts a record into table T3. Although this is not necessarily a bad thing if your logic is well considered and fully thought out, it does introduce two problems. First, an insert into table T1 requires many more I/O operations and transactions than a simple INSERT statement against table T1. Second, you can get yourself into hot water if, in fact, table T3 performs an INSERT operation against table T1. In a case like that, you may have a looping trigger process that can consume all available disk space and even shut down the server.

Recursive triggers are triggers that can fire themselves; for example an INSERT trigger that performs an INSERT against its own base table. If the procedural logic within the code_body is not properly constructed, you can cause a looping trigger error. However, recursive triggers often require setting a special configuration flag before they can be used on the various database platforms.

DB2

DB2 supports a superset of the ANSI SQL standard for the CREATE TRIGGER statement. It does not support an ALTER TRIGGER statement. The CREATE TRIGGER syntax is:

CREATE TRIGGER trigger_name

{NO CASCADE BEFORE | AFTER | INSTEAD OF}

{[DELETE] | [INSERT] | [UPDATE [OF (column [,...]) ]}

ON table_name

[REFERENCING

   {OLD[_TABLE] [AS] old_name | NEW[_TABLE]

   [AS] new_name} DEFAULTS NULL]

[FOR EACH { ROW | STATEMENT }]

MODE DB2SQL

[WHEN (conditions)]

code_block 

where:


NO CASCADE BEFORE

Declares that the trigger action is applied before the data-modification operation is applied to the table. This clause also declares that the trigger action will not cause any other triggers to fire.


ON table_name

Specifies the pre-existing table or view that the trigger is associated with. Triggers can be declared on regular tables, but not on temporary tables, nicknames, catalog tables, or materialized query tables. When creating triggers on a view, only INSTEAD OF triggers are allowed. The view must be a non-typed view that does not use the WITH CHECK OPTION clause. The data-modification operation applied to the view should be translated against the base table to determine whether it will fire the trigger or not.


OLD[_TABLE] [AS] old_name | NEW[_TABLE] [AS] new_name

Defines the alias for the ANSI before and after pseudotables using OLD_TABLE and NEW_TABLE, respectively. If you leave off the _TABLE keyword, then DB2 assigns the trigger operation as row-level, and allows you to access the row (singular) data prior to triggering the SQL operation. Adding in the _TABLE keyword declares that the trigger operation allows you to reference the set (plural) of row data prior to triggering the SQL operation. OLD and OLD_TABLE may only be used on DELETE or UPDATE triggers. Conversely, NEW and NEW_TABLE can only be used on INSERT and UPDATE triggers. OLD and NEW may only be specified once each. OLD_ TABLE and NEW_TABLE may only be specified once each and not on NO CASCADE BEFORE triggers.


DEFAULTS

Inserts default values where they have been created.


FOR EACH { ROW | STATEMENT }

Specifies that the trigger action applies either at the row level or the statement level. The FOR EACH STATEMENT clause is only allowed on AFTER triggers.


MODE DB2SQL

Declares that the mode of the trigger is DB2 SQL, the only mode currently supported.


WHEN (conditions)

Meets the ANSI SQL standard with the exception that this clause is not allowed on DB2 INSTEAD OF triggers.

DB2 does not prevent a new trigger from being created that has the same definition as an older trigger. Thus, it's possible to have two (or more) AFTER DELETE triggers on a single table. In a situation like this, DB2 will always fire the triggers in the order they were created.

Be careful declaring a BEFORE DELETE trigger on a table with a self-referencing constraint and a delete rule of CASCADE. Such a trigger may produce results that you did not expect!

DB2 allows the COMMENT ON object_type statement, so that you can provide extra commentary on any supported DB2 object. For example, you can issue the COMMENT ON TRIGGER trigger_name statement to add comments on any trigger you add to the database. You can use this on tables, views, etc.


DB2 does not specifically drop the triggers associated with a table or view when the table or view itself is dropped. Consequently, you should first issue a DROP TRIGGER statement followed by a DROP TABLE statement to avoid leaving orphaned triggers behind. Conversely, triggers are not reinstated if a table is dropped and then recreated. The triggers should be recreated as well.

BEFORE and AFTER triggers are allowed on typed tables at any level of a typed-table hierarchy. Triggers may activate on rows of subtables. If a SQL statement activates multiple triggers, the triggers will be executed in their creation order, even if they are attached to different tables in the typed-table hierarchy.

MySQL

Not supported.

Oracle

Oracle supports the ANSI standard for CREATE TRIGGER, with several additions and variations:

CREATE [OR REPLACE] TRIGGER trigger_name

{BEFORE | AFTER | INSTEAD OF}

{ {[object_event] [database_event] [...] ON {DATABASE | schema.SCHEMA} } |

   {[DELETE] [OR] [INSERT] [OR] [UPDATE [OF column [,...] ]] [...]}

      ON {table_name | [NESTED TABLE column_name OF] view_name}

   [REFERENCING {[OLD [AS] old_name] [NEW [AS] new_name]

      [PARENT [AS] parent_name]}

   [FOR EACH ROW] }

[WHEN (conditions)]

code_block

The syntax for ALTER TRIGGER, which allows you to rename, enable, or disable a trigger without dropping and recreating it, is shown below:

ALTER TRIGGER trigger_name

{ {ENABLE | DISABLE} | RENAME TO new_name |

   COMPILE [compiler_directives] [DEBUG] [REUSE SETTINGS]}

where:


OR REPLACE

Recreates an existing trigger by assigning a new definition to an existing trigger of trigger_name.


object_event

In addition to the standard data-modification events, Oracle allows triggers to fire based on object events. object_event operations may be paired with BEFORE and AFTER keywords. An object_event fires the trigger whenever such an event occurs, according to the following keywords:


ALTER

Fires whenever an ALTER statement (except ALTER DATABASE) is issued.


ANALYZE

Fires whenever Oracle validates the structure of a database object, or collects or deletes statistics on an index.


ASSOCIATE STATISTICS

Fires whenever Oracle associates a statistics type with a database object.


AUDIT

Fires whenever Oracle tracks a SQL statement or operation against a schema object.


COMMENT

Fires whenever an Oracle comment is added in the data dictionary to a database object.


DDL

Fires whenever Oracle encounters any object_event in this list.


DISASSOCIATE STATISTICS

Fires whenever Oracle disassociates a statistics type from a database object.


DROP

Fires whenever a DROP statement erases a database object from the data dictionary.


GRANT

Fires whenever a user grants privileges or roles to another user or role.


NOAUDIT

Fires whenever the NOAUDIT statement causes Oracle to stop tracking SQL statements or operations against schema objects.


RENAME

Fires whenever the RENAME statement changes the name of a database object.


REVOKE

Fires whenever a user revokes privileges or roles from another user or role.


TRUNCATE

Fires whenever a TRUNCATE statement is issued against a table or cluster.


database_event

In addition to the standard data-modification events, Oracle allows triggers to fire based on database events. Database_event operations may be paired with BEFORE and AFTER keywords. The list of allowable database_event keywords is:


LOGON

Fires whenever a client application logs on to the database. Valid for AFTER triggers only.


LOGOFF

Fires whenever a client application logs off of the database. Valid for BEFORE triggers only.


SERVERERROR

Fires whenever a server error message is logged. Valid for AFTER triggers only.


SHUTDOWN

Fires whenever an instance of the database is shut down. Valid for BEFORE triggers only with the ON DATABASE clause only.


STARTUP

Fires whenever an instance of the database is opened. Valid for AFTER triggers with the ON DATABASE clause.


SUSPEND

Fires whenever a server error causes a transaction to suspend. Valid for AFTER triggers only.


ON {DATABASE | schema.SCHEMA}

Declares that the trigger fires whenever any database user invokes a triggering event with ON DATABASE. The trigger then fires for events occurring anywhere in the entire database. Otherwise, ON schema.SCHEMA declares that the trigger fires whenever a user connected as schema invokes a triggering event. The trigger then fires for events occurring anywhere in the current schema.


ON [NESTED TABLE column_name OF] view_name

Declares that the trigger fires only if the data-manipulation operation applies to the column(s) of the view called view_name. The ON NESTED TABLE clause is compatible only with INSTEAD OF triggers.


REFERENCING PARENT [AS] parent_name

Defines the alias for the current row of the parent table (i.e., supertable). Otherwise, identical to the ANSI standard.


ENABLE

Enables a deactivated trigger when used with ALTER TRIGGER. You may alternately use the statement ALTER TABLE table_name ENABLE ALL TRIGGERS.


DISABLE

Disables an activated trigger when used with ALTER TRIGGER. You may alternately use the statement ALTER TABLE table_name DISABLE ALL TRIGGERS.


RENAME TO new_name

Renames the trigger to new_name, though the state of the trigger remains unchanged when used with ALTER TRIGGER.


COMPILE [DEBUG] [REUSE SETTINGS]

Compiles a trigger, whether valid or invalid, and all the objects that the trigger depends on. If any the objects are invalid, then the trigger is invalid. If all of the objects are valid, including the code_body of the trigger, then the trigger becomes valid. The subclauses of the COMPILE clause are:


DEBUG

Tells the PL/SQL compiler to generate and store the extra information for use by the PL/SQL debugger.


REUSE SETTINGS

Tells Oracle to retain all compiler switch settings, which can save significant time during the compile process.


compiler_directives

Defines a special value for the PL/SQL compiler in the format: directive = 'value'. The directives are: PLSQL_OPTIMIZE_LEVEL, PLSQL_CODE_TYPE, PLSQL_DEBUG, PLSQL_WARNINGS, and NLS_LENGTH_SEMANTICS. They may each specify a value once in the statement. The directive is valid only for the unit being compiled.

When referencing values in the OLD and NEW pseudotables, the values must be prefaced with a colon (:), except in the trigger's WHEN clause, where no colons are used. In this example, we'll call a procedure in the code_body and use both :OLD and :NEW values as arguments:

CREATE TRIGGER scott.sales_check

BEFORE INSERT OR UPDATE OF ord_id, qty ON scott.sales

   FOR EACH ROW

   WHEN (new.qty > 10)

   CALL check_inventory(:new.ord_id, :new.qty, :old.qty);

Multiple trigger types may be combined into a single trigger command if they are of the same level (row or statement) and they are on the same table. When triggers are combined in a single statement, the clauses IF INSERTING THEN, IF UPDATING THEN, and IF DELETING THEN may be used in the PL/SQL block to break the code logic into distinct segments. An ELSE clause also can be used in this structure.

Following is an example of a database_event-style trigger:

CREATE TRIGGER track_errors

AFTER SERVERERROR ON DATABASE

BEGIN

   IF (IS_SERVERERROR (04030))

      THEN INSERT INTO errors ('Memory error');

   ELSE (IS_SERVERERROR (01403))

      THEN INSERT INTO errors ('Data not found');

   END IF;

END;

In another example, we can create a trigger that is SCHEMA-wide in scope:

CREATE OR REPLACE TRIGGER create_trigger

AFTER CREATE ON scott.SCHEMA

BEGIN

   RAISE_APPLICATION_ERROR (num => -20000, msg =>

   'Scott created an object');

END;

PostgreSQL

PostgreSQL's implementation of CREATE TRIGGER offers a subset of features found in the ANSI standard. On PostgreSQL, a trigger may fire BEFORE a data-modification operation is attempted on a record and before any constraints are fired or it may fire AFTER a data-manipulation operation fires (and after constraints have been checked), making all operations involved in the transaction visible to the trigger. Finally, the trigger may fire INSTEAD OF the data-modification operation and completely replace the INSERT, UPDATE, or DELETE statement with some other behavior. The CREATE TRIGGER syntax is:

CREATE TRIGGER trigger_name

{ BEFORE | AFTER }

{ {[DELETE] [OR | ,] [INSERT] [OR | ,] [UPDATE]} [OR ...] }

ON table_name

FOR EACH { ROW | STATEMENT }

EXECUTE PROCEDURE function_name (parameters)

The parameters are:


OR

Declares an additional trigger action. The OR keyword is a synonym for the comma delimiter.


FOR EACH ROW

Explicitly declares that the trigger acts on the row level. This is also the default. Although PostgreSQL does not reject the STATEMENT keyword, it does not enforce statement-level triggers.


EXECUTE PROCEDURE function_name (parameters)

Executes a previously defined function (created using CREATE FUNCTION) rather than a block of procedural code. (PostgreSQL does not have its own procedural language.)

The following is an example of a PostgreSQL BEFORE trigger that checks at a row level to ensure that the specified distributor code exists in the distributors table before inserting or updating a row in the sales table:

CREATE TRIGGER if_dist_exists

BEFORE INSERT OR UPDATE ON sales

FOR EACH ROW

EXECUTE PROCEDURE check_primary_key

   ('dist_id', 'distributors', 'dist_id');

BEFORE and AFTER triggers are supported by the ANSI standard. INSTEAD OF triggers on PostgreSQL completely skip the data-modification operation that triggered them in favor of code that you substitute for the data-modification operation.

SQL Server

SQL Server supports the basics of the ANSI standard with the addition of the INSTEAD OF trigger type and a column change check. It does not support the REFERENCING or WHEN clauses. Its syntax is:

{CREATE | ALTER} TRIGGER trigger_name ON table_name

[WITH ENCRYPTION]

{FOR | AFTER | INSTEAD OF} {[DELETE] [,] [INSERT] [,] [UPDATE]}

[WITH APPEND]

[NOT FOR REPLICATION]

AS

  [IF UPDATE(column) [{AND | OR} UPDATE(column)][...] ]

  code_block

where:


{CREATE | ALTER} TRIGGER trigger_name

Creates a new trigger of trigger_name or alters an existing trigger of trigger_name by adding or changing trigger properties or the trigger code_block. When altering an existing trigger, the permissions and dependencies of the existing trigger are maintained.


ON table_name

Declares the table or view that the trigger is dependent on. Views may have INSTEAD OF triggers defined on them, as long as they are updateable and do not have the WITH CHECK clause on them.


WITH ENCRYPTION

Encrypts the text of the CREATE TRIGGER statement as shown in the syscomments table. This option is useful to protect important intellectual property. WITH ENCRYPTION prevents the trigger from use in a SQL Server replication scheme.


FOR | AFTER | INSTEAD OF

Tells SQL Server when the trigger should fire. (FOR and AFTER are synonyms.) AFTER specifies that the trigger fire only after the triggering data-modification statement (and any cascading actions and constraint checks) have completed successfully. The INSTEAD OF trigger is similar to the ANSI BEFORE trigger in that the code of the trigger may completely replace the data-modification operation. It specifies that the trigger is executed instead of the data-modification statement that fired the trigger. INSTEAD OF DELETE triggers cannot be used when there is a cascading action on the delete. Only INSTEAD OF triggers can access TEXT, NTEXT, or IMAGE columns.


WITH APPEND

Adds an additional trigger of an existing type to a table or view. This clause is supported for backward compatibility with earlier versions of the product and can be used only with FOR triggers.


NOT FOR REPLICATION

Prevents data-manipulation operations invoked through SQL Server's built-in replication engine from firing the trigger.


IF UPDATE(column) [{AND | OR} UPDATE(column)][...]

Allows you to chose the specific columns that fire the trigger. A column-specific trigger fires only on UPDATE and INSERT operations, but not on DELETE operations. If an UPDATE or INSERT occurs on any columns not in the column list, the trigger will not fire.

SQL Server allows multiple triggers for a given data-manipulation operation on a table or view. Thus, three UPDATE triggers are possible on a single table. Multiple AFTER triggers are possible on a given table. Their specific order is undefined, though the first and last triggers can be explicitly declared using the sp_settriggerorder system stored procedure. Only one INSTEAD OF trigger is possible per INSERT, UPDATE, or DELETE statement on a given table.

In SQL Server, any combination of triggers is made possible in a single trigger definition statement by separating each option with a comma. (When doing so, the same code fires for each statement in the combination definition.)

SQL Server implicitly fires in the FOR EACH STATEMENT style of the ANSI standard.

SQL Server instantiates two important pseudotables when a trigger is fired: deleted and inserted. They are equivalent to the before and after pseudotables, respectively, described earlier in the ANSI Rules at a Glance section. These tables are identical in structure to the table on which the triggers are defined, except that they contain the old data before the data-modification statement fired (deleted) and the new values of the table after the data-modification statement fired (inserted).

The AS IF UPDATE(column) clause tests specifically for INSERT or UPDATE actions on a given column or columns, in the way the ANSI statement uses the UPDATE(column) syntax. Specify multiple columns by adding separate UPDATE(column) clauses after the first. Follow the AS IF UPDATE(column) clause with a Transact-SQL BEGIN...END block to allow the trigger to fire multiple Transact-SQL operations. This clause is functionally equivalent to the IF...THEN...ELSE operation.

In addition to intercepting data modification statements as shown in the ANSI SQL example, SQL Server allows you to perform other sorts of actions when a data modification operation occurs. In the following example, we've decided that the table sales_archive_2002 is off limits and that anyone who attempts to alter data in these tables is to be notified of that restriction:

CREATE TRIGGER archive_trigger

ON sales_archive_2002

FOR INSERT, UPDATE

AS RAISERROR (50009, 16, 10, 'No changes allowed to this table')

GO

SQL Server does not allow the following statements within the Transact-SQL code_block of a trigger: ALTER, CREATE, DROP, DENY, GRANT, REVOKE, LOAD, RESTORE, RECONFIGURE, or TRUNCATE. In addition, it does not allow any DISK statements or the UPDATE STATISTICS command.

SQL Server also allows triggers to fire recursively using the recursive triggers setting of the sp_dboption system stored procedure. Recursive triggers, by their own action, cause themselves to fire again. For example, if an INSERT trigger on table T1 performs an INSERT operation on table T1, it might perform a recursive operation. Since recursive triggers can be dangerous, this functionality is disabled by default.

Similarly, SQL Server allows nested triggers up to 32 levels deep. If any one of the nested triggers performs a ROLLBACK operation, no further triggers execute. An example of nested triggers is a trigger on table T1 firing an operation against table T2, which also has a trigger that fires an operation against table T3. The triggers cancel if an infinite loop is encountered. Nested triggers are enabled with the nested triggers setting of the system stored procedure sp_configure. If nested triggers are disabled, recursive triggers are disabled as well, despite the recursive triggers setting of sp_dboption.

In the following example, we want to reroute the user activity that occurs on the people table, especially update transactions, so that changes to records in the people table are instead written to the people_reroute table. (A more elaborate version of the people table is shown in SQL Server in the CREATE/ALTER TABLE Statement section.) Our update trigger will record any changes to columns 2, 3, or 4 of the people table and write it to the people_reroute table. The trigger will also record which user issued the update transaction and the time of the transaction:

CREATE TABLE people

   (people_id    CHAR(4),

   people_name   VARCHAR(40),

   people_addr   VARCHAR(40),

   city          VARCHAR(20),

   state         CHAR(2),

   zip           CHAR(5),

   phone         CHAR(12),

   sales_rep     empid NOT NULL)

GO

CREATE TABLE people_reroute

   (reroute_log_id       UNIQUEIDENTIFIER DEFAULT NEWID( ),

   reroute_log_type      CHAR (3) NOT NULL,

   reroute_people_id     CHAR(4),

   reroute_people_name   VARCHAR(40),

   reroute_people_addr   VARCHAR(40),

   reroute_city          VARCHAR(20),

   reroute_state         CHAR(2),

   reroute_zip           CHAR(5),

   reroute_phone         CHAR(12),

   reroute_sales_rep     empidNOT NULL,

   reroute_user sysname DEFAULT SUSER_SNAME( ),

   reroute_changed datetime DEFAULT GETDATE( ) )

GO

CREATE TRIGGER update_person_data

ON people

FOR update AS

IF (COLUMNS_UPDATED(people_name)

   OR COLUMNS_UPDATEE(people_addr)

   OR COLUMNS_UPDATED(city) )

BEGIN

-- Audit OLD record.

   INSERT INTO people_reroute (reroute_log_type, reroute_people_id,

      reroute_people_name, reroute_people_addr, reroute_city)

   SELECT 'old', d.people_id, d.people_name, d.people_addr, d.city

   FROM deleted AS d

-- Audit NEW record.

   INSERT INTO people_reroute (reroute_log_type, reroute_people_id,

      reroute_people_name, reroute_people_addr, reroute_city)

   SELECT 'new', n.people_id, n.people_name, n.people_addr, n.city

   FROM inserted AS n

END

GO

Note that SQL Server CREATE statements allow deferred name resolution, meaning that a command is processed even if it refers to a database object that does not yet exist in the database.

See Also

CREATE?ALTER FUNCTION/PROCEDURE
DELETE
DROP
INSERT
UPDATE
CREATE/ALTER TYPE Statement

The CREATE TYPE statement allows you to create a user-defined type (UDT); that is, a user-defined datatype or "class" in object-oriented terms. UDTs extend SQL capabilities into the realm of object-oriented programming by allowing inheritance and other object-oriented features. You can also create something called typed tables with the CREATE TABLE statement using a previously created type made with the CREATE TYPE statement. Typed tables are based on UDTs and are equivalent to "instantiated classes" from object-oriented programming.

Platform

Command

DB2

Supported, with variations

MySQL

Not supported

Oracle

Supported, with limitations

PostgreSQL

Supported, with variations

SQL Server

Not supported


SQL2003 Syntax

CREATE TYPE type_name

[UNDER supertype_name]

[AS [new_udt_name] datatype [attribute] [,...]

   {[REFERENCES ARE [NOT] CHECKED

      [ON DELETE

         {NO ACTION | CASCADE | RESTRICT | SET NULL | SET DEFAULT} ] ] |

   [DEFAULT value] |

   [COLLATE collation_name] } ]

   [ [NOT] INSTANTIABLE]

   [ [NOT] FINAL]

[REF IS SYTEM GENERATED |

   REF USING datatype

     [CAST {(SOURCE AS REF) | (REF AS SOURCE) WITH identifier} ] |

   REF new_udt_name [,...] } ]

[CAST {(SOURCE AS DISTINCT) | (DISTINCT AS SOURCE)} WITH identifier]

[method_definition [,...] ]

The syntax below alters an existing user-defined datatype:

ALTER TYPE type_name {ADD ATTRIBUTE type_definition |

   DROP ATTRIBUTE type_name}

Keywords


{CREATE | ALTER} TYPE type_name

Creates a new type or alters an existing type of type_name.


UNDER supertype_name

Creates a subtype that is dependent upon a single, pre-existing, named supertype. (A UDT can be a supertype if it is defined as NOT FINAL.)


AS [new_udt_name] datatype [attribute] [,...]

Defines attributes of the type as if they were column declarations in a CREATE TABLE statement without constraints. You should either define the UDT attribute on an existing datatype, like VARCHAR(10), or on another, previously created UDT or even on a user-defined domain. Defining a UDT using a predefined datatype (e.g., CREATE TYPE my_type AS INT) creates a distinct type, while a UDT defined with an attribute definition is a structured type. The allowable attributes for a structured type are below:


ON DELETE NO ACTION

Produces an error when the foreign key is violated (the default).


ON DELETE RESTRICT

A synonym for NO ACTION.


ON DELETE CASCADE

Sets the value of the referencing column to the value of the referenced column.


ON DELETE SET NULL

Sets the referencing column value to NULL.


ON DELETE SET DEFAULT value

Defines a default value for the UDT when no value is supplied by the user. Follows the rules of a DEFAULT in the CREATE/ALTER TABLE Statement section.


COLLATE collation_name

Assigns a collation - that is, a sort order - for the UDT. When omitted, the collation of the database where the UDT was created applies. Follows the rules of a COLLATION in the CREATE/ALTER TABLE Statement section.


[NOT] INSTANTIABLE

Defines the UDT such that it can be instantiated. INSTANTIABLE is required for typed tables, but not standard UDTs.


[NOT] FINAL

Required for all UDTs. FINAL means the UDT may have no subtypes. NOT FINAL means the UDT may have subtypes.


REF

Defines either a system-generated or user-generated reference specification - that is, a sort of unique identifier that acts as a pointer that another type may reference. By referencing a pre-existing type using its reference specification, new types may inherit properties of pre-existing types. There are three ways to tell the DBMS how the typed table's reference column gets its values (i.e., its reference specification):


new_udt_name [,...]

Declares the reference specification is provided by another pre-existing UDT called new_udt_name.


IS SYTEM GENERATED

Declares the reference specification is system-generated. (Think of an automatically incrementing column.) This is the default when the REF clause is omitted.


USING datatype [CAST {(SOURCE AS REF) | (REF AS SOURCE) WITH identifier]

Declares that the user defines the reference specification. You do this by using a predefined datatype and optionally casting the value. You can CAST (SOURCE AS REF) WITH identifier to cast the value with the specified datatype to the reference type of the structured type. You can CAST (REF AS SOURCE) WITH identifier to cast the value for the structured type to the datatype. The WITH clause allows you to declare an additional identifier for the cast datatype.


CAST {(SOURCE AS DISTINCT) | (DISTINCT AS SOURCE)} WITH identifier method_definition [,...]

Defines one or more pre-existing methods for the UDT. A method is merely a specialized user-defined function and is created using the CREATE METHOD statement (see CREATE FUNCTION). The method_definition clause is not needed for structured types since their method(s) are implicitly created. The default characteristics of a method are LANGUAGE SQL, PARAMETER STYLE SQL, NOT DETERMINISTIC, CONTAINS SQL, and RETURN NULL ON NULL INPUT.


ADD ATTRIBUTE type_definition

Adds an additional attribute to an existing UDT, using the format described earlier under the AS clause. Available via the ALTER TYPE statement.


DROP ATTRIBUTE type_name

Drops an attribute from an existing UDT. Available via the ALTER TYPE statement.

Rules at a Glance

You are able to create user-defined types (UDTs) as a way to further ensure data integrity in your database and to ease the work involved in doing so. An important concept of UDTs is that they allow you to easily create subtypes. Subtypes are UDTs built upon other UDTs (the supertype). Subtypes inherit the characteristics of their supertypes. The UDT that subtypes are dependent on is called a parent type or supertype.

Assume, for example, that you want to define a general UDT for phone numbers called phone_nbr. You could then easily build new subtypes of phone_nbr called home_phone, work_phone, cell_phone, pager_phone, etc. Each of the subtypes could then inherit the general characteristics of the parent type, but then have characteristics of their own. In the following example, we create a general root UDT called money and then several subtypes:

CREATE TYPE money (phone_number DECIMAL (10,2) )

   NOT FINAL;

CREATE TYPE dollar UNDER money AS DECIMAL(10,2)

   (conversion_rate DECIMAL(10,2) ) NOT FINAL;

CREATE TYPE euro   UNDER money AS DECIMAL(10,2)

   (dollar_conversion_rate DECIMAL(10,2) ) NOT FINAL;

CREATE TYPE pound  UNDER euro

   (euro_conversion_rate DECIMAL(10,2) ) FINAL;

Programming Tips and Gotchas

The biggest programming gotcha for user-defined types is that they are simply seldom used or well understood by most database developers and database administrators. Consequently, they can be problematic due to simple ignorance. They offer, however, a consistent and labor-saving approach for representing commonly reused conceptual elements in a database, such as address (e.g., street1, street2, city, state, postal code).

DB2

DB2 supports most elements of the ANSI standard with a few specific enhancements. The CREATE TYPE syntax is:

CREATE [DISTINCT] TYPE type_name

[UNDER supertype_name]

[AS [new_udt_name] datatype

[WITH COMPARISONS]

[[NOT] INSTANTIABLE] [INLINE LENGTH int] [WITHOUT COMPARISONS]

 [NOT FINAL] MODE DB2SQL

[REF USING datatype] [CAST {(SOURCE AS REF) | (REF AS SOURCE)}

  WITH identifier } ]

[[OVERRIDING] METHOD method_definition [,...] ]

The syntax below alters an existing user-defined datatype on DB2:

ALTER TYPE type_name {ADD ATTRIBUTE type_definition |

   DROP ATTRIBUTE type_name [RESTRICT] |

   ADD METHOD method_definition |

   ALTER METHOD method_name [[NOT] FENCED] [[NOT] THREADSAFE] |

   DROP METHOD method_name [RESTRICT] }

The parameters are:


DISTINCT

Defines a distinct type. A distinct type is always sourced from one of the existing datatypes that ships with DB2. CREATE DISTINCT TYPE generates one or more function to cast between the distinct type and its source type.


WITH COMPARISONS

Generates support for the comparison operators (=, <>, <, <=, >, and >=) for use with a distinct type. This clause is used only with CREATE DISTINCT TYPE. Even when creating a distinct type, WITH COMPARISONS should not be used if the source datatype is BLOB, CLOB, DBCLOB, LONG VARCHAR, LONG VARGRAPHIC, or DATALINK.


INLINE LENGTH int

Defines the maximum length in bytes, int, of a structured type column. When omitted, DB2 calculates the maximum length itself.


WITHOUT COMPARISONS

Declares that there are no comparison functions supported for the structure type.


MODE DB2SQL

This is a required clause needed to maintain ANSI compliance.


OVERRIDING

Declares that the method of a subtype overrides a method of the same name on the supertype. This allows easy reimplementation of methods in subtypes.


METHOD method_definition [,...]

DB2 supports a number of SQL routine characteristics and external routine characteristics on the method_definition. In short, you must define a method in the CREATE/ALTER TYPE statement, but then you must also define the implementation of the method using CREATE METHOD. Creating methods are explained in CREATE/ALTER FUNCTION/PROCEDURE Statements.


ADD METHOD method_definition

Adds a new method, method_definition, to the existing type, type_name. However, the method is not usable until a CREATE METHOD statement defines the implementation of the method.


ALTER METHOD method_name

Alters a method, but the method must not be LANGUAGE SQL.


[NOT] FENCED

Declares whether the method is safe to run in the database's operating system process (NOT FENCED) or not (FENCED). NOT FENCED methods can introduce integrity problems when not adequately set up to prevent errors. This clause is incompatible with NOT THREADSAFE.


[NOT] THREADSAFE

Declares whether the method is safe to run in the same process as other routines (THREADSAFE) or not (NOT THREADSAFE).


DROP METHOD method_name

Drops an existing method of method_name.


RESTRICT

Disallows an attribute or method from being dropped when the type, type_name, is used in other existing objects, such as a table, view, column, index extension, etc.

In this example, we create a supertype for employee and a subtype for manager:

CREATE TYPE employee AS

   (last_name VARCHAR(32),

    emp_id    INT,

    dept      REF(dept),

    salary    DECIMAL(10,2))

MODE DB2SQL;

CREATE TYPE manager UNDER emp AS

   (bonus DECIMAL(10,2))

MODE DB2SQL;

The following example shows a more elaborate type hierarchy for addresses:

CREATE TYPE address_type AS

   (street1       VARCHAR(30),

    street2       VARCHAR(30),

    city          VARCHAR(30),

    state         VARCHAR(10),

    locality_code CHAR(15) )

NOT FINAL

MODE DB2SQL

   METHOD SAMEZIP (addr address_type)

   RETURNS INTEGER

   LANGUAGE SQL

   DETERMINISTIC

   CONTAINS SQL

   NO EXTERNAL ACTION

   METHOD DISTANCE (address_type)

   RETURNS FLOAT

   LANGUAGE C

   DETERMINISTIC

   PARAMETER STYLE SQL

   NO SQL

   NO EXTERNAL ACTION

CREATE TYPE spain_address_type UNDER address_type AS

   (family_name VARCHAR(30))

NOT FINAL

MODE DB2SQL

CREATE TYPE usa_address_type UNDER address_type AS

   (zip VARCHAR(10))

NOT FINAL

MODE DB2SQL

In the above example, we created a type called address_type with two subtypes: spain_address_type and usa_address_type.

The example that follows shows how to create a distinct type in DB2 used to identify an employee mailstop.

CREATE DISTINCT TYPE mailstop AS CHAR(5)

WITH COMPARISONS;

In essence, the type mailstop now functions like a regular datatype and may be used to create columns in tables, variables in stored procedures, etc. The WITH COMPARISONS clause tells DB2 to create the standard pre-existing system operators for use with the distinct type. Specific functions, such as AVG, MIN, or LENGTH, may not work unless the CREATE FUNCTION statement is used to register the function for the distinct type.

MySQL

Not supported.

Oracle

Oracle has CREATE TYPE and ALTER TYPE statements, but they are not ANSI standard. Instead of a single CREATE TYPE statement, Oracle uses CREATE TYPE BODY to define the code that makes up the UDT, while CREATE TYPE defines the argument specification for the type. The syntax for CREATE TYPE is:

CREATE [OR REPLACE] TYPE type_name

[AUTHID {DEFINER | CURRENT_USER} ]

{ [ UNDER supertype_name] |

  {AS | IS} [OID 'object_identifier']

  {OBJECT | TABLE OF datatype | VARRAY ( limit ) OF datatype} ] }

       EXTERNAL NAME java_ext_name LANGUAGE JAVA USING data_definition

       { [ (attribute datatype [,...] [EXTERNAL NAME 'name'] |

         [[NOT] OVERRIDING] [[NOT] FINAL] [[NOT] INSTANTIABLE]

            [{ {MEMBER | STATIC}

            {function_based | procedure_based} | constructor_clause |

            map_clause } [...] ]

         [pragma_clause] ] }

Once the type has been declared, you encapsulate all of the UDT logic in the type body declaration. The type_name for both the CREATE TYPE and CREATE TYPE BODY should be identical. The syntax for the type body is shown below:

CREATE [OR REPLACE] TYPE BODY type_name

{AS | IS}

{{MEMBER | STATIC}

{function_based | procedure_based | constructor_clause}}[...]

[map_clause]

Oracle's implementation of ALTER TYPE enables you to drop or add attributes and methods from the type:

ALTER TYPE type_name

  {COMPILE [DEBUG] [{SPECIFICATION | BODY}]

     [compiler_directives] [REUSE SETTINGS] |

   REPLACE [AUTHID {DEFINER | CURRENT_USER}] AS OBJECT

      (attribute datatype [,...] [element_definition [,...] ]  ) |

   [[NOT] OVERRIDING] [[NOT] FINAL] [[NOT] INSTANTIABLE]

  { {ADD | DROP} { {MAP | ORDER} MEMBER FUNCTION function_name

      (parameter datatype [,...]) } |

    { {MEMBER | STATIC} {function_based | procedure_based} |

       constructor_clause | map_clause } [...] |

    {ADD | DROP | MODIFY} ATTRIBUTE (attribute [datatype] [,...] ) |

    MODIFY {LIMIT int | ELEMENT TYPE datatype} }

[ {INVALIDATE |

   CASCADE [{ [NOT] INCLUDING TABLE DATA | CONVERT TO SUBSTITUTABLE}]

      [FORCE] [EXCEPTIONS INTO table_name] } ]

Parameters for the three statements are as follows:


OR REPLACE

Recreates the UDT if it already exists. Objects that depend on the type are marked as DISABLE after you recreate the type.


AUTHID {DEFINER | CURRENT_USER}

Determines what user permissions any member functions or procedures are executed under and how external name references are resolved. (Note that subtypes inherit the permission style of their supertype.) This clause can only be used with an OBJECT type, not with a VARRAY type or nested table type, according to the following keywords:


DEFINER

Executes functions or procedures under the privileges of the user who created the UDT. Also specifies that unqualified object names (object names without a schema definition) in SQL statements are resolved to the schema where the member functions or procedures reside.


CURRENT_USER

Executes functions or procedures under the privileges of the user who invoked the UDT. Also specifies that unqualified object names in SQL statements are resolved to the schema of the user who invoked the UDT.


UNDER supertype_name

Declares that the UDT is a subtype of another, pre-existing UDT. The supertype UDT must be created with the AS OBJECT clause. A subtype will inherit the properties of the supertype, though you should override or add new properties to differentiate it from the supertype.


OID 'object_identifier'

Declares an equivalent identical object, of name 'object_identifier', in more than one database. This clause is most commonly used by those developing Oracle Data Cartridges and is seldom used in standard SQL statement development.


AS OBJECT

Creates the UDT as a root object type, the top level object in a UDT hierarchy of objects.


AS TABLE OF datatype

Creates a named nested table type of a UDT called datatype. The datatype cannot be an NCLOB, but CLOB or BLOB are acceptable. If the datatype is an object type, then the columns of the nested table must match the name and attributes of the object type.


AS VARRAY ( limit ) OF datatype

Creates the UDT as an ordered set of elements, all of the same datatype. The limit is an integer of zero or more. The type name must be a built-in datatype, a REF, or an object type. The VARRAY cannot contain LOB or XMLType datatypes.


EXTERNAL NAME java_ext_name LANGUAGE JAVA USING data_definition

Maps a Java class to a SQL UDT by specifying the name of a public Java external class, java_ext_name. Once defined, all objects in a Java class must be Java objects. The data_definition may be SQLData, CustomDatum, or OraData as defined in the "Oracle9i JDBC Developers Guide." You can map many Java object types to the same class, but there are two restrictions. First, do not map to the same class two or more subtypes of a common datatype. Second, subtypes must be mapped to an immediate subclass of the class that their supertype is mapped to.


datatype

Declares the attributes and datatypes used by the UDT. Oracle does not allow ROWID, LONG, LONG ROW, or UROWID. Nested tables and varrays do not allow attributes of AnyType, AnyData, or AnyDataSet.


EXTERNAL NAME 'name' [NOT] OVERRIDING

Declares that this method overrides a MEMBER method defined in the supertype (OVERRIDING) or not (NOT OVERRIDING), the default. This clause is valid only for MEMBER clauses.


MEMBER | STATIC

Describes the way in which subprograms are associated with the UDT as attributes. MEMBER has an implicit first argument referenced as SELF, as in object_expression.method( ). STATIC has no implicit arguments, as in type_name.method( ). The following basis are allowed to call subprograms:


function_based

Declares a subprogram that is function-based using the syntax:


FUNCTION function_name ( parameter datatype [,...] )

 


return_clause |java_object_clause}

The function_name cannot be the name of any existing attribute, include those inherited from supertypes. This clause allows you to define the PL/SQL function-based UDT body without resorting to the CREATE TYPE BODY statement. The return_clause and java_object_clause are defined in the following text.


procedure_based

Declares a subprogram that is function-based using the syntax:

PROCEDURE procedure_name (parameter datatype [,...] ) 

{AS | IS} LANGUAGE {java_call_spec | c_call_spec}

Refer to the entry on java and c_call_spec later in this list. This clause allows you to define the PL/SQL procedure-based UDT body without resorting to the CREATE TYPE BODY statement. The procedure_name cannot be the name of any existing attribute, include those inherited from supertypes.


constructor_clause

Declares one or more constructor specifications using the syntax:

[FINAL] [INSTANTIABLE] CONSTRUCTOR FUNCTION datatype 

   [ ( [SELF IN OUT datatype ,] {parameter datatype [,...] ) ] 

RETURN SELF AS RESULT 

   [ {AS | IS} LANGUAGE {java_call_spec | c_call_spec}

A constructor specification is a function that returns an initialized instance of a UDT. Constructor specifications are always FINAL, INSTANTIABLE, and SELF IN OUT, so these keywords are not required. The java_call_spec and c_call_spec subclauses may be replaced with a PL/SQL code block in the CREATE TYPE BODY statement. (Refer to the entries on java_call_spec and c_call_spec later in this list.)


map_clause

Declares the mapping or ordering of a supertype using the syntax:

{MAP | ORDER} MEMBER function_based

Refer to the entry on function_based earlier in this list. MAP uses more efficient algorithms for object comparison and is best in situations when performing extensive sorting or hash joins. MAP MEMBER specifies the relative position of a given instance in the ordering of all instances of the UDT. ORDER MEMBER specifies the explicit position of an instance and references a function_based subprogram that returns a NUMBER datatype value.


return_clause

Declares the datatype return format of the SQL UDT using the syntax:

 RETURN datatype [ {AS | IS} LANGUAGE {java_call_spec | 

      c_call_spec}.


java_object_clause

Declares the return format of the Java UDT using the syntax:

RETURN {datatype | SELF AS RESULT} EXTERNAL [VARIABLE] NAME 

     'java_name'

If you use the EXTERNAL clause, the value of the public Java method must be compatible with the SQL returned value.


pragma_clause

Declares a pragma restriction (that is, an Oracle precompiler directive) for the type using the syntax:

PRAGMA RESTRICT REFERENCES ( {DEFAULT | method_name} , 

{RNDS | WNDS |RNPS | WNPS | TRUST}[,...] )

This feature is deprecated and should be avoided. It is intended to control how UDTs read and write database tables and variables. The parameters in the PRAGMA syntax are:


DEFAULT

Applies the pragma to all methods in the type that don't have another pragma in place.


method_name

Identifies the exact method to which to apply the pragma.


RNDS

Reads no database state - no database reads allowed.


WNDS

Writes no database state - no database writes allowed.


RNPS

Reads no package state - no package reads allowed.


WNPS

Writes no package state - no package writes allowed.


TRUST

States that the restrictions of the pragma are assumed but not enforced.


java_call_spec

Identifies the Java implementation of a method using the syntax JAVA NAME 'string'. This clause allows you to define the Java UDT body without resorting to the CREATE TYPE BODY statement.


c_call_spec

Declares a C language call specification using the syntax:

C [NAME name] LIBRARY lib_name [AGENT IN (argument) ] 

[WITH CONTEXT] [PARAMETERS (parameter [,...] ]

This clause allows you to define the C UDT body without resorting to the CREATE TYPE BODY statement.


COMPILE

Compiles the object type specification and body. This is the default when neither a SPECIFICATION clause nor a BODY clause are defined.


compiler_directives

Defines a special value for the PL/SQL compiler in the format: directive = 'value'. The directives are: PLSQL_OPTIMIZE_LEVEL, PLSQL_CODE_TYPE, PLSQL_DEBUG, PLSQL_WARNINGS, and NLS_LENGTH_SEMANTICS. They may each specify a value once in the statement. The directive is valid only for the unit being compiled.


DEBUG

Generates and stores additional codes for the PL/SQL debugger. Do not specify both DEBUG and the compiler_directive PLSQL_DEBUG.


SPECIFICATION | BODY

Chooses whether to recompile the SPECIFICATION of the object type (created by the CREATE TYPE statement) or the BODY (created by the CREATE TYPE BODY statement).


compiler_directives

Defines a special value for the PL/SQL compiler in the format: directive = 'value'. The directives are: PLSQL_OPTIMIZE_LEVEL, PLSQL_CODE_TYPE, PLSQL_DEBUG, PLSQL_WARNINGS, and NLS_LENGTH_SEMANTICS. They may each specify a value once in the statement. The directive is valid only for the unit being compiled.


REUSE SETTINGS

Retains the original value for the compiler_directives mentioned earlier.


REPLACE AS OBJECT

Adds new member subtypes to the specification. This clause is valid only for object types.


[NOT] OVERRIDING

Indicates the method overrides a MEMBER method defined in the supertype. This clause is only valid with MEMBER methods and is required for methods that define (or redefine using ALTER) a supertype method. NOT OVERRIDING is the default if this clause is omitted.


ADD

Adds a new MEMBER function, function- or procedure-based subprogram, or attribute to the UDT.


DROP

Drops an existing MEMBER function, function- or procedure-based subprogram, or attribute from the UDT.


MODIFY

Alters the properties of an existing attribute of the UDT.


MODIFY LIMIT int

Increases the number of elements in a VARRAY collection type up to int, as long as int is greater than the current number of elements in the VARRAY. It is not valid for nested tables.


MODIFY ELEMENT TYPE datatype

Increases the precision, size, or length of a scalar datatype of a VARRAY or nested table. This clause is valid for any non-object collection type. If the collection is a NUMBER, you may increase its precision or scale. If the collection is RAW, you may increase its maximum size. If the collection is VARCHAR2 or NVARCHAR2, you may increase its maximum length.


INVALIDATE

Invalidates all dependent objects without checks.


CASCADE

Cascades the change to all subtypes and tables. By default, the action will be rolled back if any errors are encountered in the dependent types or tables.


[NOT] INCLUDING TABLE DATA

Converts data stored in the UDT columns to the most recent version of the column's type (INCLUDING TABLE DATA), the default, or not (NOT INCLUDING TABLE DATA). When NOT, Oracle checks the metadata, but does not check or update the dependent table data.


CONVERT TO SUBSTITUTABLE

Used when changing a type from FINAL to NOT FINAL. The altered type then can be used in substitutable tables and columns, as well as in subtypes, instances of dependent tables, and columns.


FORCE

Causes the CASCADE operation to go forward, ignoring any errors found in dependent subtypes and tables. All errors are logged to a previously created EXCEPTIONS table.


EXCEPTIONS INTO table_name

Logs all error data to a table previously created using the system package called DBMS_UTILITY.CREATE_ALTER_TYPE_ERROR_TABLE.

In this example, we create a Java SQLJ object type called address_type:

CREATE TYPE address_type AS OBJECT

   EXTERNAL NAME 'scott.address' LANGUAGE JAVA

   USING SQLDATA ( street1 VARCHAR(30) EXTERNAL NAME 'str1',

      street2              VARCHAR(30) EXTERNAL NAME 'str2',

      city                 VARCHAR(30) EXTERNAL NAME 'city',

      state                CHAR(2)     EXTERNAL NAME 'st',

      locality_code        CHAR(15)    EXTERNAL NAME 'lc',

      STATIC FUNCTION square_feet RETURN NUMBER

         EXTERNAL VARIABLE NAME 'square_feet',

      STATIC FUNCTION create_addr (str VARCHAR,

         City VARCHAR, state VARCHAR, zip NUMBER)

         RETURN address_type

         EXTERNAL NAME 'create (java.lang.String,

            java.lang.String, java.lang.String, int)

            return scott.address',

      MEMBER FUNCTION rtrims RETURN SELF AS RESULT

         EXTERNAL NAME 'rtrim_spaces ( ) return scott.address' )

NOT FINAL;

We could create a UDT using a VARRAY type with four elements:

CREATE TYPE employee_phone_numbers AS VARRAY(4) OF CHAR(14);

In the following example, we alter the address_type that we created earlier by adding a VARRAY called phone_varray:

ALTER TYPE address_type

   ADD ATTRIBUTE (phone phone_varray) CASCADE;

In this last example, we'll create a supertype and subtype called menu_item_type and entry_type, respectively:

CREATE OR REPLACE TYPE menu_item_type AS OBJECT

(id INTEGER, title VARCHAR2(500),

   NOT INSTANTIABLE

   MEMBER FUNCTION fresh_today

   RETURN BOOLEAN)

NOT INSTANTIABLE

NOT FINAL;

In the above example, we created a type specification (but not the type body) that defines items that may appear on a menu at a café. Included with the type specification is a subprogram method called fresh_today, a Boolean indicator that tells whether the menu item is made fresh that day. The NOT FINAL clause that appears at the end of the code tells Oracle that this type may serve as the supertype (or base type) to other subtypes that we might derive from it. So now, let's create the entre_type:

CREATE OR REPLACE TYPE entry_type UNDER menu_item_type

(entre_id INTEGER, desc_of_entre VARCHAR2(500),

   OVERRIDING MEMBER FUNCTIOIN fresh_today

   RETURN BOOLEAN)

NOT FINAL;

PostgreSQL

PostgreSQL supports a CREATE TYPE statement used to create a new datatype, but does not support an ALTER TYPE statement. PostgreSQL's implementation of the CREATE TYPE statement is nonstandard:

CREATE TYPE type_name

  ( INPUT = input_function_name,

    OUTPUT = output_function_name,

    INTERNALLENGTH = { int | VARIABLE }

[, DEFAULT = value]

[, ELEMENT = array_element_datatype ]

[, DELIMITER = delimiter_character ]

 [, PASSEDBYVALUE ]

[, ALIGNMENT = {CHAR | INT2 | INT4 | DOUBLE} ]

[, STORAGE = {PLAIN | EXTERNAL | EXTENDED | MAIN} ] )

The parameters are as follows:


CREATE TYPE type_name

Creates a new user-defined datatype called type_name. The name may not exceed 30 characters in length nor begin with an underscore.


INPUT = input_function_name

Declares the name of a previously created function that converts external argument values into a form usable by the type's internal form.


OUTPUT = output_function_name

Declares the name of a previously created function that converts internal output values to a display format.


INTERNALLENGTH = { int | VARIABLE }

Specifies a numeric value, int, for the internal length of the new type, if the datatype is fixed length. The keyword VARIABLE declares that the internal length is variable. The default is VARIABLE.


DEFAULT = value

Defines a value for type when it defaults.


ELEMENT = array_element_datatype

Declares that the datatype is an array and that array_element_datatype is the datatype of the array elements. For example, an array containing integer values would be ELEMENT = INT4. In general, you should allow the array_element_datatype value to default. The only time you might want to override the default is when creating a fixed-length UDT composed of an array of multiple identical elements that need to be directly accessible by subscripting.


DELIMITER = delimiter_character

Declares a character used as a delimiter between output values of an array produced by the type. Only used with the ELEMENT clause. The default is a comma.


PASSEDBYVALUE

Specifies that the values of the datatype are passed by value and not by reference. The optional clause cannot be used for types whose value is longer than the DATUM datatype (4 bytes on most operating systems, 8 bytes on a few others).


ALIGNMENT = {CHAR | INT2 | INT4 | DOUBLE}

Defines a storage alignment for the type. Four datatypes are allowed, with each one equating to a specific boundary. CHAR equals a 1-byte boundary. INT2 equals a 2-byte boundary. INT4 equals a 4-byte boundary (the requirement for a variable-length UDT on PostgreSQL). DOUBLE equals an 8-byte boundary.


STORAGE = {PLAIN | EXTERNAL | EXTENDED | MAIN}

Defines a storage technique for variable-length UDTs. (PLAIN is required for fixed-length UDTs.) Four types are allowed:


PLAIN

Stores the UDT in-line, when declared as the datatype of a column in a table, and uncompressed.


EXTERNAL

Stores the UDT outside of the table without trying to compress it first.


EXTENDED

Stores the UDT as a compressed value if it fits inside of the table. If it is still too long, PostgreSQL will save the UDT outside of the table.


MAIN

Stores the UDT as a compressed value within the table. There are situations where PostgreSQL cannot save the UDT within the table because it is just too large. The MAIN storage parameter puts the highest emphasis on storing UDTs with all other table data.

When you create a new datatype in PostgreSQL, it is available only in the current database. The user who created the datatype is the owner.

In order to create a new datatype, you must create at least two functions before defining the type (see CREATE/ALTER FUNCTION/PROCEDURE Statements"). In summary, you must create an INPUT function that provides the type with external values that can be used by the operators and functions defined for the type. You must also create an OUTPUT function that renders a usable external representation of the datatype. There are some additional requirements when creating the input and output functions:

  • The input function should either take one argument of type OPAQUE or take three arguments of OPAQUE, OID, and INT4. In the latter case, OPAQUE is the input text of a C string, OID is the element type for array types, and the INT4 (if known) is the typemod of the destination column.

  • The output function should either take one argument of type OPAQUE or take two arguments of OPAQUE and OID. In the latter case, OPAQUE is the datatype itself and the OID is the element type for array types, if needed.

For example, we can create a UDT called floorplan and use it to define a column in two tables, one called house and one called condo:

CREATE TYPE floorplan

   (INTERNALLENGTH=12, INPUT=squarefoot_calc_proc,

   OUTPUT=out_floorplan_proc);

CREATE TABLE house

   (house_plan_id        int4,

    size              floorplan,

    descrip        varchar(30) );

CREATE TABLE condo

   (condo_plan_id        INT4,

    size              floorplan,

    descrip        varchar(30)

    location_id   varchar(7) );

SQL Server

Not supported. New datatypes can be added to SQL Server using the non-ANSI system stored procedure sp_addtype.

See Also

CREATE/ALTER FUNCTION/PROCEDURE
DROP
CREATE/ALTER VIEW Statement

This statement creates a view, also known as a virtual table. A view acts just like a table but is actually defined as a query. When a view is referenced in a statement, the result set of the query becomes the content of the view for the duration of that statement. Almost any valid SELECT statement can define the contents of a view, though some platforms restrict the certain clauses of the SELECT statement and certain set operators.

In some cases, views can be updated, causing the view changes to be translated to the underlying data in the base tables. Some database platforms support a materialized view; that is, a physically created table that is defined with a query just like a view.

ALTER VIEW is not an ANSI-supported statement.


Platform

Command

DB2

Supported, with variations

MySQL

Not supported

Oracle

Supported, with variations

PostgreSQL

Supported, with variations

SQL Server

Supported, with variations


SQL2003 Syntax

CREATE [RECURSIVE] VIEW view_name {[(column [,...])] |

[OF udt_name [UNDER supertype_name

   [REF IS column_name {SYSTEM GENERATED | USER GENERATED | DERIVED} ]

   [column_name WITH OPTIONS SCOPE table_name] ] }

AS

select_statement [WITH [CASCADED | LOCAL] CHECK OPTION]

Keywords


CREATE VIEW view_name

Creates a new view using the supplied name.


RECURSIVE

Creates a view that derives values from itself. It must have a column clause and may not use the WITH clause.


[(column [,...])]

Names all of the columns in the view. The number of columns declared here must match the number of columns generated by the select_statement. When omitted, the columns assume the names of the columns that they come from. This clause is required when one or more of the columns is derived and does not have a base table column to reference.


OF udt_name [UNDER supertype_name]

Defines the view on a UDT rather than on the column clause. The typed view is created using each attribute of the type as a column in the view. Use the UNDER clause to define a view on a subtype.


REF IS column_name {SYSTEM GENERATED | USER GENERATED | DERIVED}

Defines the object-ID column for the view.


column_name WITH OPTIONS SCOPE table_name

Provides scoping for a reference column in the view. (Since the columns are derived from the type, there is no column list. Therefore, to specify column options, you must use "column_name WITH OPTIONS...".)


AS select_statement

Defines the exact SELECT statement that provides the data of the view.


[WITH [CASCADED | LOCAL] CHECK OPTION]

Used only on views that allow updates to their base table. It ensures that only data that may be read by the view may be inserted, updated, or deleted by the view. For example, if a view of employees showed salaried employees but not hourly employees, it would be impossible to insert, update, or delete hourly employees through that view. The CASCADED and LOCAL options of the CHECK OPTION clause are used for nested views. CASCADED performs the check option for the current view and all views it is built on top of. LOCAL performs the check option only for the current view, even when it is built upon other views.

Rules at a Glance

Views are usually as effective as the queries upon which they are based. That is why it is important to be sure that the defining SELECT statement is speedy and well-written. The simplest view is based on the entire contents of a single table:

CREATE VIEW employees

AS

SELECT *

FROM employee_tbl;

A column list also may be specified after the view name. The optional column list contains aliases serving as names for each element in the result set of the SELECT statement. If you use a column list, then you must provide a name for every column returned by the SELECT statement. If you don't use a column list, then the columns of the view will be named whatever the columns in the SELECT statement are called. You will sometimes see complex SELECT statements within a view that make heavy use of AS clauses for all columns, because that allows the developer of the view to put meaningful names on the columns without including a column list.

The ANSI standard defines that you must use a column list or an AS clause. However, some vendors allow more flexibility, so follow these rules for when to use an AS clause:

  • When the SELECT statement contains calculated columns, such as (salary * 1.04)

  • When the SELECT statement contains fully qualified column names, such as pubs.scott.employee

  • When the SELECT statement contains more than one column of the same name (though with separate schema or database prefixes)

For example, the following two view declarations have the same functional result:

-- using a column-list

CREATE VIEW title_and_authors

   (title, author_order, author, price, avg_monthly_sales,

   publisher)

AS

SELECT t.title, ta.au_ord, a.au_lname, t.price, (t.ytd_sales / 12),

   t.pub_id

FROM authors AS a

JOIN titleauthor AS ta ON a.au_id = ta.au_id

JOIN titles AS t ON t.title_id = ta.title_id

WHERE t.advance > 0;

-- using the AS clause with each column

CREATE VIEW title_and_authors

AS

SELECT t.title AS title, ta.au_ord AS author_order,

   a.au_lname AS author, t.price AS price,

   (t.ytd_sales / 12) AS avg_monthly_sales, t.pub_id AS publisher

FROM authors AS a

JOIN titleauthor AS ta ON a.au_id = ta.au_id

JOIN titles AS t ON t.title_id = ta.title_id

WHERE t.advance > 0

You can alternately change the title of columns using the column list. In this case, we'll change avg_monthly_sales to avg_sales. Note that the code overrides the default column names provided by the AS clauses (in bold):

CREATE VIEW title_and_authors

   (title, author_order, author, price, avg_sales, publisher)

AS

SELECT t.title AS title, ta.au_ord AS author_order,

   a.au_lname AS author, t.price AS price,

   (t.ytd_sales / 12) AS avg_monthly_sales, t.pub_id AS publisher

FROM authors AS a

JOIN titleauthor AS ta ON a.au_id = ta.au_id

JOIN titles AS t ON t.title_id = ta.title_id

WHERE t.advance > 0;

ANSI standard view can update the base table(s) it is based upon if it meets the following conditions:

  • The view does not have UNION, EXCEPT, or INTERSECT operators.

  • The defining SELECT statement does not contain GROUP BY or HAVING clauses.

  • The defining SELECT statement does not contain any reference to non-ANSI pseudo-columns such as ROWNUM or ROWGUIDCOL.

  • The defining SELECT statement does not contain the DISTINCT clause.

  • The view is not materialized.

This example shows a view named california_authors that allows data modifications to apply only to authors within the state of California:

CREATE VIEW california_authors

AS

SELECT au_lname, au_fname, city, state

FROM authors

WHERE state = 'CA'

WITH LOCAL CHECK OPTION

The view shown in this example would accept INSERT, DELETE, and UPDATE statements against the base table, but still maintain that all inserted, updated, or deleted records contain a state of 'CA' using the WITH ... CHECK clause.

The most important rule to remember when updating a base table through a view is that all columns in a table that are defined as NOT NULL must receive a not null value when receiving a new or changed value. You can do this explicitly by directly inserting or updating a not null value into the column or by relying on a default value. In addition, views do not lift constraints on the base table. Thus, the values being inserted or updated into the base table must meet all the constraints placed on it by unique indexes, primary keys, CHECK constraints, etc.

Programming Tips and Gotchas

Views also can be built upon other views, but this is inadvisable and usually considered bad practice. Depending on the platform, such a view may take longer to compile, but may offer the same performance as a transaction against the base table(s). On other platforms, where each view is dynamically created as it is invoked, nested views may take a long time to return a result set because each level of nesting means another query must be processed before a result set is returned to the user. So in this worst case scenario, a three-level nested view must make three correlated query calls before it can return results to the user.

Although materialized views are defined like views, they take up space more like tables. Ensure that you have enough space available for the creation of materialized views.

DB2

DB2 supports a number of extensions to the ANSI standard CREATE VIEW statement:

CREATE VIEW view_name

{ [ (column [,...]) ] | [OF type_name MODE DB2SQL

      { (REF IS objectid_column_name USER GENERATED

            [UNCHECKED] [, with_options] ) |

         UNDER parent_view_name INHERIT SELECT PRIVILEGES

       [ (with_options) ] }

AS

[WITH common_table_expression [, ...] ]

(select_statement)

[WITH {CASCADE | LOCAL} CHECK OPTION]

The ALTER VIEW syntax is:

ALTER VIEW view_name

ALTER [COLUMN] column_name ADD SCOPE type_name

Parameters for both statements are as follows:


OF type_name MODE DB2SQL

Declares that the columns of the view are derived from attributes of a structured type called type_name. MODE DB2SQL indicates the type is DB2's version of a typed view.


REF IS objectid_column_name USER GENERATED

Declares that the object identifier column appears as the first column in the view. That first column in the SELECT clause of the view must be a REF type. In this case, the objectID is required on the topmost (i.e., root) view of a view hierarchy. The root view must be a typed view containing the OF clause that is not a subview. The USER GENERATED clause specifies that the first value of the objectID must be provided by the user. From then on, the value is maintained by the system.


UNCHECKED

Declares that the user is certain that all values in first column of the SELECT clause are unique and are not null. Uniqueness may be enforced by a primary key, unique key, unique index, OID-column definition, or an external method. This setting is usually optional, but is required for views in a typed hierarchy.


UNDER parent_view_name INHERIT SELECT PRIVILEGES

Declares that the view is a subview of the previously declared view parent_view_name. The child and parent views must be in the same schema. The parent view must have been declared with the REF clause and must be sourced from a structured type. The parent view named cannot have any subviews of the same structured type as the view being created. The INHERIT SELECT PRIVILEGES clause entitles any user or role with SELECT privileges on the parent view to also have SELECT privileges on all subviews.


with_options

Declares additional options for specific columns of the view. Multiple options are allowed by placing a comma between each option. The full syntax of the with_options clause is:

{column_name WITH OPTIONS {READ ONLY | SCOPE typed_name} [,...] }      [,...]

The parameters are:


READ ONLY

Specifies that a column is read-only.


SCOPE type_name

Specifies the scope of a reference type column where type_name is the name of the typed table or view. A scope is required for any column serving as the left operand of a dereference operator or as the argument of the DEREF function.


WITH common_table_expression

Associates a common table expression with the SELECT statement of the view. This clause is incompatible with typed views.


WITH {CASCADE | LOCAL} CHECK OPTION

Declares that any rows inserted or updated through the view must conform to the definition of the view. Any row that couldn't also be returned by the view cannot, therefore, be inserted or updated through it. When omitted, no checking of inserted or updated data is done beyond the constraints that exist on the source table. WITH CHECK OPTION is not allowed for read-only views, views with an INSTEAD OF trigger, or views that reference a nicknamed source, NODENUMBER or PARTITION functions, non-deterministic functions, or functions with external actions. The following WITH CHECK OPTION options are available:


CASCADE

Causes the search conditions of the current view to inherit the search conditions of any updateable view that the current view is based on. With this option, the current view has its own WHERE clause implicitly appended with an AND keyword to the WHERE clause of the view it depends on.


LOCAL

Applies the search conditions of the current view to any views that depend on it.


ALTER [COLUMN] column_name ADD SCOPE type_name

Allows you to add scope characteristics to an existing view.

The SELECT statement of a view should be a standard SELECT statement and cannot contain any of the following:

  • Temporary tables

  • Parameter markers

  • Referenced host variables

You can get around the limitation on parameterized views by making a user-defined function based on a SQL table.

A typed view or subview must follow some specific rules:

  • The SELECT statement of the view cannot reference DBPARTITIONNUM or HASHEDVALUE functions, functions with external actions, or any non-deterministic function.

  • The view can contain a single SELECT statement. More SELECT statements can be added by using a UNION ALL clause between each one. (DB2 refers to a query with multiple SELECT statements as having multiple branches.)

  • Branches should not cross hierarchies.

  • Branches of a typed view should not contain GROUP BY or HAVING clauses.

  • The root view should contain the UNCHECKED clause if it contains branches.

The following is an example including types, a typed table, and a view hierarchy, built around people_type and emp_type:

CREATE TYPE people_type

  AS (name VARCHAR(20), address VARCHAR(100))

  MODE DB2SQL

  CAST (SOURCE AS REF) WITH people_func;

CREATE TYPE emp_type

  UNDER people_type

  AS (title VARCHAR(20), salary DECIMAL(8,2))

  MODE DB2SQL

  CAST (SOURCE AS REF) WITH emp_func;

CREATE TABLE people

  OF people_type

  (REF IS people_oid USER GENERATED);

INSERT INTO people (people_oid, name, address)

  VALUES (people_func('0'), 'Sammy', '123 Lane');

CREATE TABLE emp

  OF emp_type

  UNDER people INHERIT SELECT PRIVILEGES;

INSERT INTO emp (people_oid, name, address, title, salary)

  VALUES (emp_func('1'), 'Josh', '123 Street', 'Director', 1000);

CREATE VIEW people_view

  OF people_type

  MODE DB2SQL

  (REF IS people_view_oid USER GENERATED)

  AS SELECT people_func (VARCHAR(people_oid)), name, address

    FROM ONLY (people);

CREATE VIEW emp_view

  OF emp_type

  MODE DB2SQL

  UNDER people_view INHERIT SELECT PRIVILEGES

  AS SELECT emp_func (VARCHAR(people_oid)), name,

      address, title, salary

        FROM emp;

SELECT *

  FROM people_view;

PEOPLE_VIEW_OID  NAME   ADDRESS

---------------  -----  ---------------

x'30'            Sammy  123 Lane

x'31'            Josh   123 Street

SELECT *

  FROM emp_view;

PEOPLE_VIEW_OID  NAME  ADDRESS           TITLE                     SALARY

---------------  ----  ----------------  --------------------  ----------

x'31'            Josh  123 Street        Director                 1000.00

The WITH CHECK OPTION clause can be tricky because you are, in effect, telling the views to combine WHERE clauses either from upward in the dependency chain (via CASCADE) or downward in the dependency chain (via LOCAL). Consider the following:

V1 sourced from table T
V2 sourced from V1 WITH check_opn CHECK OPTION
V3 sourced from V2
V4 sourced from V3 WITH check_opn CHECK OPTION
V5 sourced from V4

The following table shows the search conditions against which inserted or updated rows are checked.

Note that if you create a view (or any other object, for that matter) with a schema name that does not already exist in the database, DB2 will implicitly create a schema of that name.


MySQL

Not supported.

Oracle

Oracle supports extensions to the ANSI standard to create object-oriented views, XMLType views, and views that support LOB and object types:

CREATE [OR REPLACE] [ [NO] FORCE] VIEW view_name

   {[(column [,...]) [constraint_clause] |

    [OF type_name {UNDER parent_view |

       WITH OBJECT IDENTIFIER {DEFAULT | (attribute [,...] ) }

       [(constraint_clause)] ] |

    [OF XMLTYPE [ [XMLSCHEMA xml_schema_url] ELEMENT

       {element | xml_schema_url # element} ]

       WITH OBJECT IDENTIFIER {DEFAULT | (attribute [,...]} ]

AS

(select statement)

[WITH [READ ONLY | CHECK OPTION [CONSTRAINT constraint_name] ] ]

Oracle's implementation of the ALTER VIEW statement supports added capabilities, such as adding, dropping, or modifying constraints associated with the view. In addition, the ALTER VIEW statement will explicitly recompile a view that is invalid, enabling you to locate recompile errors before runtime. This recompiling feature enables you to determine if a change in a base table negatively impacts any dependent views:

ALTER VIEW view_name

  {ADD constraint_clause |

   MODIFY CONSTRAINT constraint_clause [NO]RELY] |

   DROP {PRIMARY KEY | CONSTRAINT constraint_clause |

      UNIQUE (column [,...])} }

COMPILE

The parameters are:


OR REPLACE

Replaces any existing view of the same view_name with the new view.


[NO] FORCE

The FORCE clause creates the view regardless of whether the base tables exist or the user creating the view has privileges to the base tables, views, or functions defined in the view. The FORCE clause also creates the view regardless of errors that occur during view creation. The NO FORCE clause creates the view only if the base tables and proper privileges are in place.


constraint_clause

Allows you to specify constraints (see CREATE TABLE) on views for CREATE VIEW. Using ALTER VIEW, this clause also allows you to affect a named, pre-existing constraint. You can define the constraint at the view level, similar to a table-level view, or at the column or attribute level. Note that although Oracle allows you to define constraints on a view, it doesn't yet enforce them. Oracle supports constraints on a view in DISABLE and NOVALIDATE modes.


OF type_name

Declares that the view is an object view of type_name. The columns of the view correspond directly to the attributes returned by type_name, where type_name is a previously declared type (see CREATE TYPE). You do not specify column names for object and XMLType views.


UNDER parent_view

Specifies a subview based on a pre-existing parent_view. The subview must be in the same schema as the parent view, the type_name must be an immediate subtype of the parent_view, and one subview is allowed.


WITH OBJECT IDENTIFIER {DEFAULT | ( attribute [,...] ) }

Defines the root object view as well as any attribute of the object type used to identify each row of the object view. The attributes usually correspond to the primary key columns of the base table and must uniquely identify each row of the view. This clause is incompatible with subviews and dereferenced or pinned REF keys. The DEFAULT keyword uses the implicit object identifier of the base object table or view.


OF XMLTYPE [ [XMLSCHEMA xml_schema_url] ELEMENT {element | xml_schema_url # element ] WITH OBJECT IDENTIFIER (attribute [,...] )

Specifies that the view will return XMLType instances. Specifying the optional xml_schema_url as a pre-registered XMLSchema and element name further constrains the returned XML as an element in that XMLSchema. The WITH OBJECT IDENTIFIER clause specifies the identifier that uniquely identifies each row of the XMLType view. One or more attributes may use non-aggregate functions like extractValue( ) to obtain the identifiers from the resultant XMLType.


WITH READ ONLY

Ensures the view is used only to retrieve data and not to modify it.


WITH CHECK OPTION [CONSTRAINT constraint_name]

Forces the view to accept only inserted and updated data that can be returned by the view's SELECT statement. Alternately, you can specify a single CHECK OPTION constraint_name that exists on the base table that you want to enforce. If the constraint is not named, Oracle names the constraint SYS_Cn, where n is an integer.


ADD constraint_clause

Adds a new constraint to the view. Oracle supports constraints only in DISABLE and NOVALIDATE mode.


MODIFY CONSTRAINT constraint_clause [NO]RELY

Changes the RELY or NORELY setting of an existing view constraint. (RELY and NORELY are explained under CREATE TABLE.)


DROP {PRIMARY KEY | CONSTRAINT constraint_clause | UNIQUE (column [,...])}

Drops an existing constraint on a view.


COMPILE

Recompiles the view.

Any dblinks in the view's SELECT statement must be declared using the CREATE DATABASE LINK...CONNECT TO statement. Views containing flashback queries will have their AS OF clause evaluated at each invocation of the view, not when the view is compiled.

In this example, we create a view that has an added constraint:

CREATE VIEW california_authors (last_name, first_name,

   author_ID UNIQU RELY DISABLE NOVALIDATE,

   CONSTAINT id_pk PRIMARY KEY (au_id) RELY DISABLE NOVALIDATE)

AS

SELECT au_lname, au_fname, au_id

FROM authors

WHERE state = 'CA';

We might also wish to create an object view on an Oracle database and schema. This example creates the type and the object view:

CREATE TYPE inventory_type AS OBJECT

( title_id NUM(6),

  warehouse wrhs_typ,

  qty NUM(8) );

CREATE VIEW inventories OF inventory_type

WITH OBJECT IDENTIFIER (title_id)

AS

SELECT i.title_id, wrhs_typ(w.wrhs_id, w.wrhs_name,

   w.location_id), i.qty

FROM inventories i

JOIN warehouses w ON i.wrhs_id = w.wrhs_id;

You could recompile the inventory_type view like this:

ALTER VIEW inventory_type COMPILE:

An updateable view in Oracle cannot contain any of the following:

  • The DISTINCT clause

  • UNION, INTERSECT, or MINUS

  • Joins that cause inserted or updated data to affect more than one table

  • Aggregate or analytic functions

  • GROUP BY, ORDER BY, CONNECT BY, or START WITH clauses

  • Subqueries or collection expressions in the SELECT item list (Subqueries are acceptable in the SELECT statement's WHERE clause.)

  • Update pseudocolumns or expressions

There are some restrictions on how subviews and materialized views can be defined in Oracle:

  • The subview must use aliases for ROWID, ROWNUM, or LEVEL pseudocolumns.

  • The subview cannot query CURRVAL or NEXTVAL pseudocolumns.

  • The subview cannot contain the SAMPLE clause.

  • The subview evaluates all columns of a SELECT * FROM... statement at compile time. Thus, any new columns added to the base table will not be retrieved by the subview until the view is recompiled.

Note that older versions of Oracle supported partitioned views. This feature has been deprecated. You should use explicitly declared partitions instead.

PostgreSQL

PostgreSQL supports a no-frills subset of the ANSI standard:

CREATE VIEW view_name [ (column [,...] ) ]

AS select_statement

PostgreSQL's CREATE VIEW does not support some of the more complex options that other vendors do. However, it does allow views to be built on tables and other defined class objects. PostgreSQL views are built only upon other tables, not upon other views. PostgreSQL views are always read-only and cannot be used to perform data modifications on the underlying base tables.

SQL Server

SQL Server supports some extensions to the ANSI standard, but does not offer object views or subviews:

CREATE VIEW view_name [(column [,...])]

[WITH {ENCRYPTION | SCHEMABINDING | VIEW_METADATA} [,...]]

AS

select_statement

[WITH CHECK OPTION]

SQL Server's implementation of ALTER VIEW allows you to change an existing view without affecting the permissions or dependent objects of the view:

ALTER VIEW view_name [(column [,...])]

[WITH {ENCRYPTION | SCHEMABINDING | VIEW_METADATA} [,...]]

AS

select_statement

[WITH CHECK OPTION]

The parameters are as follows:


ENCRYPTION

Encrypts the text of the view in the syscomments table. This option is usually invoked by software vendors who want to protect their intellectual capital.


SCHEMABINDING

Binds the view to a specific schema, meaning that all objects in the view must be referenced by their full name (both owner and object name). The view and any tables referenced in the view SELECT clause must be fully qualified, as in pubs.scott.employee. Views created with SCHEMABINDING (and tables referenced by these views) must have the schema binding dropped (via ALTER VIEW) before they may be dropped or altered.


VIEW_METADATA

Specifies that SQL Server return metadata about the view (rather than the base table) to calls made from DBLIB or OLEDB APIs. Views created or altered with VIEW_METADATA enable their columns to be updated by INSERT and UPDATE INSTEAD OF triggers.


WITH CHECK OPTION

Forces the view to accept only inserted and updated data that can be returned by the view's SELECT statement.

The SELECT clause of a SQL Server view cannot:

  • Have the COMPUTE, COMPUTE BY, INTO, or ORDER BY clauses (ORDER BY is allowed if you use SELECT TOP)

  • Reference a temporary table

  • Reference a table variable

  • Reference more than 1,024 columns, including those referenced by subqueries

Here, we define a SQL Server view with both ENCRYPTION and CHECK OPTION:

CREATE VIEW california_authors (last_name, first_name, author_id)

WITH ENCRYPTION

AS

   SELECT au_lname, au_fname, au_id

   FROM authors

   WHERE state = 'CA'

WITH CHECK OPTION

GO

SQL Server allows multiple SELECT statements in a view, as long as they are linked with UNION or UNION ALL clauses. SQL Server also allows functions and hints in the SELECT statement of a view. A SQL Server view is updateable if all of the items in the following list are true.

  • The SELECT statement has no aggregate functions

  • The SELECT statement does not contain TOP, GROUP BY, DISTINCT, or UNION

  • The SELECT statement has no derived columns (see SUBQUERY)

  • The FROM clause of the SELECT statement references at least one table

SQL Server allows indexes to be created on views (see CREATE INDEX). By creating a unique, clustered index on a view, you cause SQL Server to store a physical copy of the view on the database. Changes to the base table are automatically updated in the indexed view. Indexed views consume extra disk space, but provide a boost in performance. Indexed views must be built using the SCHEMABINDING clause.

SQL Server also allows the creation of local partitioned views and distributed partitioned views. A local partitioned view is a partitioned view where all views are present on the same SQL Server. A distributed partitioned view is a partitioned view where one or more views are located on remote servers.

Partitioned views must very clearly derive their data from different sources, with each distinct data source joined with a UNION ALL statement to the next. Furthermore, all columns of the partitioned views should be selected and identical. (The idea is that you have split the data out logically by means of a frontend application. SQL Server then recombines the data through the partitioned view.) This example shows how the data in the view comes from three separate SQL Servers:

CREATE VIEW customers

AS

--Select from a local table on server 'New_York'

SELECT *

FROM sales_archive.dbo.customers_A

UNION ALL

SELECT *

FROM houston.sales_archive.dbo.customers_K

UNION ALL

SELECT *

FROM los_angeles.sales_archive.dbo.customers_S

Note that each remote server (New_York, houston, and los_angeles) has to be defined as a remote server on all of the SQL Servers using the distributed partitioned view. Partitioned views can greatly boost performance because they can split I/O and user loads across many machines. But they are also difficult to plan, create, and maintain. Be sure to read the vendor documentation for complete details about all the permutations available with partitioned views.

When altering an existing view, SQL Server acquires and holds an exclusive schema lock on the view until the alteration is finished. ALTER VIEW drops any indexes that might be associated with a view. You must manually recreate them using CREATE INDEX.

See Also

CREATE/ALTER TABLE
DROP
SELECT
SUBQUERY
DECLARE CURSOR Command

The DECLARE command is one of four commands used in cursor processing, along with FETCH, OPEN, and CLOSE. Cursors allow you to process queries one row at a time, rather than in a complete set. The DECLARE CURSOR command specifies the exact records to be retrieved and manipulated one row at a time from a specific table or view.

In other words, cursors are especially important for relational databases because databases are set-based, while most client-centric programming languages are row-based. This is important for two reasons. First, cursors allow programmers to program using methodologies supported by their favorite row-based programming language. Second, cursors run counter to the default behavior of some relational database platforms, which operate on a set of records and, on those specific platforms, may be noticeably slower than standard set-based operations.

Platform

Command

DB2

Supported, with limitations

MySQL

Not supported

Oracle

Supported, with limitations

PostgreSQL

Supported, with limitations

SQL Server

Supported, with limitations


SQL2003 Syntax

DECLARE cursor_name [ {SENSITIVE | INSENSITIVE | ASENSITIVE} ]

[[NO] SCROLL] CURSOR [{WITH | WITHOUT} HOLD]

    [{WITH | WITHOUT} RETURN}]

FOR select_statement 

[FOR {READ ONLY | UPDATE [OF column [,...] ]} ]

Keywords


DECLARE cursor_name

Gives the cursor a unique name in the context in which it is defined - for example, in the database or schema where it is created. The name must be unique, meaning that no other cursors may share the same name.


SENSITIVE | INSENSITIVE | ASENSITIVE

Defines the manner in which the cursor interacts with the source table and the result set retrieved by the cursor query, where:


SENSITIVE

Tells the database to operate directly against the result set, such that the cursor will see changes to its result set as it moves through the records.


INSENSITIVE

Tells the database to create a temporary but separate copy of the result set, so that all changes made against the result set by other operations are invisible to the cursor.


ASENSITIVE

Allows the database implementation to determine whether to make a copy of the result set. ASENSITIVE is the SQL2003 default.


[NO] SCROLL

Tells the database not to enforce processing one row at a time, using FETCH NEXT, but that all forms of the FETCH clause are allowed against the result set. NO SCROLL enforces processing one row at a time.


{WITH | WITHOUT} HOLD

Tells the cursor to remain open when a transaction encounters the COMMIT statement. Conversely, WITHOUT HOLD tells the cursor to close when the transaction encounters a COMMIT statement. (A cursor that uses WITH HOLD can only be and is always closed with a ROLLBACK statement or a CLOSE CURSOR statement.)


{WITH | WITHOUT} RETURN

Used only in a stored procedure, the WITH RETURN clause tells the database to return the result set, if it is still open, when the stored procedure terminates. With the WITHOUT RETURN clause, which is the default behavior, all open cursors are implicitly closed when the stored procedure terminates.


FOR select_statement

Defines the underlying SELECT statement that determines the rows in the result set of the cursor. As with a regular SELECT statement, the results of the query may be sorted according to an ORDER BY clause.


FOR {READ ONLY | UPDATE [OF column [,...] ] }

Specifies that the cursor is not updateable in any way, using FOR READ ONLY. This is the default when the cursor is defined with SCROLL or INSENSITIVE properties or the query contains an ORDER BY clause or is against an non-updateable table. Alternately, you can specify FOR UPDATE OF column1, column2 [,...], defining the columns where you want to execute UPDATE statements. You can leave off a column list on the FOR UPDATE OF to include all columns in the cursor.

Rules at a Glance

The DECLARE CURSOR command enables the retrieval and manipulation of records from a table one row at a time. This provides row-by-row processing, rather than the traditional set processing offered by SQL.

At the highest level, these steps are followed when working with a cursor:

  • Create a cursor using DECLARE.

  • Open the cursor using OPEN.

  • Operate against the cursor using FETCH.

  • Dismiss the cursor using CLOSE.

The DECLARE CURSOR command works by specifying a SELECT statement. Each row returned by the SELECT statement may be individually retrieved and manipulated. In this Oracle example, the cursor is declared in the declaration block along with some other variables. The cursor is then opened, fetched against, and then closed in the BEGIN...END block that follows:

DECLARE

   CURSOR title_price_cursor IS

      SELECT title, price

      FROM titles

      WHERE price IS NOT NULL;

   title_price_val title_price_cursor%ROWTYPE;

   new_price NUMBER(10,2);

BEGIN

   OPEN title_price_cursor;

   FETCH title_price_cursor INTO title_price_val;

   new_price := "title_price_val.price" * 1.25

   INSERT INTO new_title_price

   VALUES (title_price_val.title, new_price)

   CLOSE title_price_cursor;

END;

Because this example uses PL/SQL, much of the code is beyond the scope of this book. However, the DECLARE block clearly shows that the cursor is declared. In the PL/SQL execution block, the cursor is initialized with the OPEN command, values are retrieved with the FETCH command, and the cursor finally is terminated with the CLOSE command.

The SELECT statement is the heart of your cursor, so it is a good idea to test it thoroughly before embedding it in the DECLARE CURSOR statement. The SELECT statement may operate against a base table or a view. For that matter, read-only cursors may operate against non-updateable views. The SELECT statement can have subclauses like ORDER BY, GROUP BY, and HAVING if it is not updating the base table. If the cursor is FOR UPDATE, then it is a good idea to exclude these clauses from the SELECT statement.

Local cursors are sometimes used as output parameters of stored procedures. Thus, a stored procedure could define and populate a cursor and pass that cursor to a calling batch or stored procedure.

In this simple DB2 example, we'll declare a cursor that looks at department numbers, names, and manager numbers for all departments in the admin_group 'X01':

EXEC SQL

DECLARE dept_cursor CURSOR

FOR SELECT dept_nbr, dept_name, mgr_nbr

    FROM department

    WHERE admin_group = 'X01'

    ORDER BY dept_name ASC, dept_nbr DESC, mgr_nbr DESC;

In this next example from Microsoft SQL Server, a cursor from the publishers table is declared and opened. The cursor takes the first record from publishers that matches the SELECT statement and inserts it into another table; it then moves to the next record and the next, until all records are processed. Finally, the cursor is closed and deallocated (DEALLOCATE is used only with Microsoft SQL Server):

DECLARE @publisher_name VARCHAR(20)

DECLARE pub_cursor CURSOR

FOR SELECT pub_name FROM publishers

    WHERE country <> 'USA'

OPEN pub_cursor

FETCH NEXT FROM pub_cursor INTO @publisher_name

WHILE @@FETCH_STATUS = 0

BEGIN

    INSERT INTO foreign_publishers VALUES(@publisher_name)

END

CLOSE pub_cursor

DEALLOCATE pub_cursor

In this example, you see how the cursor moves through a set of records. (The example was intended only to demonstrate this concept, since there is actually a better way to accomplish the same task, namely an INSERT...SELECT statement.)

Programming Tips and Gotchas

Most platforms do not support dynamically executed cursors. Rather, cursors are embedded within an application program, stored procedure, user-defined function, etc. In other words, the various statements for creating and using a cursor are usually used only in the context of a stored procedure or other database-programming object, not in a straight SQL script.

For ease of programming and migration, don't use the SCROLL clause or the various sensitivity keywords. Some platforms support only forward-scrolling cursors, so you can avoid headaches later by just sticking to the simplest form of cursor.

Cursors behave differently on the various database platforms when crossing a transaction boundary - for example, when a set of transactions is rolled back in the midst of a cursor. Be sure to get familiar with exactly how each database platform behaves in these circumstances.

MySQL does not support server-side cursors in the ANSI SQL style, but does support extensive C-programming extensions that provide the same functionality.

DB2

DB2 supports the basic DECLARE CURSOR statement along with some variations on the WITH HOLD and WITH RETURN clauses, as in the following example:

DECLARE cursor_name CURSOR 

[WITH HOLD] [WITH RETURN [{TO CALLER | TO CLIENT}] ]

FOR select_statement

where:


WITH RETURN [{TO CALLER | TO CLIENT}]

Used only in a stored procedure, the WITH RETURN clause tells the database to return the result set, if it is still open, when the stored procedure terminates. (DB2 will accept WITH RETURN on cursors outside of a stored procedure, but it has no effect.) It has these options:


TO CALLER

Returns the result set to the caller, such as another stored procedure or process on the database server. It will also return the result set to a client, if that is what called the stored procedure. This is the default behavior for cursors embedded in DB2 external stored procedures.


TO CLIENT

Returns the result set to the client application, bypassing any intermediate processes such as nested stored procedures. This clause cannot be used to return result sets to functions or methods.


FOR select_statement

Defines the underlying SELECT statement that determines the rows in the result set of the cursor. The SELECT statement cannot include parameters, but can include host variables, as long as they have been declared before the cursor. You may also use a prepared SELECT statement as the select_statement, using the DB2 PREPARE command.

DB2 provides syntax to explicitly declare a cursor as read-only or updateable as part of the SELECT statement rather than as part of the DECLARE CURSOR statement.

When not specified, the updateability of a cursor is implicitly determined according to a variety of rules that improve locking. First of all, a cursor is assumed to be read-only if it is not deleteable. A DB2 cursor is deleteable when it has the FOR UPDATE clause plus:

  • The FROM clause of the SELECT statement references only one base table or deleteable view.

  • The SELECT statement does not contain a VALUES clause, a DISTINCT clause, a GROUP BY clause, a HAVING clause, an ORDER BY clause, a FOR READ ONLY clause, or UNION, EXCEPT, or INTERSECT clauses.

  • The SELECT statement is free of column functions in the select item list.

The columns of a DB2 cursor are updateable when it meets the requirements to be deleteable plus:

  • The columns are resolved to columns in the base table or view.

  • The LANGLEVEL bind option is MIA, SQL92E, or the columns are referenced in the FOR UPDATE clause of the select_statement.

A DB2 cursor may also be updateable if it is statically defined or has the SQL-standard bind option (MIA) applied to LANGLEVEL. The LANGLEVEL setting MIA indicates that the cursor runs under SQL92 rules. The setting SQL92E indicates that the cursor runs under the SQL92 entry-level rules. And the setting SAA1 indicates that the cursor runs under the DB2 common (old) rules. LANGLEVEL is assigned using the DB2 PREP command.

DB2 also allows cursors to be ambiguous. An ambiguous cursor is considered updateable unless the BLOCKING bind option is ALL, whence it is considered read-only. A cursor is ambiguous when all these conditions are true:

  • The select_statement doesn't include a FOR READ ONLY or FOR UPDATE clause.

  • The language level setting (LANGLEVEL) is set to the value SAA1.

  • The select_statement is dynamically prepared.

  • The cursor is otherwise deleteable.

There are a couple things to be careful of with DB2 cursors:

  • System function values, such as those returned by CURRENT DATE, CURRENT TIME, or CURRENT TIMESTAMP, are determined when a cursor is opened and not when the FETCH statement is executed. Therefore, any of these values would be identical for every record in the result set, since the values are determined once when the cursor is opened.

  • If a LANGUAGE other than SQL (such as Java) is used for the stored procedure, the default behavior is WITH RETURN TO CALLER.


MySQL

Not supported.

Oracle

Oracle has a rather interesting implementation of cursors. In reality, all Oracle data modification statements (INSERT, UPDATE, DELETE, and SELECT) implicitly open a cursor. For example, a C program accessing Oracle would not need to issue a DECLARE CURSOR statement to retrieve data on a record-by-record basis because that is the implicit behavior of Oracle. Because of this behavior, DECLARE CURSOR is something you use only in PL/SQL constructs, like stored procedures, and not something you would use in a script that is purely SQL.

Since cursors can only be used in stored procedures and user-defined functions on Oracle, they are documented in the Oracle PL/SQL reference material, not in the SQL reference material.


Oracle utilizes a variation of the DECLARE CURSOR statement that supports parameterized inputs, as in the following syntax:

DECLARE CURSOR cursor_name [ ( parameter datatype [,...] ) ]

IS select_statement

[FOR UPDATE [OF column_name [,...]]}]

where:


parameter datatype [,...]IS select_statement

Defines the select_statement used to retrieve the cursor result set. It serves the same purpose as the ANSI SQL2003 FOR select_statement clause.


FOR UPDATE [OF column_name]

Defines the cursor or specific columns of the cursor as updateable. Otherwise, the cursor is assumed to be read-only.

In Oracle, variables are not allowed in the WHERE clause of the SELECT statement unless they are first declared as variables. The parameters are not assigned at the DECLARE; instead, they are assigned values at the OPEN command. This is important since any system function will return an identical value for all rows in the cursor result set.

PostgreSQL

PostgreSQL does not support the WITH clauses. It does allow you to return result sets in BINARY rather than text format. Although the compiler will not cause errors with many of the ANSI keywords, PostgreSQL's implementation of DECLARE CURSOR is more limited than it might first appear:

DECLARE cursor_name [BINARY] [INSENSITIVE] [SCROLL] CURSOR

FOR select_statement

[FOR {READ ONLY | UPDATE [OF column_name [,...]]}]

where:


BINARY

Forces the cursor to retrieve binary-formatted data rather than text-formatted data.


INSENSITIVE

Indicates that data retrieved by the cursor is unaffected by updates from other processes or cursors. However, this is PostgreSQL's default behavior, so adding or leaving this keyword off has no effect.


SCROLL

Allows multiple rows to be retrieved by a single FETCH operation. However, this is PostgreSQL's default behavior, so adding or leaving off this keyword has no effect.


FOR {READ-ONLY | UPDATE}

Indicates that a cursor is opened using read-only mode or updateable mode, respectively. However, PostgreSQL only supports read-only cursors. That means that the FOR READ-ONLY clause has no effect, while the FOR UPDATE (column_name) clause produces an informational error message.

PostgreSQL closes any existing cursor when a newly declared cursor is created with the same name. Binary cursors tend to be faster because PostgreSQL stores data as binary on the backend. However, user applications are only text aware. Therefore, you would have to build in binary handling for any BINARY cursors.

PostgreSQL allows cursors only within a transaction. You should enclose a cursor within a BEGIN and COMMIT or ROLLBACK transaction block.

PostgreSQL does not support an explicit OPEN cursor statement. Cursors are considered open when they are declared. So to declare and open a cursor in PostgreSQL, you could use code like this:

DECLARE pub_cursor CURSOR

FOR SELECT pub_name FROM publishers

    WHERE country <> 'USA';

SQL Server

SQL Server supports the ANSI standard, as well as a good many extensions that provide flexibility in how a cursor scrolls through a result set and manipulates data, as in the following syntax:

DECLARE cursor_name [INSENSITIVE] [SCROLL] CURSOR

  [LOCAL | GLOBAL] [FORWARD_ONLY | SCROLL]

  [STATIC | KEYSET | DYNAMIC | FAST_FORWARD]

  [READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]

  [TYPE_WARNING]

FOR select_statement

[FOR {READ ONLY | UPDATE [OF column_name [,...] ]} ]

The parameters are as follows:


LOCAL | GLOBAL

Scopes the cursor for either the local Transact-SQL batch or makes the cursor available to all Transact-SQL batches issued by the current session via OPEN and FETCH statements, respectively. A global cursor name can be referenced by any stored procedure, function, or Transact-SQL batch executed in the current session. A global cursor is implicitly deallocated at disconnect, but a local cursor must be manually deallocated. The LOCAL and GLOBAL keywords are optional. The default behavior, if neither is specified, is defined by the default to local database property.


INSENSITIVE | FORWARD_ONLY | SCROLL

Determines how the cursor will move through the result set, with three options:


INSENSITIVE

Creates the result set as a table in TEMPDB. Changes to the base table are not reflected in the cursor result set. Not compatible with SQL Server extensions to the DECLARE CURSOR command like LOCAL, GLOBAL, STATIC, KEYSET, DYNAMIC, FAST_FORWARD, etc. Can only be used in a SQL92-style DECLARE CURSOR statement, such as DECLARE sample CURSOR INSENSITIVE FOR select_statement FOR UPDATE.


FORWARD_ONLY

Indicates that the cursor must scroll from the first to the last record in the result set and that FETCH NEXT is the only supported form of the FETCH statement. The cursor is assumed to be DYNAMIC unless STATIC or KEYSET are used. FAST_FORWARD is mutually exclusive of FORWARD_ONLY.


SCROLL

Enables all FETCH options (ABSOLUTE, FIRST, LAST, NEXT, PRIOR, and RELATIVE). Otherwise, only FETCH NEXT is available. If DYNAMIC, STATIC, or KEYSET are used, the cursor defaults to SCROLL behavior. FAST_FORWARD is mutually exclusive of SCROLL.


STATIC | KEYSET | DYNAMIC | FAST_FORWARD

Determines how records are manipulated in the result set. These settings are incompatible with the FOR READ ONLY and FOR UPDATE clauses. There are four options:


STATIC

Makes a temporary copy of the result set data and stores it in tempdb. Modifications made to the source table or view do not show up when processing the cursor. STATIC cursors cannot modify data in the source table or view.


KEYSET

Makes a temporary copy of the result set with membership and fixed row order (also known as a keyset) in tempdb. The keyset correlates the data in the cursor result set to the base table or view such that the cursor can see changes made to the underlying data. Rows that have been deleted or updated show an @@FETCH_STATUS of -2 (unless the update was done using UPDATE...WHERE CURRENT OF, in which case they are fully visible), while rows inserted by other users are not visible at all.


DYNAMIC

Determines the records in the cursor result set as each FETCH operation is executed. Thus, DYNAMIC cursors see all changes made to the base table or view, even those by other users. Because the result set may be in constant flux, DYNAMIC cursors do not support FETCH ABSOLUTE.


FAST_FORWARD

Creates a FORWARD_ONLY, READ_ONLY cursor that quickly reads through the entire cursor result set at one time.


READ_ONLY | SCROLL_LOCKS | OPTIMISTIC

Determines concurrency and positional update behavior for the cursor. These settings are incompatible with FOR READ ONLY and FOR UPDATE. The allowable parameters include:


READ_ONLY

Prevents updates to the cursor and disallows the cursor from being referenced in UPDATE or DELETE statements that contain WHERE CURRENT OF.


SCROLL_LOCKS

Ensures that positional updates and deletes succeed by locking the cursor result set rows as they are read into the cursor. The locks are held until the cursor is closed and deallocated. SCROLL_LOCKS is mutually exclusive of FAST_FORWARD.


OPTIMISTIC

Ensures that positional updates and deletes succeed unless the row benig updated or deleted in the cursor result set has changed since it was read into the cursor. SQL Server accomplishes this by comparing a timestamp, or a checksum value when no timestamp exists, on the columns. It does not lock the rows in the cursor result set. OPTIMISTIC is mutually exclusive of FAST_FORWARD.


TYPE_WARNING

Warns the user when the cursor is implicitly converted from one type to another - for example from SCROLL to FORWARD_ONLY.


FOR {READ ONLY |

Identifies the cursor as read only using the ANSI standard syntax. This keyword is not compatible with the other type identifiers shown previously. It should only be used with INSENSITIVE, FORWARD_ONLY, and SCROLL.


FOR UPDATE [OF column_name [,...] ]}

Allows updates to columns in the cursor using UPDATE and DELETE statements with the WHERE CURRENT OF clause. If FOR UPDATE is used without a column list, then all columns in the cursor are updateable. Otherwise, only those columns listed are updateable.

Microsoft SQL Server allows two basic forms of syntax for the DECLARE CURSOR statement. The syntax forms are not compatible! The basic forms of syntax are SQL92 compatible and Transact-SQL extensions. You cannot mix keywords of the two forms together.


The SQL-92 compatibility syntax for DECLARE CURSOR is:

DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ] CURSOR

FOR select_statement 

[ FOR { READ ONLY | UPDATE [ OF column_name [,...] ] } ]

While the Transact-SQL extensioned syntax for DECLARE CURSOR is:

DECLARE cursor_name CURSOR

[ LOCAL | GLOBAL ] [ FORWARD_ONLY | SCROLL ]

[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]

[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]

[ TYPE_WARNING ]

FOR select_statement 

[ FOR UPDATE [ OF column_name [,...] ] ]

The SQL92 compatability syntax is supported to enable your code to be more transportable. The Transact-SQL extensions syntax enables you to define cursors using the same cursor types that are available in popular database APIs like ODBC, OLE-DB, and ADO, but may only be used in SQL Server stored procedures, user-defined functions, triggers, and ad hoc queries.

If you do define a Transact-SQL extension cursor but do not define concurrency behavior using the OPTIMISTIC, READ_ONLY, or SCROLL_LOCKS keywords, then:

  • The cursor defaults to READ-ONLY if the cursor is defined as FAST_FORWARD, STATIC, or the user has insufficient privileges to update the base table or view.

  • The cursor defaults to OPTIMISTIC if the cursor has been defined as DYNAMIC or KEYSET.

Note that variables may be used in the select_statement of a SQL Server cursor, but the variables are evaluated when the cursor is declared. Thus, a cursor containing the column based on the system function GETDATE( ) will have the same date and time for every record in the cursor result set.

In the following SQL Server example, we use a KEYSET cursor to change blank spaces to dashes in the phone column of the authors table:

SET NOCOUNT ON

DECLARE author_name_cursor CURSOR LOCAL KEYSET TYPE_WARNING

   FOR SELECT au_fname FROM pubs.dbo.authors

DECLARE @name varchar(40)

OPEN author_name_cursor

FETCH NEXT FROM author_name_cursor INTO @name

WHILE (@@fetch_status <> -1)

BEGIN

-- @@fetch_status checks for 'record not found' conditions and errors

   IF (@@fetch_status <> -2)

   BEGIN

      PRINT 'updating record for ' + @name

      UPDATE pubs.dbo.authors

      SET phone = replace(phone, ' ', '-')

      WHERE CURRENT OF author_name_cursor

   END

   FETCH NEXT FROM author_name_cursor INTO @name

END

CLOSE author_name_cursor

DEALLOCATE author_name_cursor

GO

See Also

CLOSE CURSOR
FETCH
OPEN
DELETE Statement

The DELETE statement erases records from a specified table or tables. DELETE statements acting against tables are sometimes called search deletes. The DELETE statement may also be used in conjunction with a cursor. DELETE statements acting upon the rows of a cursor are sometimes called positional deletes.

Platform

Command

DB2

Supported, with variations

MySQL

Supported, with variations

Oracle

Supported, with variations

PostgreSQL

Supported

SQL Server

Supported, with limitations


SQL2003 Syntax

DELETE FROM { table_name | ONLY (table_name) }

[{ WHERE search_condition | WHERE CURRENT OF cursor_name }]

Keywords


FROM table_name

Identifies the table, called table_name, from which rows will be deleted. The table_name assumes the current schema if one is not specified. You may alternately specify a single table view name. FROM is mandatory, except in the DELETE...WHERE CURRENT OF statement. When not using the ONLY clause, do not enclose the table_name in parentheses.


ONLY (table_name)

Restricts cascading of the deleted records to any subtables of the target table or view. ONLY effects only typed (object-oriented) tables and views. If used with a non-typed table or view, it is ignored and does not cause an error. If ONLY is used, you must enclose the table_name in parentheses.


WHERE search_condition

Defines search criteria for the DELETE statement using one or more search_condition clauses to ensure that only the target rows are deleted. Any legal WHERE clause is acceptable. Typically, these criteria are evaluated against each row of the table before the deletion occurs.


WHERE CURRENT OF cursor_name

Restricts the DELETE statement to the current row of a defined and opened cursor called cursor_name.

Rules at a Glance

The DELETE statement erases rows from a table or view. Space released by erased rows will be returned to the database where the table is located, though it may not happen immediately.

A simple DELETE statement that erases all records in a given table has no WHERE clause, as in the following:

DELETE FROM sales;

You can use any valid WHERE clause to filter records that you do not want to delete. All three of the following examples show valid DELETE statements, and since all are search deletes, they all include the FROM clause:

DELETE FROM sales

WHERE qty IS NULL;

DELETE FROM suppliers

WHERE supplierid = 17

   OR companyname = 'Tokyo Traders';

DELETE FROM distributors

WHERE postalcode IN

   (SELECT territorydescription FROM territories);

In some cases, you may wish to delete a specific row that is being processed by a declared and open cursor:

DELETE titles WHERE CURRENT OF title_cursor;

The above query assumes that you have declared and opened a cursor named title_cursor. Whichever row the cursor is on will be deleted when the command, shown above, is executed. Note that in the positional delete shown earlier, the FROM clause is not required.

Programming Tips and Gotchas

It is rare to issue a DELETE statement without a WHERE clause, because this results in deleting all rows from the affected table. You should first issue a SELECT statement with the same WHERE clause you intend to use on the DELETE statement. That way you can be sure exactly which records will be deleted.

If it becomes necessary to remove all the rows in a table, you should consider using the non-ANSI TRUNCATE TABLE statement. In those databases that support the command, TRUNCATE TABLE is usually a faster method to physically remove all rows. TRUNCATE TABLE is faster than DELETE because the deletion of individual records is not logged. On some platforms, this makes rollback of a TRUNCATE statement impossible. The reduction of logging overhead saves considerable time when erasing a large number of records. On some database platforms, all foreign keys on the table must be dropped before issuing a TRUNCATE statement.

DB2

DB2 supports the ANSI standard, with the addition of transaction isolation control and the ability to assign an alias to the table from which records will be deleted, as in the following:

DELETE FROM { table_name | ONLY (table_name) } [AS alias]

[WHERE {search_conditions | CURRENT OF cursor_name}]

[WITH { RR | RS | CS | UR }]

The parameters are:


AS alias

Allows the target table_name to use an alias. This is especially useful for correlated subqueries. (Note that DB2 has a special object called an alias that may be created with the DB2 CREATE ALIAS statement. In this case, the term "alias" represents what the ANSI SQL standard calls a correlation name, something akin to a simple nickname for the table or view.)


WITH {RR | RS | CS | UR}

Controls transaction isolation level for the update statement. RR is repeatable read, RS is read stability, CS is cursor stability, and UR is uncommitted read. See the SET TRANSACTION Statement section for full details on these transaction isolation levels.

On DB2, the target may be a table, updateable view, or nickname. As the ANSI standard dictates, rows will be deleted from any subtables of the target table unless you use the ONLY keyword. If ONLY is used, you must enclose the table_name in parentheses.

If you use ONLY in combination with WHERE CURRENT OF, then the SELECT statement that defined the cursor must use the FROM ONLY clause as well. For example:

DECLARE CURSOR emp_cursor FOR

  SELECT name, address

    FROM ONLY (employee);

DELETE FROM ONLY (employee)

  WHERE CURRENT OF emp_cursor;

The previous code assumes that employee is the base table, with subtables below it. The cursor will only select rows that are contained in employee and not the other types contained in the subtables (e.g., parttime, salaried, student). Similarly, deletes will only take place at this level of the hierarchy as well.

MySQL

MySQL allows a number of extensions over the ANSI standard, but does not support the WHERE CURRENT OF clause, as in the following:

DELETE [LOW_PRIORITY] [QUICK] [table_name[.*] [,...] ]

{FROM table_name[.*] [,...] | [USING table_name[.*] [,...] ] }

[WHERE search_condition]

[ORDER BY clause]

[LIMIT nbr_of_rows]

The parameters are:


LOW PRIORITY

Delays the execution of DELETE until no other clients are reading from the table.


QUICK

Prevents the storage engine from merging index leaves during the delete operation.


DELETE table_name [,...]

Enables you to delete from more than one table at a time. Tables listed before the FROM clause, assuming one or more tables appear in the FROM clause, will be the target of the delete operation. If more than one table appears before the FROM clause, then all matching records in all tables will be deleted.


FROM table_name[.*]

Specifies the table or tables where records will be deleted. (The .* clause is an option to improve compatibility with MS-Access.) If tables are listed before the FROM clause, then the table or tables in the FROM clause are assumed to be used to support a join or lookup operation.


USING table_name[.*] [,...]

Substitute the table or tables before the FROM clause with those after the FROM clause.


ORDER BY clause

Specifies the order that rows will be deleted in. This is useful only in conjunction with LIMIT.


LIMIT nbr_of_row

MySQL also can place an arbitrary cap on the number of records deleted before control is passed back to the client using the LIMIT nbr_of_rows clause.

MySQL allows deletion from more than one table at a time. For example, the following two DELETE statements are functionally equivalent:

DELETE orders FROM customers, orders

WHERE customers.customerid = orders.customerid

  AND orders.orderdate BETWEEN '19950101' AND '19951231'

DELETE FROM orders USING customers, orders

WHERE customers.customerid = orders.customerid

  AND orders.orderdate BETWEEN '19950101' AND '19951231'

In the examples above, we delete all orders made by customers during the year 1995. Note that you cannot use ORDER BY or LIMIT clauses in a multitable delete like those shown above.

You can also delete records in orderly batches using the ORDER BY clause in conjunction with the LIMIT clause:

DELETE FROM sales

WHERE customerid = 'TORTU

ORDER BY customerid

LIMIT 5

MySQL exhibits several behaviors that speed up the delete operation. For example, MySQL returns the number of records deleted when it completes the operation. However, MySQL will return zero as the number of deleted records when you delete all records from a table because it is faster for MySQL to return zero than to count the rows deleted. In AUTOCOMMIT mode, MySQL will even substitute a TRUNCATE statement for a DELETE statement without a WHERE clause because TRUNCATE is faster.

Note that the speed of a MySQL delete operation is directly related to the number of indexes on the table and the available index cache. You can speed up delete operations by executing the command against tables with few or no indexes or by increasing the size of the index cache.

Oracle

Oracle allows you to delete rows from tables, views, materialized views, nested subqueries, and partitioned views and tables, as follows:

DELETE [FROM]

   {table_name | ONLY (table_name)} [alias]

      [{PARTITION (partition_name) |

      SUBPARTITION (subpartition_name)}] |

   (subquery [WITH {READ ONLY |

      CHECK OPTION [CONSTRAINT constraint_name]}] ) |

   TABLE (collection_expression ) [ (+) ] }

[WHERE search_condition]

[RETURNING expression [,...] INTO variable [,...] ]

The parameters are:


table_name [alias]

Specifies the table, view, materialized view, or partitioned table or view where records will be deleted. You may optionally prepend a schema identifier to the table_name or append a database link. Otherwise, Oracle will assume the user's default schema and the local database server. You may optionally apply an alias to the table_name. The alias is required if the target table references an object type attribute or method.


PARTITION partition_name

Applies the delete operation to the named partition, rather than to the entire table You are not required to name a partition when deleting from a partitioned table, but it can, in many cases, help reduce the complexity of the WHERE clause.


SUBPARTITION subpartition_name

Applies to a named subpartition, rather than to the entire table.


(subquery [WITH {READ ONLY | CHECK OPTION [CONSTRAINT constraint_name] } ] )

Specifies that the target for deletion is a nested subquery, not a table, view, or other database object. The parameters of this clause are:


subquery

Describes the SELECT statement that makes up the subquery. The subquery can be any standard subquery, though it may not contain an ORDER BY clause.


WITH READ ONLY

Specifies that the subquery cannot be updated.


WITH CHECK OPTION

Tells Oracle to abort any changes to the deleted table that would not appear in the result set of the subquery.


CONSTRAINT constraint_name

Tells Oracle to further restrict changes based upon a specific constraint identified by constraint_name.


TABLE (collection_expression ) [ (+) ]

Informs Oracle that the collection_expression should be treated like a table though it may, in fact, be a subquery, a function, or some other collection constructor. In any case, the value returned by the collection_expression must be a nested table or VARRAY.


RETURNING expression

Retrieves the rows affected by the command, where DELETE normally only shows the number of rows deleted. The RETURNING clause can be used when the target is a table, a materialized view, or a view with a single base table. When used for single-row deletes, the RETURNING clause stores values from the row deleted by the statement, defined by expression, into PL/SQL variables and bind variables. When used for a multirow delete, the RETURNING clause stores the values of the deleted rows, defined by expression, into bind arrays.


INTO variable

Specifies the variables into which the values returned as a result of the RETURNING clause are stored. There must be a corresponding variable for every expression in the RETURNING clause.

When you execute a DELETE statement, Oracle releases space from the target table (or the base table of a target view) back to the table or index that owned the data.

When deleting from a view, the view cannot contain a set operator, the DISTINCT keyword, joins, an aggregate function, an analytic function, a subquery in the SELECT list, a collection expression in the SELECT list, a GROUP BY clause, an ORDER BY clause, a CONNECT BY clause, or a START WITH clause.

Here's an example where we delete records from a remote server:

DELETE FROM scott.sales@chicago;

In the following query, we delete from a derived table that is a collection expression:

DELETE TABLE(SELECT contactname FROM customers

   c WHERE c.customerid = 'BOTTM') s

WHERE s.region IS NULL OR s.country = 'MEXICO';

Here's an example where we delete from a partition:

DELETE FROM sales PARTITION (sales_q3_1997)

WHERE qty > 10000;

Finally, in the example below, we use the RETURNING clause to look at the values that are deleted:

DELETE FROM employee

WHERE job_id = 13

  AND hire_date + TO_YMINTERVAL('01-06') =< SYSDATE;

RETURNING job_lvl

INTO :int01;

The previous example deletes records from the employee table and returns the job_lvl values into the predefined :into1 variable.

PostgreSQL

PostgreSQL uses the DELETE command to remove rows and any defined subclasses from the table. It is otherwise identical to the ANSI standard, as follows:

DELETE [FROM] [ONLY] table_name

[ WHERE search_condition | WHERE CURRENT OF cursor_name ]

When deleting rows from only the table specified, use the optional ONLY clause. Otherwise, PostgreSQL will also delete records from any explicitly defined subtable.

To delete all records from the titles table:

DELETE titles

To delete all records in the authors table where the last name starts with "Mc":

DELETE FROM authors

WHERE au_lname LIKE 'Mc%'

To delete all titles with an old ID number:

DELETE titles WHERE title_id >= 40

To delete all titles that have no sales:

DELETE titles WHERE ytd_sales IS NULL

To delete all records in one table based on the results of a subquery against another table (in this case, the records that have a match concerning "computers" in the titles table are erased from the titleauthor table):

DELETE FROM titleauthor

WHERE title_id IN

  (SELECT title_id

  FROM titles

  WHERE title LIKE '%computers%')

DISCONNECT

SQL Server

Microsoft SQL Server allows records to be deleted both from tables and from views that describe a single table. SQL Server also allows a second FROM clause to allow JOIN constructs, as in the following example:

DELETE [TOP number [PERCENT]] [FROM] table_name [[AS] alias]

[FROM table_source [,...]]

[ [{INNER | CROSS | [{LEFT | RIGHT | FULL] OUTER}]

   JOIN joined_table ON condition][,...]

[WHERE search_condition | WHERE CURRENT OF [GLOBAL] cursor_name ]

[OPTION (query_hint[,...n])]

The syntax elements are as follows:


DELETE table_name

Allows the deletion of records from the named table or view filtered by the WHERE clause. You can delete records from a view providing the view is based on one table and contains no aggregate functions and no derived columns. If you leave off the server name, database name, or schema name when naming the table or view, SQL Server assumes the current context. An OPENDATASOURCE or OPENQUERY function, as described in the SELECT Statement section may be referenced instead of a table or view.


TOP number [PERCENT]

Specifies that only the number of rows are deleted by the statement. If PERCENT is specified, only the first number percent of the rows are retrieved. If the number is an expression, such as a variable, it must be enclosed in parentheses. The expression should be of FLOAT datatype with a range of 0 to 100 when using PERCENT. When not using PERCENT, the expression should by of BIGINT datatype.


FROM table_source

Names an additional FROM clause that correlates records from the table in the first FROM clause using a JOIN rather than forcing you to use a correlated subquery. One or more tables may be listed in the second FROM clause.


[{INNER | CROSS | [{LEFT | RIGHT | FULL] OUTER}] JOIN joined_table ON condition][,...]

Specifies one or more JOIN clauses, in conjunction with the second FROM clause. You may use any of the join types that SQL Server supports. Refer to the JOIN Subclause and SELECT Statement sections for more information.


GLOBAL cursor_name

Specifies that the delete operation should occur on the current row of an open global cursor. This clause is otherwise the same as the standard for WHERE CURRENT OF.


OPTION (hint [,...] )

Replaces elements of the default query plan with your own. Because the optimizer usually picks the best query plan for any query, we strongly discourage you from placing optimizer hints into your queries.

The primary addition to DELETE that SQL Server offers over and above the ANSI standard is a second FROM clause. The second FROM allows the use of the JOIN statement and makes it quite easy to delete rows from the table in the first FROM by correlating rows of a table declared in the second FROM. For example, you can use a rather complex subquery to erase all the sales records of computer books with this command:

DELETE sales

WHERE title_id IN

   (SELECT title_id

   FROM titles

   WHERE type = 'computer')

But SQL Server allows a more elegant construction using a second FROM clause and a JOIN clause:

DELETE s

FROM sales AS s

INNER JOIN titles AS t ON s.title_id = t.title_id

   AND type = 'computer'

The following example deletes all rows with an order_date of 2003 or earlier in batches of 2,500:

WHILE 1 = 1

BEGIN

  DELETE TOP (2500)

  FROM sales_history WHERE order_date <= '20030101'

  IF @@rowcount < 2500 BREAK

END

The TOP clause should be used in favor of the old SET ROWCOUNT statement because the TOP clause is open to many more query optimization algorithms. (Prior to SQL Server 2005, the SET ROWCOUNT statement was often used with data modification transactions to process large numbers of rows in batches, thus preventing the transaction log from filling up and ensuring that row locks would not escalate to a full table lock.)

See Also

INSERT
SELECT
TRUNCATE TABLE
UPDATE
DISCONNECT Statement

The DISCONNECT statement terminates one or more connections created between the current SQL process and the database server.

Platform

Command

DB2

Supported, with limitations

MySQL

Not supported

Oracle

Supported, with limitations

PostgreSQL

Not supported

SQL Server

Supported, with limitations


SQL2003 Syntax

DISCONNECT {CURRENT | ALL | connection_name | DEFAULT}

Keywords


CURRENT

Closes the currently active user connection.


ALL

Closes all open connections for the current user.

Rules at a Glance

DISCONNECT is used to disconnect a named SQL session (connection_name), the CURRENT connection, the DEFAULT connection, or ALL connections held by the user. For example, we can disconnect a single session called new_york:

DISCONNECT new_york

In the next example, we might want to disconnect all currently open sessions for the current user process:

DISCONNECT ALL

Programming Tips and Gotchas

DISCONNECT is not universally supported across platforms. Do not build cross-platform applications based on DISCONNECT unless you've made provisions to disconnect SQL sessions using each platform's preferred disconnection methodology.

DB2

DB2 supports the ANSI standard for DISCONNECT in embedded SQL only. DISCONNECT can drop one or more connections only after a commit or rollback operation succeeds for the sessions to be dropped. You can also use the RELEASE statement to place a connection in a disconnect-pending condition.

MySQL

Not supported.

Oracle

Oracle allows DISCONNECT only in its ad hoc query tool, SQL*Plus, using this syntax:

DISC[ONNECT]

In this usage, the command ends the current session with the database server but otherwise allows work in SQL*Plus to continue. For example, a programmer can continue to edit the buffer, save run files, and so on. However, you must establish a new connection to issue any SQL commands. Exiting SQL*Plus and returning to the filesystem requires the EXIT or QUIT commands. For example, to end the current connection with an Oracle server:

DISCONNECT;

PostgreSQL

Not supported. Instead, every programming interface supports a disconnect operation; for example, SPI_FINISH is available under the Server Programming Interface, and PG_CONNECT is available under the PL/TCL programming package.

SQL Server

Microsoft SQL Server supports the ANSI syntax for DISCONNECT in Embedded-SQL (ESQL) only, not within its ad hoc querying tool, SQL Query Analyzer. To disconnect cleanly from Microsoft SQL Server in an ESQL program, use the DISCONNECT ALL statement.

See Also

CONNECT
DROP Statements

All of the database objects created with CREATE statements may be destroyed using complementary DROP statements. On some platforms, a ROLLBACK statement after a DROP statement will recover the dropped object. However, on other database platforms, the DROP statement is irreversible and permanent, so it is advisable to use the command with care.

Platform

Command

DB2

Supported, with variations

MySQL

Supported, with limitations

Oracle

Supported, with variations

PostgreSQL

Supported, with limitations

SQL Server

Supported, with limitations


SQL2003 Syntax

Currently, the SQL2003 standard supports the ability to drop a lot of object types that are largely unsupported by most vendors. The ANSI SQL2003 syntax follows this format:


DROP {object_type} object_name {RESTRICT | CASCADE}

Keywords


DROP object_type object_name

Irreversibly and permanently destroys the specified object, called object_name, of the type identified. The object_name does not need a schema identifier, but the current schema is then assumed. ANSI SQL2003 supports a long list of object types, each created with their own corresponding CREATE statement. CREATE statements covered in this book with corresponding DROP statements include:

DOMAIN

SCHEMA

FUNCTION

TABLE

METHOD

TRIGGER

PROCEDURE

TYPE

ROLE

VIEW



RESTRICT | CASCADE

Prevents the DROP from taking place if any dependent objects exist (RESTRICT), or causes all dependent objects to also be dropped (CASCADE). This clause is not allowed with some forms of DROP, like DROP TRIGGER, but is mandatory for others, like DROP SCHEMA. To further explain, DROP SCHEMA RESTRICT will only drop an empty schema. Otherwise, if the schema contains objects, the operation will be prevented. In contrast, DROP SCHEMA CASCADE will drop a schema and all objects contained therein.

Rules at a Glance

For rules about the creation or modification of each of the object types, refer to the corresponding CREATE/ALTER statements.

The DROP statement destroys a pre-existing object. The object is permanently destroyed, and all users who had access to the object immediately lose the ability to access the object.

The object may be qualified - that is, you may fully specify the schema where the dropped object is located. For example:

DROP TABLE scott.sales_2004 CASCADE;

The above statement would not only drop the table scott.sales_2004, but also any views, triggers, or constraints built on it. On the other hand, a DROP statement may include an unqualified object name, and then the current schema context is assumed. For example:

DROP TRIGGER before_ins_emp;

DROP ROLE sales_mgr;

Although not required by the SQL2003 standard, most implementations cause the DROP command to fail if the database object is in use by another user.

Programming Tips and Gotchas

DROP will only work when it is issued against a pre-existing object of the appropriate type where the user has appropriate permissions, usually the DROP TABLE permission. (Refer to the GRANT Statement section for more information.) The SQL standard requires only that the owner of an object may drop it, but most database platforms allow variations on that requirement. For example, the database superuser can usually drop any object on the database server.

With some vendors, the DROP command fails if the database object has extended properties. For example, Microsoft SQL Server will not drop a table that is replicated unless you first remove the table from replication.

It is important to be aware that most vendors do not notify you if the DROP command creates a dependency problem. Thus, if a table that is used by a few views and by stored procedures elsewhere in the database is dropped, no warning is issued. Those other objects simply return failures when they are accessed. To prevent this problem, you may wish to use the RESTRICT syntax where it is available.


You may have noticed that the ANSI standard does not support certain common DROP commands like DROP DATABASE and DROP INDEX, even though every vendor covered in this book (and just about every one in the market) supports these commands. The exact syntax for each of these commands is covered in the platform-specific sections below.

DB2

DB2 does not support the CASCADE option. It supports many of the ANSI object types in addition to many of its own object types, as follows:

DROP {BUFFERPOOL | EVENT MONITOR | [SPECIFIC] FUNCTION |

      FUNCTION MAPPING | INDEX | INDEX EXTENSION |

      [SPECIFIC] METHOD | NICKNAME | DATABASE PARTITION GROUP |

      PACKAGE | [SPECIFIC] PROCEDURE | SCHEMA | SEQUENCE | SERVER |

      TABLE [HIERARCHY] | TABLESPACE[S] | TRANSFORM[S]

      [{ALL | group_name}] FOR | TRIGGER | [DISTINCT] TYPE |

      TYPE MAPPING | USER MAPPING FOR {authorization_name | USER} SERVER |

      VIEW [HIERARCHY] | WRAPPER } object_name [RESTRICT]

The rules for DB2's DROP statements are less consistent than the ANSI standard's rules, so the full syntax of each DROP variant is shown below:


BUFFERPOOL bufferpool_name

Drops the named bufferpool as long as no tablespaces are assigned to it. Memory is recovered immediately, but disk space may be recovered at the next connection to the database.


EVENT MONITOR event_monitor_name

Drops the named event monitor as long as the event monitor is not set ON.


[SPECIFIC] FUNCTION function_name [ (datatype [,...] )] [RESTRICT]

Drops the named user-defined function. DB2 allows multiple functions of the same name. To drop these, use the syntax DROP FUNCTION function_name (data type [,...]), providing data type identifiers sufficient to uniquely identify the user-defined function. Use the optional SPECIFIC keyword to identify functions by the unique name assigned to each at creation time. You may drop a function while it is in use without causing the user to experience a failure (until they try to access it later). However, you cannot drop a function that is a component of a package, triggers, views, etc. Here are examples of all three syntaxes:

DROP FUNCTION sales_summary_1992

DROP FUNCTION sales_summary (int, float)

DROP SPECIFIC FUNCTION products.inventory_level


FUNCTION MAPPING function_mapping_name

Drops the named function mapping.


INDEX [EXTENSION] index_name [RESTRICT]

Drops the named index or, optionally, an index extension, as long as it is not a primary key or unique constraint. You should use ALTER TABLE to drop a primary key or unique constraint. RESTRICT is mandatory when dropping an index extension.


[SPECIFIC] METHOD method_name [ (datatype [,...] )]

 


[FOR type_name ][RESTRICT]

Drops the named method body or specific method body, except those implicitly created by CREATE TYPE. The method specification remains as part of the definition of the subject type, unless removed with ALTER TYPE DROP METHOD. You may alternately use the syntax DROP METHOD method_body_name (data type1 [,...]) to further identify the method via datatypes. The FOR type_name clause must be specified when SPECIFIC is not specified in order to name the type where the method will be dropped. All dependencies on a method must be dropped before the method can be dropped.


NICKNAME nickname

Drops the named nickname. Certain other dependent objects are also dropped, including materialized query tables, index specifications, views (not dropped but marked inoperable), and packages (not dropped but marked inoperable).


DATABASE PARTITION GROUP db_prtn_name

Drops the named database partition group, and all tablespaces and subordinant objects defined under it (such as tables, packages, constraints, etc.) are dropped or marked inoperable. You should drop any tablespaces from the database partition group first. For example:

DROP TABLESPACE sales_2004

DROP TABLESPACE sales_2003

DROP DATABASE PARTITION GROUP sales_archive_0304


PACKAGE package_name [VERSION version_id]

Drops the named package of schema_name.package_id. You may also optionally add the clause VERSION version_id after the package_id to further identify the package.


[SPECIFIC] PROCEDURE procedure_name [ (datatype1 [,...] )] [RESTRICT]

Drops the named procedure or specific procedure. DB2 allows multiple procedures with the same name, each distinguished by their different datatype usage. You may alternately identify the procedure to drop via the syntax DROP PROCEDURE procedure_name (datatype [,...]) syntax.


SCHEMA schema_name RESTRICT

Drops the named schema. The RESTRICT keyword requires that the schema be empty before it can be dropped.


SEQUENCE sequence_name [RESTRICT]

Drops the named sequence from the server. However, you cannot drop a sequence created for an IDENTITY column using the DROP SEQUENCE statement.


SERVER server_name

Drops the definition of a named data source from the catalog as well as all nicknames for objects residing on the remote server. In addition, index specifications, user-defined functions, user-defined type mappings, and user mappings dependent on the remote server are dropped. Packages and function mappings dependent on the remote server are invalidated.


TABLE [HIERARCHY] table_name

Drops the named base table, declared temporary table, materialized query table, or staging table from the server. Indexes, constraints, materialized query tables, and staging tables that reference a dropped table are also dropped. Subtables of a typed table are not automatically dropped and must be dropped before the parent table can be dropped. Views, packages, and triggers that reference the dropped table are rendered inoperable. Any DATALINK columns are unlinked, though asynchronously. The HIERARCHY option is used to drop a named type table hierarchy (i.e., both the parent table and all of its subtables). In this syntax, the object_name is the name of the root table in the typed table hierarchy. A table cannot be dropped if it has the RESTRICT ON DROP attribute.


TABLESPACE[S] tablespace_name [,...]

Drops one or more named tablespaces and all objects from those tablespaces, unless a table stored in the tablespace spans the tablespace to be dropped and at least one of the tablespaces spanned, or the table has the RESTRICT ON DROP property. The TABLESPACE keyword and the TABLESPACES keyword are synonyms.


TRANSFORM[S] {ALL | group_name} FOR type_name

Drops all transform groups for a user-defined datatype using the syntax DROP TRANSFORM ALL FOR datatype_name. Note that only the transform group and not the user-defined datatype are dropped. Alternately, use the syntax DROP TRANSFORM transform_group_name FOR datatype_name to drop a single transform group from a user-defined datatype. For example:

DROP TRANSFORM sales_calcs FOR orders


TRIGGER trigger_name

Drops the named trigger. This may also cause certain packages to be marked invalid.


[DISTINCT] TYPE type_name [RESTRICT]

Drops the named user-defined type or, with the optional DISTINCT keyword, drops the named distinct type. Using the optional RESTRICT keyword prevents the type from being dropped, if the type has any dependency such as being used in a table definition or in a view, has subtypes, etc.


TYPE MAPPING type_mapping_name

Drops the named user-defined type mapping, though no other subordinant objects are dropped.


USER MAPPING FOR {user_name | USER} SERVER server_name

Drops the user mapping to a federated server for a named user. If no server is specified, all user mappings are dropped for the named user. For example, the user Dylan no longer needs the oracle50 data source:

DROP USER MAPPING FOR dylan SERVER oracle50


VIEW [HIERARCHY] view_name

Drops the named view from the schema. If the view is a parent object, then all subviews must be dropped before the parent view. Other objects that directly or indirectly depend on the view, such as triggers or materialized query tables, are marked inoperable. The optional HIERARCHY keyword tells DB2 to drop a parent typed view and all of its subviews.


WRAPPER wrapper_name

Drops the named wrapper as well as any server definitions, user-defined function mappings, and user-defined datatype mappings. This can cause a cascading action when dropping a server definition because objects dependent on the server definition (things like user mappings and nicknames) are also dropped. If the server definition results in a nickname being dropped, then objects dependent on the nickname (like views or packages) become inoperable.


RESTRICT

Optionally allowed on FUNCTION, SPECIFIC FUNCTION, METHOD, SPECIFIC METHOD, PROCEDURE, SPECIFIC PROCEDURE, SEQUENCE, TYPE, and DISTINCT TYPE. Mandatory for INDEX EXTENSION and SCHEMA. Like the ANSI standard, RESTRICT prevents the object from being dropped if a dependant object exists. The RESTRICT behavior is the default.

If you do not specify a schema along with the object name when performing a drop, DB2 will assume the current schema in dynamic SQL statements. DB2 will apply the QUALIFIER precompile/bind option for static SQL statements.

MySQL

MySQL supports a very limited number of objects via the CREATE/ALTER statement. Consequently, the syntax for DROP is also limited, as in the following:

DROP { DATABASE | [TEMPORARY] TABLE | INDEX } object_name [,...] 

     [ON table_name]

[IF EXISTS] object_name [,...] [RESTRICT |CASCADE]

The syntax elements are:


DATABASE database_name

Drops the named database, including all the objects it contains, such as tables and indexes. The DROP DATABASE command removes all database and table files from the filesystem, as well as two-digit subdirectories. MySQL will return a message showing how many files were erased from the database directory. (Files of these extentions are erased: .BAK, .DAT, .frm, .HSH, .ISD, .ISM, .MRG, .MYD, .MYI, .dm, and .fm.) If the database is linked, both the link and the database are erased. You may only drop one database at a time. RESTRICT and CASCADE are not valid on DROP DATABASE.


[TEMPORARY] TABLE table_name [,...]

Drops one or more named tables, with table names separated from each other by commas. MySQL erases each table's definition and deletes the three table files from the filesystem (.frm, .MYD, and .MYI). Issuing this command causes MySQL to commit all active transactions. The TEMPORARY keyword drops only temporary tables without committing running transactions or checking access rights.


INDEX index_name ON table_name

Drops the named index from the named table on Version 3.22 or later. This command doesn't do anything on versions earlier than 3.22, but on 3.22 it actually executes an ALTER TABLE...DROP INDEX command behind the scenes. You cannot use RESTRICT, CASCADE, or IF EXISTS with a DROP INDEX statement.


RESTRICT | CASCADE

Acts as noise. These keywords do not generate an error by MySQL, nor do they do anything.


IF EXISTS

Prevents an error message when attempting to drop an object that does not exist. Usable in MySQL Version 3.22 or later.

MySQL supports only the ability to drop a database, a table (or tables), or an index from a table. Although the DROP statement will not fail with the RESTRICT and CASCADE optional keywords, they also don't do anything. You can use the IF EXISTS clause to prevent MySQL from returning an error message by trying to delete an object that doesn't exist.

Oracle

Oracle supports most of the ANSI keywords for the DROP statements, as well as many additional keywords corresponding to objects uniquely supported by Oracle, as follows:

DROP {CLUSTER | CONTEXT | DATABASE | DATABASE LINK | DIMENSION |

      DIRECTORY | FUNCTION | INDEX | INDEXTYPE | JAVA |

      LIBRARY | MATERIALIZED VIEW | MATERIALIZED VIEW LOG |

      OPERATOR | OUTLINE | PACKAGE | PROCEDURE | PROFILE |

      ROLE | ROLLBACK SEGMENT | SEQUENCE | SYNONYM | TABLE |

      TABLESPACE | TRIGGER | TYPE | TYPE BODY | USER | VIEW }

      object_name

The rules for Oracle DROP statements are less consistent than the ANSI standard's rules, so the full syntax of each DROP variant is shown below:


CLUSTER cluster_name [INCLUDING TABLES [CASCADE CONSTRAINTS] ]

Drops the named cluster from the database. (Note that this drops a cluster; it does not uncluster a specific table from a cluster.) INCLUDING TABLES drops all tables that belong to the cluster. CASCADE CONSTRAINTS drops all referential integrity constraints that refer to the tables in the cluster. DROP CLUSTER will fail without CASCADE CONSTRAINTS when tables outside of the cluster have constraints (like a primary or foreign key) that refer to tables in the cluster. For example:

DROP CLUSTER hr INCLUDE TABLES CASCADE CONSTRAINTS;


CONTEXT namespace

Drops the named context from the database. Users currently in the namespace are unaffected, but will be unable to access the context when they next attempt to use that context. For example:

DROP CONTEXT hr_context


DATABASE

Drops a database from the Oracle server.

[PUBLIC] DATABASE LINK database_link_name

Drops the named database link from the database. You must include the PUBLIC keyword to drop a public database link. Note that the database link cannot be schema qualified. For example, to drop the database link called hq.southeast.tenn:

DROP DATABASE LINK hq.southeast.tenn;


DIMENSION dimension_name

Drops the named dimension. This does not invalidate materialized views built on the dimension, though they may execute more slowly and query requests may be rewritten.


DIRECTORY directory_name

Drops the named directory object from the database. This should not be used on directories containing files accessed by PL/SQL or OCI programs. For example, you could drop the image_files directory:

DROP DIRECTORY image_files;


FUNCTION function_name

Drops the named function, as long as it is not a component of a package. If you want to drop a function from a package, use the CREATE PACKAGE...OR REPLACE statement to redefine the package without the function you want to be rid of. Any local objects that depend on or call the function are invalidated and any statistical types associated with the function are disassociated.


INDEX index_name [FORCE]

Drops a named index or domain index from the database. Dropping an index invalidates all objects that depend on the parent table, including views, packages, functions, and stored procedures. Dropping an index invalidates cursors and execution plans that use the index, and will force a hard parse of the affected SQL statements when they are next executed.

Non-IOT indexes are secondary objects and can be dropped and recreated without any loss of user data. IOTs, because they combine both table and index data in the same structure, cannot be dropped and recreated in this manner. IOTs should be dropped using the DROP TABLE syntax.

When you drop a partitioned index, all partitions are dropped. When you drop a composite-partitioned index, all index partitions and subpartitions are dropped. When you drop a domain index, any statistics associated with the domain index are removed and any statistic types are disassociated. The optional keyword FORCE applies only when dropping domain indexes. FORCE allows you to drop a domain index marked IN PROGRESS, or to drop a domain index when its indextype routine invocation returns an error. For example:

DROP INDEX ndx_sales_salesperson_quota;


INDEXTYPE indextype_name [FORCE]

Drops the named indextype along with any associated statistic types. Oracle also drops any statistics collected with the statistics type. The optional keyword FORCE drops the indextype even when it is currently referenced by one or more domain indexes and marks the applicable domain indexes as INVALID. If you do not use FORCE on an indextype that is referenced by one or more domain indexes, the statement will fail. For example:

DROP INDEXTYPE imageindextype FORCE;


JAVA {SOURCE | CLASS | RESOURCE} "java_object_name"

Drops the named Java source, Java class, or Java resource schema object. SOURCE drops the named Java source schema object and all Java class schema objects derived from it. CLASS drops the named Java class schema object. RESOURCE drops the named Java resource schema object. For example, to drop the Java source MyJavaSource and all dependent schema objects:

DROP JAVA SOURCE "MyJavaSource";


LIBRARY library_name

Drops the named external procedure library.


{MATERIALIZED VIEW | SNAPSHOT} mview_name

Drops the named materialized view. You can use the keyword SNAPSHOT as an alternative to MATERIALIZED VIEW for backward compatibility. You must have privileges to drop the table plus views and indexes that make up the materialized view. Note that if you drop a parent table, any materialized views built upon it are not automatically dropped. But Oracle will return an error when a refresh is attempted on a materialized view whose parent table has been dropped. For example, we can drop a materialized view called salespeople_at_quota:

DROP MATERIALIZED VIEW salespeople_at_quota;


{MATERIALIZED VIEW | SNAPSHOT} LOG ON parent_table_name

Drops the named materialized view log that resides on the parent table (also known as the master table). You can use the statement DROP SNAPSHOT as an alternative to DROP MATERIALIZED VIEW for backward compatibility. RowID, primary key, and subquery materialized views can no longer be fast refreshed after the materialized view log has been dropped.


OPERATOR operator_name FORCE

Drops the named user-defined operator from the database. The optional keyword FORCE allows you to drop the operator even if it is referenced by other schema objects such as triggers, packages, user-defined functions, and so forth. In that case, the dependent objects become invalid. Dropping a user-defined operator with dependents without the FORCE keyword will result in an error.


OUTLINE outline_name

Drops the named stored outline from the database. The optimizer will generate new query plans for any SQL statements that used the stored outline after it is dropped.


PACKAGE [BODY] package_name

Drops the named package body and specification. The optional keyword BODY drops only the body of the package, but leaves the specification unaltered. This option is useful if you do not want to invalidate dependent objects, though you cannot call any components of the package until the package body is recreated. Otherwise, if you drop both body and specification, Oracle invalidates all dependent objects. (Note that if you want to drop a single object from a package, you should use the statement CREATE PACKAGE [BODY]...OR REPLACE.) The following examples drop first the package body and specification of the sales_quota_calc package, and then drop only the body of the regional_sales_calc package:

DROP PACKAGE sales_quota_calc;

DROP PACKAGE BODY regional_sales_calc;


PROCEDURE procedure_name

Drops the named stored procedure. Any dependent objects are invalidated when you drop a stored procedure. Dependent objects will fail with an error if they are accessed before you recreate the stored procedure. If you recreate the stored procedure, and a dependent object is accessed, the dependent object will be recompiled.


PROFILE profile_name [CASCADE]

Drops the named profile. The optional keyword CASCADE removes the profile from any users who were granted the profile. CASCADE is only required if the profile has been granted to one or more users. Users who no longer have a profile are then assigned the DEFAULT password. For example, the following statement drops the web_user profile and removes it from all users:

DROP PROFILE web_user CASCADE;


ROLE role_name

Drops the named role, removes it from the database, and revokes it from all users and roles where it has been granted. No new sessions can use the role, but sessions that are currently running under the role are not affected. For example, the following statement drops the sales_mgr role:

DROP ROLE sales_mgr:


ROLLBACK SEGMENT rbseg_name

Drops the named rollback segment and returns its space to the tablespace where the rollback segment was assigned. The rollback segment must be on-line and may not be the SYSTEM rollback segment. (Note that in Automatic Undo Management mode, you can only drop rollback segments. You cannot create or alter them.) For example, the following statement drops the rollback segment named rbseg_sales_tblspc:

DROP ROLLBACK SEGMENT rbseg_sales_tblspc;


SEQUENCE sequence_name

Drops the named sequence. (Note that the only way to restart a sequence is to drop it and recreate it.)


[PUBLIC] SYNONYM synonym_name [FORCE]

Drops the named private or PUBLIC synonym. (Note that the only way to redefine a synonym is to drop it and recreate it.) You cannot specify a schema when dropping a PUBLIC synonym. Materialized views become invalid when you drop their synonym. The optional keyword FORCE allows you to drop a synonym even if it has dependent tables or user-defined types. Otherwise, you cannot drop a synonym with dependent tables or user-defined types. Oracle discourages the use of FORCE. For example, you could drop the public synonym called users:

DROP PUBLIC SYNONYM users;


TABLE table_name [CASCADE CONSTRAINTS] [PURGE]

Drops the named table, erases all of its data, drops all indexes and triggers built from the table (even those in other schemas), and invalidates all permissions and all dependent objects (like views, stored procedures, etc.). On partitioned tables, Oracle drops all their partitions (and subpartitions). On index-organized tables, Oracle drops all dependent mapping tables. Statistic types associated with a dropped table are disassociated. Materialized view logs built on a table are also dropped when the table is dropped.

The DROP TABLE statement is effective for standard tables, index-organized tables, and object tables. The table being dropped is only moved to the recycling bin, unless you add the optional keyword PURGE, which tells Oracle to immediate free all space consumed by the table. (Oracle also supports a non-ANSI SQL command called PURGE that lets you remove tables from the recycling bin outside of the DROP TABLE statement.) DROP TABLE erases only the metadata of an external table. You must use an external operating system command to drop the file associated with an external table and reclaim its space.

Use the optional CASCADE CONSTRAINTS clause to drop all referential integrity constraints elsewhere in the database that depend on the primary or unique key of the dropped table. You cannot drop a table with dependent referential integrity constraints without using the CASCADE CONSTRAINTS clause. The following example drops the job_desc table in the emp schema, then drops the job table and all referential integrity constraints that depend on the primary key and unique key of the job table:

DROP TABLE emp.job_desc;

DROP TABLE job CASCADE CONSTRAINTS;


TABLESPACE tablespace_name [INCLUDING CONTENTS [AND DATAFILES] [CASCADE CONSTRAINTS]

Drops the named tablespace (preferably when it is offline), deleting all datafiles and tempfiles. Oracle-managed datafiles and tempfiles in the tablespace are deleted from the filesystem, but datafiles and tempfiles managed by the OS can also be deleted by including the optional clause INCLUDING CONTENTS AND DATAFILES. Note that you cannot drop a tablespace when it contains a domain index, objects created by a domain index, data needed to roll back uncommitted transactions, or the SYSTEM tablespace. The optional clause INCLUDING CONTENTS drops all contents of the tablespace, and is required for any tablespace that contains database objects. The optional clause AND DATAFILES also drops associated operating system files. The optional clause CASCADE CONSTRAINTS drops all external referential integrity constraints that depend on the primary or unique keys of tables within the tablespace and is required when such dependencies exist. The first of the following examples drops the tablespace sales_tblspc and all dependent referential integrity constraints, while the second example drops the tablespace sales_images_tblspc and all associated operating system files:

DROP TABLESPACE sales_tblspc 

   INCLUDING CONTENTS CASCADE CONSTRAINTS;

DROP TABLESPACE sales_image_tblspc 

   INCLUDING CONTENTS AND DATAFILES;


TRIGGER trigger_name

Drops the named trigger from the database.


TYPE [BODY] type_name [ {FORCE | VALIDATE} ]

Drops the specification and body of the named object type, nested table type, or VARRAY, as long as they have no type or table dependencies. You must use the optional FORCE keyword to drop a supertype, a type with an associated statistics type, or a type with any sort of dependencies. All subtypes and statistic types are then invalidated. Oracle will also drop any public synonyms associated with a dropped type. The optional BODY keyword tells Oracle to drop only the body of the type while keeping its specification intact. Use the optional VALIDATE keyword when dropping subtypes to check for stored instances of the named type in any of its supertypes. Oracle then performs the drop only if no stored instances are found. For example:

DROP TYPE salesperson_type;


USER user_name [CASCADE]

Drops the named user from the database. By default, Oracle will not drop a user whose schema still owns objects. The optional keyword CASCADE tells Oracle to also remove all of the user's objects, as well as applicable dependent objects. Oracle does not drop objects from other users' schemas that reference those in the dropped schema, though it does invalidate them. For example, the following statement drops the user cody and all of his objects:

DROP USER cody CASCADE;


VIEW view_name [CASCADE CONSTRAINTS]

Drops the named view and marks as invalid any views, subviews, synonyms, or materialized views that refer to the dropped view. Use the optional clause CASCADE CONSTRAINTS to drop all referential integrity constraints that depend on the view. Otherwise, the DROP statement will fail if dependent referential integrity constraints exist. For example, the following statement drops the active_employees view in the hr schema:

DROP VIEW hr.active_employees;

In all of the syntax shown above, object_name can be replaced with [schema_name.]object_name. If you leave off the schema name, the default schema of the user session is assumed. Thus, the following DROP statement drops the specified view from the sales_archive schema:

DROP VIEW sales_archive.sales_1994;

However, if your personal schema is scott, then the following command is assumed to be against scott.sales_1994:

DROP VIEW sales_1994;

PostgreSQL

PosgreSQL does not support the RESTRICT or CASCADE optional keywords supported by the ANSI standard. It supports a wide variety of DROP variants, as follows:

DROP { AGGEGATE | DATABASE | FUNCTION | GROUP | INDEX |

       LANGUAGE | OPERATOR |RULE | SEQUENCE | TABLE | TRIGGER |

       TYPE | USER | VIEW } object_name

Following is the full syntax for each variant:


AGGEGATE aggregate_name ( {datatype | *} )

Drops the user-defined aggregate function. The value for datatype is the datatype of the existing aggregate function, but you may substitute an asterisk ( * ) to match any input datatype. For example, we can drop an aggregate function called sales_avg we made using PostgreSQL's CREATE AGGREGATE statement:

DROP AGGREGATE sales_avg(int4);


DATABASE database_name

Drops the named database and erases the operating system directory containing all of the database's data. This command can only be executed by the database owner while connected to a database other than the target database. For example, we can drop the sales_archive database:

DROP DATABASE sales_archive;


FUNCTION function_name ( [datatype1 [,...] )

Drops the named user-defined function. Since PostgreSQL allows multiple functions of the same name distinguished only by the various input parameters they require, you must specify one or more datatypes to uniquely identify the user-defined function you wish to drop. PostgreSQL does not perform any kind of dependency checks on other objects that might reference a dropped user-defined function. (They will fail when invoked against an object that no longer exists.) For example:

DROP FUNCTION median_distribution (int, int, int, int);


GROUP group_name

Drops the named group, though it does not affect users who were in the group. This is similar to DROP ROLE on other database platforms.


INDEX index_name [,...]

Drops one or more named indexes that you own. For example:

DROP INDEX ndx_titles, ndx_authors;


[PROCEDURAL] LANGUAGE language_named

Drops the named user-defined procedural language. You can optionally enclose the name in single quotes. Note that PostgreSQL does not check to see if any user-defined functions or triggers written in the named language still exist in the database. For example:

DROP LANGUAGE php;


OPERATOR operator_id ( {left_datatype | NONE }, {right_datatype | NONE } )

Drops a named user-defined operator where the value of left_datatype is the operator's left argument and right_datatype is the operator's right argument. NONE may be substituted for either argument when there is no argument in that position. (PostgreSQL does not check for any dependent access methods or operator classes that rely on the dropped operator. You should check for them and drop them manually to avoid errors when they are invoked.) For example, the first of the following statements drops the power operator, and the second drops the unary negation operator:

DROP OPERATOR ^ (int4, int4);

DROP OPERATOR ! (NONE, bool);


RULE rule_name [,...]

Drops one or more named rules from the database. PostgreSQL then immediately stops enforcing the rules and erases historical data about the rules. For example:

DROP RULE phone_rule;


SEQUENCE seq_name [,...]

Drops one or more named sequences from the database. Since the current version of PostgreSQL treats sequences as special tables, the DROP SEQUENCE statement works very much like the DROP TABLE statement.


TABLE table_name [,...]

Drops one or more existing tables from the database, as well as any indexes or triggers specified for the table. For example, you can drop more than one table in a single statement:

DROP TABLE authors, titles;


TRIGGER trigger_name ON table_name

Drops the named trigger from the database. Since PostgreSQL requires that trigger names be unique only on the table they are attached to, it is possible to have many triggers called, say, insert_trigger or delete_trigger, each on a different table. For example:

DROP TRIGGER insert_trigger ON authors;


TYPE type_name [,...]

Drops one or more pre-existing user-defined types from the database. PostgreSQL does not check to see what impact the DROP TYPE command might have on any dependent objects like functions, aggregates, or tables. You must check dependent objects manually. (Do not remove any of the built-in types that ship with PostgreSQL!) Note that PostgreSQL's implementation of types differs from the ANSI standard. Refer to the CREATE/ALTER TYPE Statement section for more information.


USER user_name

Drops the named user from the current database. This command does not drop any objects owned by the user, such as tables or views, but will fail if the user owns any databases. For example:

DROP USER emily;


VIEW view_name [,...]

Drops one or more pre-existing views from the database.

Note that PostgreSQL drop operations do not allow you to specify the target database where the operation will take place (except for DROP DATABASE). Therefore, you should execute any drop operation from the database where the object you want to drop is located.

SQL Server

SQL Server supports several standard variants of the DROP statement. SQL Server's main difference compared to the ANSI DROP statement is the ability to drop multiple objects with a single statement:

DROP { DATABASE | DEFAULT | FUNCTION | INDEX | PROCEDURE |

     RULE |  STATISTICS | TABLE | TRIGGER | TYPE | VIEW } object_name

Following is the full syntax for each variant:


DATABASE database_name [,...]

Drops the named database(s) and erases all disk files used by the database(s). This command may only be issued from the master database. Replicated databases must be removed from their replication schemes before they can be dropped, as must log shpping databases. You cannot drop a database while it is in use, nor can you drop system databases (master, model, msdb, or tempdb). For example, we can drop the northwind and pubs databases with one command:

DROP DATABASE northwind, pubs

GO


DEFAULT default_name [,...]

Drops one or more user-defined defaults from the current database. Note that this does not drop DEFAULT constraints, only user-defined defaults created with the CREATE DEFAULT statement. (You can drop default constraints using the statement ALTER TABLE...DROP CONSTRAINT.) When dropping a default from a column, null values will be inserted into columns that accept null. Otherwise, if a column does not accept nulls, an error is raised and no values are entered into the column. If a column or user-defined datatype being dropped is bound, then you must first unbind it using the SQL Server system stored procedure sp_unbindefault. In the following two examples, we first drop a user-defined default and then unbind and drop the user-defined default:

DROP DEFAULT sales_date_default

GO



EXEC sp_unbindefault 

'sales.ord_date'

DROP DEFAULT order_date_default

GO


FUNCTION [schema.]function_name [,...]

Drops one or more user-defined functions from the current database.


INDEX table_or_view_name.index_name [,...]

Drops one or more indexes from tables or indexed views in the current database and returns space to the database. This statement should not be used to drop a PRIMARY KEY or UNIQUE constraint. Instead, drop these constraints using the ALTER TABLE...DROP CONSTRAINT statement. When dropping a clustered index from a table, all non-clustered indexes are rebuilt. When dropping a clustered index from a view, all non-clustered indexes are dropped.


PROCEDURE procedure_name [,...]

Drops one or more stored procedures from the current database. SQL Server allows multiple versions of a single procedure via a version number, but these versions cannot be dropped individually. You must drop all versions of a stored procedure at once. System procedures (those with an sp_ prefix) are dropped from the master database if they are not found in the current user database. For example:

DROP PROCEDURE calc_sales_quota

GO


RULE rule_name [,...]

Drops one or more user-defined rules from the current database. Existing data in columns governed by a rule are not checked when the rule is dropped. You may need to unbind the rule first using the SQL Server system stored procedure sp_unbindefault. In the following two examples, we first drop a user-defined rule, and then unbind and drop the user-defined rule:

DROP RULE phone_rule

GO



EXEC sp_unbindrule 'authors.phone'

DROP RULE phone_rule

GO


STATISTICS table_or_view_name.statistics_name [,...]

Drops statistics on one or more collections from a table or indexed view in the current database. Dropping statistics can have a big impact on query performance, since they help the query optimizer choose the best query plan. (Statistics are created with the CREATE INDEX and CREATE STATISTICS statements. You can update statistics with the UPDATE STATISTICS statement or retrieve information about them with the statement DBCC SHOW_STATISTICS.) For example, we'll create statistics on two columns in two separate tables and then drop the statistics:

CREATE STATISTICS title_stats ON sales (title_id, ord_num)

   WITH SAMPLE 30 PERCENT

GO

CREATE STATISTICS zip_stats ON stores (zip)

   WITH FULLSCAN

GO

DROP STATISTICS sales.title_stats, stores.zip_stats

GO


TABLE table_name

Drops a named table and all data, permissions, indexes, triggers, and constraints specific to that table. (The table_name may be a fully qualified table name like pubs.dbo.sales or a simple table name, like sales, if the current database and owner are correct.) Views, functions, and stored procedures that reference the table are not dropped or marked as invalid, but will return an error when their procedural code encounters the missing table. Be sure to drop these yourself! You cannot drop a table referenced by a FOREIGN KEY constraint without first dropping the constraint. Similarly, you cannot drop a table used in replication without first removing it from the replication scheme. Any user-defined rules or defaults are unbound when the table is dropped. They must be rebound if the table is recreated.


TRIGGER trigger_name [,...]

Drops one or more triggers from the current database.


TYPE type_name [,...]

Drops one or more user-defined types from the current database.


VIEW view_name [,...]

Drops one or more views from the database, including indexed views, and returns all space to the database.

See Also

CALL
CONSTRAINTS
CREATE/ALTER FUNCTION/PROCEDURE/METHOD
CREATE SCHEMA
CREATE/ALTER TABLE
CREATE/ALTER VIEW
DELETE
DROP
GRANT
INSERT
RETURN
SELECT
SUBQUERY
UPDATE
EXCEPT Set Operator

The EXCEPT set operator retrieves the result sets of two or more queries including all the records retrieved by the first query that are not also found in subsequent queries. Whereas JOIN clauses are used to return the rows of two or more queries that are in common, EXCEPT is used to filter out the records that are present in only one of multiple, but similar, tables.

EXCEPT is in a class of keywords called a set operator. Other set operators include INTERSECT and UNION. (MINUS is Oracle's equivilent to the EXCEPT keyword. EXCEPT is the ANSI standard.) All set operators are used to simultaneously manipulate the result set of two or more queries, hence the term "set operators."

Platform

Command

DB2

Supported, with limitations

MySQL

Not supported

Oracle

Supported,with limitations

PostgreSQL

Supported, with limitations

SQL Server

Not supported


SQL2003 Syntax

There are technically no limits to the number of queries that you may combine with the EXCEPT operator. The general syntax is:

{SELECT statement1 | VALUES (expr1 [,...] ) }

EXCEPT [ALL | DISTINCT]

[CORRESPONDING [BY (column1, column2, ...)] ]

{SELECT statement2 | VALUES (expr2 [,...] ) }

EXCEPT [ALL | DISTINCT]

[CORRESPONDING [BY (column1, column2, ...)] ]

...

Keywords


VALUES (expr1 [,...] )

Generates a derived result set with explicitly declared values as expression1, expression2, etc. It is essentially a SELECT statement result set without the SELECT...FROM syntax. This is known as a row constructor, since the rows of the result set are manually constructed. According to the ANSI standard, mutliple, hand-coded rows in a row constructor must be enclosed in parentheses and separated by commas.


EXCEPT

Determines which rows will be excluded from the single result set.


ALL

Considers duplicate rows from all result sets.


DISTINCT

Drops duplicate rows from all result sets prior to the EXCEPT comparison. Columns containing a NULL value are considered duplicates. (If neither ALL nor DISTINCT are used, DISTINCT behavior is the default.)


CORRESPONDING [BY] (column1, column2, ...)

Specifies that only columns with the listed names are returned, even if one or both queries use the asterisk shortcut.

Rules at a Glance

There is only one significant rule to remember when using EXCEPT:

The order, number, and datatypes of columns should be of the same category in all queries

The datatypes do not have to be identical, but they must be compatible. For example, CHAR and VARCHAR are compatible datatypes. By default, the result set will default to the largest datatype size of each column in each ordinal position. For example, a query retrieving from columns containing a VARCHAR(10) and a VARCHAR(15) column will use the VARCHAR(15) datatype and size.

Programming Tips and Gotchas

None of the platforms support the CORRESPONDING [BY column1, column2, ...] clause.

On platforms that do not support EXCEPT, you might substitute a NOT IN subquery. However, NOT IN subqueries have different NULL handling and, on some database platforms, produce different result sets.


According to the ANSI standard, the UNION and EXCEPT set operators evaluate with equal precedence. However, the INTERSECT set operator evaluates first before the other set operators. We recommend that you explicitly control the precedence of set operators, using parentheses as a general best practice.

According to the ANSI standard, only one ORDER BY clause is allowed in the entire query. Include it at the end of the last SELECT statement. In order to avoid column and table ambiguity, be sure to alias each column for each table with the same respective alias. For example:

SELECT au_lname AS 'lastname', au_fname AS 'firstname'

FROM authors

EXCEPT

SELECT emp_lname AS 'lastname', emp_fname AS 'firstname'

FROM employees

ORDER BY lastname, firstname

Also, while each of your column lists may list columns with correspondingly compatible datatypes, there may be some variation in behavior across the DBMS platforms with regard to varying length of the columns. For example, if the au_lname column in the previous example's first query is markedly longer than the emp_lname column in the second query, each platform may apply different rules as to which length is used for the final result. In general, though, the platforms will choose the longer (and less restrictive) column size for use in the result set.

Each DBMS may apply its own rules as to which column name is used if the names vary across column lists. In general, the column names of the first query are used.

DB2

DB2 supports the EXCEPT and EXCEPT ALL keywords of the ANSI standard, plus the VALUES extension:

{ SELECT statement1 | VALUES (expression1, expression2 [,...] ) }

EXCEPT [ALL]

{ SELECT statement2 | VALUES (expression1, expression2 [,...] ) }

EXCEPT [ALL]

...

where:


VALUES

Allows you to specify one or more hand-coded rows to include in the final result set. (This is known as a row constructor.) The VALUES clause must specify the exact same number of columns as the queries in the EXCEPT.

Although EXCEPT DISTINCT is not supported, EXCEPT is the functional equivalent. The CORRESPONDING clause is not supported. In addition, the datatypes LONG VARCHAR, LONG VARGRAPHIC, BLOB, CLOB, DBCLOB, DATALINK, and the structured types are not usable with EXCEPT, but are useable with EXCEPT ALL.

When the result set has the same column name for a given column across all SELECT statements, then that name is used as the final column name returned by the statement. If, however, the given column is named differently in different SELECT statements, then you must rename the column in each query using the same AS alias_name.

If multiple set operations are used in a single query, those enclosed in parentheses are evaluated first. Then, the queries are evaluated in left-to-right order. However, all INTERSECT operations are performed before any UNION and EXCEPT operations.

For example:

(SELECT empno

   FROM   employee

   WHERE  workdept LIKE 'E%'

 EXCEPT

 SELECT empno

   FROM   emp_act

   WHERE  projno IN ('IF1000', 'IF2000', 'AD3110')  )

UNION

VALUES ('AA0001'), ('AB0002'), ('AC0003')

The example above retrieves all IDs for all employees from the employee table who are in any department that starts with "E," then it excludes any employee IDs from the employee accounts (emp_act) table representing employees working in the projects IF1000, IF200', and AD3110. Finally, it adds in three extra employee IDs - AA0001, AB0002, and AC0003 using the UNION set operator.

MySQL

EXCEPT is not supported in MySQL. However, you can use the NOT IN or NOT EXISTS operations as alternatives.

Oracle

Oracle does not support the EXCEPT set operator. However, it has an alternative set operator, MINUS, with identical functionality.

<SELECT statement1>

MINUS

<SELECT statement2>

MINUS

...

MINUS DISTINCT and MINUS ALL are not supported. MINUS is the functional equivalent of MINUS DISTINCT. Oracle does not support MINUS on queries under the following circumstances:

  • Queries containing columns of LONG, BLOB, CLOB, BFILE, or VARRAY datatypes

  • Queries containing the FOR UPDATE clause

  • Queries containing TABLE collection expressions

If the first query in a set operation contains any expressions in the select item list, then include AS clauses to associate aliases with those expressions. Also, only the last query in the set operation may contain an ORDER BY clause.

For example, you could generate a list of all store IDs that do not have any records in the sales table:

SELECT stor_id FROM stores

MINUS

SELECT stor_id FROM sales

The MINUS command is functionally similar to a NOT IN query. The following query would retrieve the same results as the earlier query:

SELECT stor_id FROM stores

WHERE stor_id NOT IN

   (SELECT stor_id FROM sales)

PostgreSQL

PostgreSQL supports the EXCEPT and EXCEPT ALL set operators using the basic ANSI SQL syntax:

<SELECT statement1>

EXCEPT [ALL]

<SELECT statement2>

EXCEPT [ALL]

...

PostgreSQL does not support EXCEPT or EXCEPT ALL on queries with a FOR UPDATE clause. PostgreSQL does not support the CORRESPONDING clause. EXCEPT DISTINCT is not supported, but EXCEPT is the functional equivalent.

The first query in the set operation may not contain an ORDER BY clause or a LIMIT clause. Subsequent queries in the EXCEPT or EXCEPT ALL set operation may contain these clauses, but such queries must be enclosed in parentheses. Otherwise, the right-most occurence of ORDER BY or LIMIT will be applied to the entire set operation.

PostgreSQL evaluates SELECT statements in a multi-EXCEPT statement from top to bottom unless you use parentheses to change the evaluation hierarchy of the statements.

Normally, duplicate rows are eliminated from the two result sets, unless you add the ALL keyword. For example, you could find all titles in the authors table that have no records in the sales table:

SELECT title_id

FROM   authors

EXCEPT ALL

SELECT title_id

FROM   sales;

SQL Server

EXCEPT is not supported. However, you can use NOT IN or NOT EXISTS operations in conjunction with a correlated subquery as alternatives. The following queries are examples of how you can achieve EXCEPT functionality using NOT EXISTS and NOT IN:

SELECT DISTINCT a.city

FROM pubs..authors AS a

WHERE NOT EXISTS

   (SELECT *

    FROM pubs..publishers AS p

    WHERE a.city = p.city)

SELECT DISTINCT a.city

FROM pubs..authors AS a

WHERE a.city NOT IN

   (SELECT p.city

    FROM pubs..publishers AS p

    WHERE p.city IS NOT NULL)

In general, NOT EXISTS is faster than NOT IN. In addition, there is a subtle issue with NULLs that differentiates the IN and NOT IN operators and the EXISTS and NOT EXISTS set operator. In order to get around this different handling of NULLs, simply add the IS NOT NULL clause to the WHERE clause, as we have in the preceding example.

See Also

INTERSECT
SELECT
UNION
EXISTS Operator

The EXISTS operator tests a subquery for the existence of rows.

Platform

Command

DB2

Supported

MySQL

Supported

Oracle

Supported

PostgreSQL

Supported

SQL Server

Supported


SQL2003 Syntax

SELECT ...

WHERE [NOT] EXISTS (subquery)

The parameters and keywords are as follows:


WHERE [NOT] EXISTS

Tests the subquery for the existence of one or more rows. If even one row satisfies the subquery clause, it returns a Boolean TRUE value. The optional NOT keyword returns a Boolean TRUE value when the subquery returns no matching rows.


subquery

Retrieves a result set based on a fully formed subquery.

Rules at a Glance

The EXISTS operator checks a subquery for the existence of one or more records against the records in the parent query.

For example, we want to see if we have any jobs where no employee is filling the position:

SELECT *

FROM jobs

WHERE NOT EXISTS

   (SELECT * FROM employee

     WHERE jobs.job_id = employye.job_id)

This example tests for the absence of records in the subquery using the optional NOT keyword. The next example looks for specific records in the subquery to retrieve the main result set:

SELECT au_lname

FROM authors

WHERE EXISTS

   (SELECT *

   FROM publishers

   WHERE authors.city = publishers.city)

This query returns the last name of authors who live in the same city as their publishers. Note that the asterisk in the subquery is acceptable, since the subquery only needs to return a single record to provide a Boolean TRUE value. Columns are irrelevant in these cases. The first example selects only a single column. The key point is whether a row exists.

Programming Tips and Gotchas

EXISTS, in many queries, does the same thing as ANY. EXISTS is usually most effective with correlated subqueries.

EXISTS is symantically equivalent to the ANY operator.


The EXISTS subquery usually searches for only one of two things. Your first option is to use the asterisk wildcard (e.g., SELECT * FROM...) so that you are not retrieving any specific column or value. In this case, the asterisk means "any column." The second option is to select only a single column in the subquery (e.g., SELECT au_id FROM...). Some individual database platforms allow a subquery against more than one column (e.g., SELECT au_id, au_lname FROM...). However, this feature is rare and should be avoided on code that needs to be transportable across platforms.

Platform Differences

All of the platforms support EXISTS in the manner described above.

See Also

ALL/ANY/SOME
SELECT
WHERE
FETCH Statement

The FETCH statement is one of four commands used in cursor processing, along with DECLARE, OPEN, and CLOSE. Cursors allow you to process queries one row at a time, rather than as a complete set. FETCH positions a cursor on a specific row and retrieves that row from the result set.

Cursors are especially important in relational databases because they are set-based, while most client-centric programming languages are row-based. So cursors allow you to perform operations a single row at a time, to better fit what a client program can do, rather than operate on a whole set of records at once.

Platform

Command

DB2

Supported, with limitations

MySQL

Not supported

Oracle

Supported, with limitations

PostgreSQL

Supported, with variations

SQL Server

Supported, with variations


SQL2003 Syntax

FETCH [ { NEXT | PRIOR | FIRST | LAST |

  { ABSOLUTE | RELATIVE  int } }

  FROM ] cursor_name

[INTO variable1 [, ...] ]

Keywords


NEXT

Tells the cursor to return the record immediately following the current row, and increments the current row to the row returned. FETCH NEXT is the default behavior for FETCH. It retrieves the first record if FETCH is performed as the first fetch against a cursor.


PRIOR

Tells the cursor to return the record immediately preceding the current row and decrements the current row to the row returned. FETCH PRIOR does not retrieve a record if it is performed as the first fetch against the cursor.


FIRST

Tells the cursor to return the first record in the cursor, making it the current row.


LAST

Tells the cursor to return the last record in the cursor, making it the current row.


ABSOLUTE int

Tells the cursor to return the int record from the cursor record set counting from the top (if int is a positive integer), or the int record counting from the bottom (if int is a negative integer), making the returned record the new current record of the cursor. If int is 0, no rows are returned. If the value of int moves the cursor past the end of the cursor result set, then the cursor is positioned after the last row (for a positive int) or before the first row (for a negative int).


RELATIVE int

Tells the cursor to return the record int rows after the current record (if int is positive) or int rows before the current record (if int is negative), making the returned record the new current row of the cursor. If int is 0, the current row is returned. If the value of int moves the cursor past the end of the cursor result set, then the cursor is positioned after the last row (for a positive int) or before the first row (for a negative int).


[FROM] cursor_name

Tells the name of the OPEN cursor where you want to retrieve rows. The cursor must be previously created and instantiated using the DECLARE and OPEN clauses. FROM is optional, but encouraged.


INTO variable1[, ...]

Stores data from each column in the open cursor into a local variable. Each column in the cursor must have a corresponding variable of a matching datatype in the INTO clause. Each column value is directly related to the variables in ordinal positions.

Rules at a Glance

At the highest level, a cursor must be:

  1. Created using DECLARE

  2. Opened using OPEN

  3. Operated against using FETCH

  4. Dismissed using CLOSE

By following these steps, you create a result set similar to that of a SELECT statement, except that you can operate against each individual row within the result set separately. For example, assume you've created and opened a cursor on a DB2 database called employee_cursor containing three columns:

DECLARE employee_cursor CURSOR FOR

SELECT lname, fname, emp_id

FROM employee

WHERE hire_date >= '2005-02-15';

OPEN employee_cursor;

You can now retrieve values from the cursor using FETCH:

FETCH FROM employee_cursor

INTO :emp_last_name, :emp_first_name, :emp_id

The FETCH statement allows you to position the current row within the cursor. Since you have not yet accessed the cursor in this example, you will be given the first record in the result set. You can then use any procedural code you want to operate against the values in that row.

Each database platform has its own rules about how variables are used. For example, DB2 requires a colon as a prefix on each variable, as shown in the earlier example; SQL Server requires an at sign (@), PostgreSQL and Oracle have no prefix, and so forth. Meanwhile, the SQL standard says that a colon prefix is necessary for languages that are embedded, like C or COBOL, but no prefix is needed for procedural SQL.


A cursor rests either directly on a row, before the first row, or after the last row. When a cursor is resting directly in a row, then that row is known as the current row. You can use cursors to position an UPDATE or DELETE statement in the current row using the WHERE CURRENT OF clause.

It is important to remember that a cursor result set does not wrap around. Thus if you have a result set containing 10 records and tell the cursor to move forward 12 records, it will not wrap back around to the beginning and continue its count from there. Instead, the default cursor behavior is to stop after the last record in the result set when scrolling forward, and to stop before the first record when scrolling back. For example, on SQL Server:

FETCH RELATIVE 12 FROM employee_cursor

INTO @emp_last_name, @emp_first_name, @emp_id

When fetching values from the database into variables, make sure that the datatypes and number of columns and the variables match. Otherwise, you'll get an error. For example:

FETCH PRIOR FROM employee_cursor

INTO @emp_last_name, @emp_id

The above example will fail since the employee_cursor contains three columns while the fetch operation has only two variables.

Programming Tips and Gotchas

The most common errors encountered with the FETCH statement are a mismatch of variables to the values in the cursor, whether that is in the exact number, order, or datatype. So take a little time to make sure you remember exactly what values are in the cursor and what their datatypes are.

Typically, the database will lock at least the current row and possibly all rows held by the cursor. According to the ANSI standard, cursor locks are not held through ROLLBACK or COMMIT operations, although this varies from platform to platform.

Although the FETCH statement is detailed in isolation here, it should always be managed as a group with the DECLARE, OPEN, and CLOSE statements. For example, every time you open a cursor, the server consumes memory. If you forget to close your cursors, you could create memory management problems. So make sure that every declared and opened cursor is eventually closed.

Cursors are also often used in stored procedures or batches of procedural code. The reason for this is because sometimes you need to perform actions on individual rows rather than on entire sets of data at a time. But because cursors operate on individual rows and not sets of data, they are often much slower than other means of accessing your data. Just make sure that you perform strong analysis on your approach. Many challenges, such as a convoluted DELETE operation or a very complex UPDATE, can be solved by using clever WHERE and JOIN clauses instead of cursors.

DB2

DB2 cursors are implicitly forward-only cursors that always scroll forward one record at a time. A DB2 cursor, when compared to the ANSI standard, is essentially a FETCH NEXT 1 cursor. DB2 does not support keywords like PRIOR, ABSOLUTE, and RELATIVE. DB2 FETCH syntax is:

FETCH [ FROM ] cursor_name

{ [INTO variable1 [, ...] ] |

  [USING DESCRIPTOR descriptor_name] }

where:


USING DESCRIPTOR descriptor_name

Identifies a previously created SQLDA (SQL Descriptor Area) called descriptor_name to contain zero or more of the retrieved values from the FETCH statement.

When saving fetched values INTO variables, DB2 allows LOB values to be inserted into regular host variables such as VARCHAR (when they are big enough to hold the value), locator variables, or file-reference variables.

When saving fetched values with the USING DESCRIPTOR clause, you should remember several rules about descriptor areas:

  • SQLN indicates the number of SQLVAR occurrences in the SQLDA.

  • SQLDABC indicates the number of bytes of storage allocated in the SQLDA.

  • SQLD indicates the number of variables used in the SQLDA when processing the statement. SQLD must be set to a value greater than or equal to zero and less than or equal to SQLN.

  • SQLVAR indicates the attributes of the variables. The descriptor needs enough storage to hold all SQLVAR occurrences. Use this formula to calculate the size of SQLDABC: it must be greater than or equal to 16 + SQLN*(n), where n is the length of SQLVAR occurrences.

  • When LOB or structured type result columns must be accommodated, use two SQLVAR entries for every select item (or column returned from the result table).

For example, the following FETCH statement uses an SQLDA:

FETCH employee_cursor USING DESCRIPTOR :sqlda2

In the above example, the descriptor :sqlda2 and the cursor employee_cursor must already exist.

MySQL

Not supported.

Oracle

Oracle cursors are implicitly forward-only cursors that always scroll forward one record at a time. An Oracle cursor, when compared to the ANSI standard, is essentially a FETCH NEXT 1 cursor. Oracle cursors must either insert the retrieved values into matching variables, or use the BULK COLLECT clause to insert all of the records of the result set into an array. Oracle does not support keywords like PRIOR, ABSOLUTE, and RELATIVE. However, Oracle does support both forward-only and scrollable cursors in the database via the Oracle Call Interface (OCI). OCI also supports features like PRIOR, ABSOLUTE, and RELATIVE for read-only cursors whose result set is based on a read consistent snapshot.

Oracle's FETCH syntax is:

FETCH cursor_name

{ INTO variable_name1 [,...] | BULK COLLECT INTO

    [collection_name [,...] [LIMIT int] }

where:


BULK COLLECT INTO collection_name

Retrieves the entire rowset, or a specified number of rows (see LIMIT), into a client-side array or collection variable named collection_name.


LIMIT int

Limits the number of records fetched from the database when using the BULK statement. The int value is a nonzero integer (or a variable representing an integer value).

Oracle supports dynamic SQL-based cursors whose text can be built at runtime. Oracle also supports cursor_names that may be any allowable variable, parameter, or host-array type. In fact, you may also use user-defined or %ROWTYPE record variables for the INTO clause as well. This allows you to construct flexible, dynamic cursors in a template-like structure.

For example:

DECLARE

   TYPE namelist IS TABLE OF employee.lname%TYPE;

   names namelist;

   CURSOR employee_cursor IS SELECT lname FROM employee;

BEGIN

   OPEN employee_cursor;

   FETCH employee_cursor BULK COLLECT INTO names;

   ...

   CLOSE employee_cursor;

END;

Oracle FETCH often is paired with a PL/SQL FOR loop (or other kind of loop) to cycle through all the rows in the cursor. You should use the cursor attributes %FOUND or %NOTFOUND to detect the end of the rowset. For example:

DECLARE

   TYPE employee_cursor IS REF CURSOR RETURN employee%ROWTYPE;

   employee_cursor  EmpCurTyp;

   employee_rec     employee%ROWTYPE;

BEGIN

   LOOP

      FETCH employee _cursor INTO employee_rec;

      EXIT WHEN employee _cursor%NOTFOUND;

      ...

   END LOOP;

CLOSE employee_cursor;

END;

This example uses a standard PL/SQL loop with an EXIT clause to end the loop when there are no more rows in the cursor to process.

PostgreSQL

PostgreSQL supports both forward and backward scrolling cursors. It covers the ANSI standard except ABSOLUTE, FIRST, or LAST. The syntax for FETCH in PostgreSQL is:

FETCH { [ FORWARD | BACKWARD | ABSOLUTE | RELATIVE] }

      { [int | ALL | NEXT | PRIOR ] }

{ IN | FROM } cursor_name

[ INTO :variable1 [,...] ]

where:


FORWARD

Tells PostgreSQL that the cursor scrolls forward. This is the default if no other mode is defined.


BACKWARD

Tells PostgreSQL that the cursor scrolls backward.


ABSOLUTE

Allowed as a keyword, but not supported in functionality.


RELATIVE

Allowed as a keyword, but not supported in functionality.


int

A signed integer that indicates how many records to scroll forward (if positive) or backward (if negative).


ALL

Retrieves all records remaining in the cursor.


NEXT

Retrieves the next single record.


PRIOR

Retrieves the previous single record.


IN | FROM cursor_name

Defines the previously declared and opened cursor where data is retrieved.


INTO variable

Assigns a cursor value to a specific variable. As with ANSI cursors, the values retrieved by the cursor and the variables must match in number and datatype.

PostgreSQL cursors must be used with transactions explicitly declared using BEGIN, and must be closed with COMMIT or ROLLBACK.

The following PostgreSQL statement retrieves five records from the employee table and displays them:

FETCH FORWARD 5 IN employee_cursor;

It is important to note that PostgreSQL also supports a separate command, MOVE, to move to a specific cursor position. It differs from FETCH only by not returning values into variables:

MOVE { [ FORWARD | BACKWARD | ABSOLUTE | RELATIVE] }

     { [int | ALL | NEXT | PRIOR ] }

{ IN | FROM } cursor_name

For example, the following code declares a cursor, skips forward five records, and then returns the values in the sixth record:

BEGIN WORK;

   DECLARE employee_cursor CURSOR FOR SELECT * FROM employee;

   MOVE FORWARD 5 IN employee_cursor;

   FETCH 1 IN employee_cursor;

   CLOSE employee_cursor;

COMMIT WORK;

The above code will return a single row from the employee_cursor result set.

SQL Server

SQL Server supports a variation of FETCH that is very close to the ANSI standard:

FETCH [ { NEXT | PRIOR | FIRST | LAST |

        { ABSOLUTE | RELATIVE  int } }

  [FROM] [GLOBAL] cursor_name

[INTO @variable1 [, ...] ]

The differences between SQL Server's implementation and the ANSI standard are very small. First, SQL Server allows you to use variables in place of the int and cursor_name values. Second, SQL Server allows the declaration and use of GLOBAL cursors that can be accessed by any user or session, not just the one that created it.

There are some rules that apply to how you use the FETCH command based upon how you issued the DECLARE CURSOR command:

  • When you declare a SCROLL SQL-92 cursor, all FETCH options are supported. In all other SQL-92 cursors, only NEXT is the only option supported. (There is also an alternate Transact-SQL style DECLARE CURSOR statement.)

  • DYNAMIC SCROLL cursors support all FETCH options except ABSOLUTE.

  • FORWARD-ONLY and FAST_FORWARD only support FETCH NEXT.

  • KETSET, STATIC, and SCROLL cursors (and DYNAMIC, FORWARD-ONLY, and FAST_FORWARD are not defined), all FETCH options are supported.

SQL Server also requires a DEALLOCATE statement, in addition to CLOSE, to release memory consumed by a cursor.


Here's a full example that goes from declaring and opening a cursor to initiating several fetches and then finally closing and deallocating the cursor:

DECLARE @vc_lname VARCHAR(30), @vc_fname VARCHAR(30), @i_emp_id CHAR(5)

DECLARE employee_cursor SCROLL CURSOR FOR

   SELECT lname, fname, emp_id

   FROM employee

   WHERE hire_date <= 'FEB-14-2004'

OPEN employee_cursor

-- Fetch the last row in the cursor.

FETCH LAST FROM employee_cursor

-- Fetch the row immediately prior to the current row in the cursor.

FETCH PRIOR FROM employee_cursor

-- Fetch the fifth row in the cursor.

FETCH ABSOLUTE 5 FROM employee_cursor

-- Fetch the row that is two rows after the current row.

FETCH RELATIVE 2 FROM employee_cursor

-- Fetch values eight rows prior to the current row into variables.

FETCH RELATIVE -8 FROM employee_cursor

INTO @vc_lname, @vc_fname, @i_emp_id

CLOSE employee_cursor

DEALLOCATE employee_cursor

GO

Remember that in SQL Server you must not only CLOSE the cursor, but you must also DEALLOCATE it. In some rare cases, you might wish to reopen a closed cursor. You can reuse any cursor that you have closed but not deallocated. The cursor is permanently destroyed only when it is deallocated.

See Also

CLOSE
DECLARE CURSOR
OPEN
GRANT Statement

The GRANT statement assigns privileges to users and roles, which allows them to access and use database objects (that is, object privileges).

In addition, most database platforms use the GRANT statement to authorize users and roles to create database objects and execute stored procedures, functions, and so on (particularly usage privileges).

Platform

Command

DB2

Supported, with variations

MySQL

Supported, with variations

Oracle

Supported, with variations

PostgreSQL

Supported, with variations

SQL Server

Supported, with variations


SQL2003 Syntax

The SQL2003 syntax for GRANT includes only the assignment of object privileges and roles to a specific user:

GRANT { {object privilege [,...] | role [,...]} }

[ON database_object_name]

[TO grantee [,...] ]

[WITH HIERARCHY OPTION] [WITH GRANT OPTION] [WITH ADMIN OPTION]

[FROM { CURRENT_USER | CURRENT_ROLE } ]

Keywords


object privilege

Grants one or more privileges for a SQL statement. Multiple privileges may be granted at one time, as long as commas separate them. Do not combine ALL PRIVILEGES with other privileges, but the remainder may be combined in any order. Valid privileges are:


ALL PRIVILEGES

Indicates a shorthand for every privilege the grantor has available to grant. Grants all privileges currently assigned to the grantor to the named users and/or for the specified database objects. This is generally not a recommended approach, since it can encourage sloppy permissioning.


EXECUTE

Grants the privileges to execute any ANSI SQL routine. An ANSI routine is any stored procedure, user-defined function, or user-defined method.


{SELECT | INSERT | UPDATE | DELETE}

Grants the specific privilege for a given user on the specified database object, such as a table or view. You may add a parenthetical list of the columns of a given table on which the privilege will be granted (except for the DELETE statement).


REFERENCES

Grants the privilege to use the column(s) in any constraint or assertion, not just a foreign key. The REFERENCES clause also allows you to define column-specific details (by including a parenthetical, comma-delimited list) for statements like INSERT, SELECT, and so on. Finally, REFERENCES grants the privilege to create or drop foreign key constraints referencing the database object as a parent object.


TRIGGER

Grants the privilege of creating a trigger to operate on a specific table and its columns.


UNDER

Grants the privilege to create subtypes or typed tables.


USAGE

Grants privileges to use a domain, user-defined type, character set, collation, sequence, or translation.


role

Grants a specific, predefined role from the named grantee identified in the FROM clause. For example, the database administrator might want to create a role called Reporter that has read-only access to several tables. By granting this role to a user, that user then receives all of the read-only permissions granted to the Reporter role. Users can have a role assigned to them and receive all of the permissions already assigned to that role.


ON database_object_name

Grants privileges on the specified, predefined database object identified by database_object_name, which may be one of the following:

{[TABLE] object_name | DOMAIN object_name | 

 COLLATION object_name | CHARACTER SET object_name | 

 TRANSLATION object_name | SPECIFIC ROUTINE routine_name}


TO grantee

Assignes the privilege to the named user(s) or role(s), designated as grantee. You can assign privileges to multiple users and/or roles, as long as commas separate them. Alternately, privileges may be granted to PUBLIC, meaning that all users (including those that will be created in the future) have the specified privileges.


WITH HIERARCHY OPTION

Bestows the WITH HIERARCHY OPTION privilege, enabling the grantee to SELECT not only from the named table, but also from all of its subtables. This applies to privilege grants only.


WITH GRANT OPTION

Enables the grantee to further grant the privileges to other users. This applies to privilege grants only.


WITH ADMIN OPTION

Bestows the ability to assign a role. The ability to assign role responsibilities is separate from the ability to grant privileges to other users or roles.


FROM { CURRENT_USER | CURRENT_ROLE}

Names the user who is granting the specified privilege(s), either the CURRENT_USER or the CURRENT_ROLE. This clause is optional and assumes the current user context.

Rules at a Glance

You may grant many privileges on a single object with one statement, but do not mix the ALL PRIVILEGES privilege with the individual SQL statement keywords in a single GRANT statement. You can grant a specific privilege on a specific database object to a single user using:

GRANT privilege_name ON object_name TO grantee_name

For example:

GRANT SELECT ON employee TO Dylan;

You can grant a specific privilege on a specific object to all users via the PUBLIC user. When a grant is issued to PUBLIC, that means everyone has permission to the object without the need for a grant specifically to the object. For example:

GRANT SELECT ON employee TO PUBLIC;

When granting privileges to multiple grantees, simply place a comma between each:

GRANT SELECT ON employee TO Dylan, Matt

The previous example shows that you may grant privileges to multiple users, in this case Dylan and Matt, and to the PUBLIC user in a single GRANT statement. When granting privileges on a table, the privileges may extend to the column level by showing a list of columns enclosed in parentheses after the table name. For example:

GRANT SELECT ON employee(emp_id, emp_fname, emp_lname, job_id)

TO Dylan, Matt

The previous example shows that Dylan and Matt now have select privileges on several columns of the employee table.

Programming Tips and Gotchas

Depending on the specific database implementation, views may or may not have independent access privileges from their base tables.

Note that all of the optional WITH clauses control extensions to the base privilege(s) granted in the statement. Thus, the following command grants the privilege to SELECT records from the employee table:

GRANT SELECT ON employee TO Dylan;

but the following command grants the privilege to SELECT records from the employee table and also to grant that SELECT privilege to other users.

GRANT SELECT ON employee TO Dylan

WITH GRANT OPTION;

Similarly, you can use the REVOKE statement to revoke only the WITH GRANT OPTION, the individual SELECT privilege, or both.

Most of the platforms isolate privileges at the user and role level. Thus, an individual user who is a member of two roles may have an individual set of permissions four times - once for themselves, once for PUBLIC, and once with each of the roles for which they have permission. In this situation, you should be very careful. In order to remove a specific privilege completely from such a user, you have to revoke the user's privileges directly, and then in both roles.

DB2

DB2 offers many options in its implementation of the GRANT command. It is important to note that privileges on database objects (such as SELECT privileges on a specific table) are handled by the command, as are a variety of other privileges:

GRANT { [database_privilege [,...] ON DATABASE ] |

   [ CONTROL ON INDEX index_name] |

   [ {BIND | CONTROL | EXECUTE} ON PACKAGE package_name ] |

   [ EXECUTE ON [SPECIFIC] {FUNCTION | METHOD {* | FOR} | PROCEDURE}

      object_name ] |

   [ {ALTERIN | CREATEIN | DROPIN} ON SCHEMA schema_name ] |

   [ ON SEQUENCE sequence_name] |

   [ PASSTHRU ON SERVER server_name ] |

   [ object_privilege [,...] ON [TABLE] object_name ] }

TO [ {USER |GROUP} ]

   { grantee_name [,...] | group_name [,...]  | PUBLIC } ] 

[WITH GRANT OPTION] | [ USE OF TABLESPACE tablespace_name ]

The parameters are as follows:


database_privileges

Grants one or more privileges that apply to the entire database, rather than to a single object. The database privileges are:


BINDADD

Grants the authority to create packages. The user who creates a package always has the CONTROL privilege on that package even when BINDADD is revoked at a later date.


CONNECT

Grants the authority to access the specified database.


CREATETAB

Grants the authority to create a base table. The user who created the base table always has the CONTROL privilege on the table even if CREATETAB is revoked at a later date.


CREATE_EXTERNAL_ROUTINE

Grants the privilege to register external routines. This is somewhat dangerous since external threads can have adverse side effects. The routine will continue to exist once created, even if the CREATE_EXTERNAL_ROUTINE privilege is revoked for the user. (For more information, check on the THREADSAFE clause of the CREATE or ALTER routine statements in the DB2 documentation.)


CREATE_NOT_FENCED_ROUTINE

Grants the authority to create routines that are not fenced into a specific user process. That is, the routines may execute within the database manager's process. CREATE_NOT_FENCED_ROUTINE is a superset of CREATE_EXTERNAL_ROUTINE. Consequently, you automatically are granted the latter privilege when assigned the former. Read the description of CREATE_EXTERNAL_ROUTINE for more information.


DBADM

Grants superuser authority, including the ability to create any object, and including all privileges against all objects in the database, even the ability to grant those privileges to other users.


IMPLICIT_SCHEMA

Grants the authority to create a schema implicitly, though this privilege does not impact the ability to create a schema or any objects within a schema explicitly.


LOAD

Grants the authority to explicitly LOAD the specified database. SYSADM and DBADM, who automatically possess this privilege, need no other explicitly granted privileges to load a database. But other users with LOAD privilege must have, at a minimum, INSERT privileges on tables they wish to load.


QUIESCE_CONNECT

Grants the privilege to access the specified database while it is quiesced.


CONTROL ON INDEX index_name

Grants the privilege to drop an index, once created, of the specified index_name. This is the explicit CONTROL privilege for indexes. It is automatically granted to the creator of any index.


{BIND | CONTROL | EXECUTE} ON PACKAGE package_name

Grants the privileges associated with packages. Note that RUN and PROGRAM are acceptable synonyms for EXECUTE and PACKAGE, respectively. The package privileges are:


BIND

Grants the authority to bind or rebind the specified package. Since any SQL statements in the package are checked at bind time, the user must also have statement permissions on each object referenced by the package.


CONTROL

Grants the authority to rebind, drop, or execute the specified package, as well as to grant BIND and EXECUTE privileges to other users. Users granted the CONTROL privilege automatically receive BIND and EXECUTE as well. CONTROL is automatically granted to the creator of a package.


EXECUTE

Grants the authority to execute the specified package.


EXECUTE ON [SPECIFIC] {FUNCTION | METHOD {* | FOR} | PROCEDURE} object_name

Grants privileges on an ANSI routine (i.e., user-defined function, user-defined method, or stored procedure). The elements of this clause are as follows:


FUNCTION [schema.]function_name

Specifies that the user is granted execution privileges on a specific function. A SPECIFIC function name may be specified. DB2 also supports functions without names. In this case, FUNCTION [(param [,...])] should be used, including any and all parameters of the function. If schema is not included, the current schema is assumed. You may substitute an asterisk (*) for a specific function name to grant a user the execution privilege on all functions in the current or specified schema.


METHOD { * | FOR type_name}

Specifies that the user is granted rights to execute all methods of type_name, even those that have not yet been created. The optional FOR type_name clause names the type where the specified method is found. A SPECIFIC method name may be specified. DB2 also supports methods without names. In this case, METHOD [(param [,...])] should be used, including any and all parameters of the function. Alternately, the asterisk (*) can be used to specify that all types in the schema are granted to the user.


PROCEDURE [schema.]procedure_name

Specifies that the user be granted execute privileges on all stored procedures in the specified schema, even those created in the future. If schema is not included, the current schema is assumed. You may substitute an asterisk ( * ) for a specific stored procedure name to grant a user the execution privilege on all stored procedures in the current or specified schema.


{ALTERIN | CREATEIN | DROPIN} ON SCHEMA schema_name

Grants privileges associated with manipulating a schema (that is, a user-owned set of objects). Only users with SYSADM, DBADM, or WITH GRANT OPTION permissions for all privileges for the specified schema may issue this command. The elements are as follows:


ALTERIN

Grants the authority to alter or comment on objects in a schema defined by ON SCHEMA schema_name.


CREATEIN

Grants the authority to create objects in a schema defined by ON SCHEMA schema_name.


DROPIN

Grants the authority to drop objects in the schema defined by ON SCHEMA schema_name.


{ALTER | USAGE} ON SEQUENCE sequence_name TO PUBLIC

Grants privileges on a sequence in an explicit or current schema (USAGE) or the privilege to execute the ALTER SEQUENCE statement (ALTER).


PASSTHRU ON SERVER server_name

Grants the privilege to access an external data source named server_name using pass-through mode.


object_privilege

Represents privileges for a variety of statements on tables, views, and nicknamed tables or views. Object privileges may be combined in any order:


ALL [PRIVILEGES]

Provides a shorthand for every privilege the grantor has available to grant. The PRIVILEGES keyword is optional. It grants all privileges currently assigned to the granting user for the specified database objects, including SELECT, INSERT, UPDATE, and DELETE privileges. With ALL, you have privileges to add columns to a table, create or drop primary keys or unique constraints, create or drop foreign keys, create or drop check constraints, create triggers on a table, add or change comments on a table, change a nicknamed column name or datatype, or add, rest, or drop a nicknamed column name. However, granting ALL is generally not a good approach since it can encourage sloppy coding.


ALTER

The privilege to add or alter columns, constraints, comments, or triggers on a specified table or view. ALTER also permits the use of nicknames on column names or datatypes or to change a column option for a nickname.


CONTROL

Grants a large number of privileges to the specific user or role (or PUBLIC) for the specified object. When you grant CONTROL on a table, that includes the privileges for ALTER, DELETE, INSERT, INDEX, REFERENCES, SELECT, and UPDATE. When you grant CONTROL on a view, that includes DELETE, INSERT, SELECT, and UPDATE. On nicknames, CONTROL includes ALTER, INDEX, and REFERENCES.

The grantee has the ability to grant these aforementioned privileges to others, who may drop the specified table, view, or nickname. They may execute the RUNSTATS utility on tables and indexes, as well as execute the SET INTEGRITY command on tables, materialized views, and staging tables.


INDEX

The ability to create an index against a table, or to create an index specification on a nickname. (The creator of an index retains CONTROL privileges on the indexes they create, even if the INDEX privilege is later revoked.)


{SELECT | INSERT | UPDATE | DELETE}

Grants the specific privilege to a given user for the specified database object, such as a table or view. In some cases, these privileges also extend to utilities with similar behavior. For example, the INDEX privilege also includes the use of the IMPORT utility. You may add a parenthetical list of the columns on a given table where the privilege is granted. The UPDATE privilege may be assigned down to the column level by including a parentheses-encapsulated list of column or columns made available to the user.


REFERENCES

Grants the privilege to create or drop foreign key constraints referencing the database object as a parent object. The REFERENCES privilege may be assigned down to the column level by including a parentheses-encapsulated list of column or columns made available to the grantee.


TO { [USER | GROUP]} grantee_name

Names the user or users who will gain the specified privilege or privileges. When both a user and group exist with the same name, use the optional USER or GROUP keywords to control whether the privileges are granted to the user or to the group. PUBLIC may also be used to grant privileges to the PUBLIC role. Multiple grantees can be listed; separate them with a comma between each.


WITH GRANT OPTION

Entitles the grantee to assign the granted privilege(s) to other users.


USE OF TABLESPACE tablespace_name

Grants the privilege of specifying or defaulting new tables to the specified tablespace_name. In effect, it enables the USE privilege on that tablespace.

In situations when a group and a user of the same name exist, you must use either GROUP or KEYWORD to inform DB2 whether you want the privileges assigned to the group or to the user. If you do not, DB2 will return an error and abort the GRANT statement. For example, to grant CONNECT and BINDADD permissions to the user emily and the group datareaders:

GRANT CONNECT, BINDADD ON DATABASE TO USER emily,

   GROUP datareaders

To give the user Dylan, and all users who are members of the Admin role, control over a specific index:

GRANT CONTROL ON INDEX emp_ndx TO dylan, admin;

You can give a user rights on a package to execute it and bind (or rebind it), without the privilege to drop it (via CONTROL) as follows:

GRANT BIND, EXECUTE ON PACKAGE d02.sales_processing

   TO USER dylan

The following example grants a user a variety of privileges on the sales table, as well as the privilege to pass those privileges on to other users:

GRANT DELETE, INSERT, SELECT, UPDATE ON sales TO USER sam

WITH GRANT OPTION

Similarly, you can give another user privileges on a specific object (a view in this case) that includes only specific columns in the object:

GRANT UPDATE (sales_qty, sales_discount) ON sales TO USER jake

DB2 also has privileges at the instance level that aren't managed with the GRANT statement. Most importantly, there are three database manager configuration parameters (SYSADM_GRP, SYSCTRL_GRP, and SYSMAINT_GRP) that control administrative rights to the instance. You control these privileges using the DB2 UPDATE DATABASE MANAGER CONFIGURATION statement. For example:

ATTACH DB2;



UPDATE DATABASE MANAGER CONFIGURATION 

  USING 

    sysadm_group 'DB2GRP'

  IMMEDIATE;



DETACH;


MySQL

MySQL provides additional access privileges, primarily relating to object manipulation within a database. GRANT in MySQL is available from Version 3.22.11 and on. The syntax is as follows:

GRANT [ { ALL [PRIVILEGES] |

   {SELECT | INSERT | UPDATE} [ (column_name [,...]) ] | DELETE |

   REFERENCES [ (column_name [,...]) ] } |

[ USAGE ] | [{ALTER | CREATE | DROP}] | [FILE] | [INDEX] | [PROCESS] |

   [RELOAD] | [SHUTDOWN] | [CREATE TEMPORARY TABLES] | [LOCK TABLES] |

   [REPLICATION CLIENT] | [REPLICATION SLAVE] | [SHOW DATABASES] |

   [SUPER] }[,...]

ON {table_name | * | *.* | database_name.*}

{TO grantee_name [IDENTIFIED BY 'password']} [,...]

[WITH GRANT OPTION]

where:


ALL [PRIVILEGES]

Grants a user all applicable privileges that apply at the current level on one or more objects in the database, with the exception of WITH GRANT OPTION. For example, GRANT ALL ON *.* grants all privledges, except WITH GRANT OPTION, globally.


SELECT | INSERT | UPDATE | DELETE

Grants the ability to read, write, modify, and erase data from tables (and possibly from specific columns of a table), respectively. Column-level permissions are allowed on SELECT, INSERT, and UPDATE, but not DELETE. Granting column-level permissions can slow down MySQL somewhat, since more permission checking is required.


REFERENCES

Remains unimplemented.


USAGE

Creates a "no privilege" user account for use in creating a user that has no privileges.


ALTER | CREATE | DROP

Grants the ability to alter, drop, or create tables and other database objects. When using the CREATE syntax, you are not required to specify an ON clause to identify a specific table.


FILE

Grants the ability to load data from, or write data to, files using the SELECT INTO and LOAD DATA commands.


INDEX

Grants the ability to create or drop indexes.


PROCESS

Grants the ability to view running processes using SHOW FULL PROCESSLIST.


RELOAD

Grants the ability to invoke the FLUSH and RESET commands.


SHUTDOWN

Grants usage of the mysqladmin shutdown command to kill the server process.


CREATE TEMPORARY TABLES

Grants the ability to create temporary tables.


LOCK TABLES

Grants the use of the MySQL command LOCK TABLES on tables where the user has SELECT privileges.


REPLICATION CLIENT

Grants a user the privilege to see metadata about replication slaves and masters.


REPLICATION SLAVE

Grants a replication slave the right to read binlogs from a replication master.


SHOW DATABASES

Grants the user the privilege to execute the MySQL command SHOW DATABASES.


SUPER

Grants the user the privilege of one connection even if the max_connections threshold is reached. Users with SUPER privileges can also execute important MySQL commands like CHANGE MASTER, KILL, mysqladmin debug, PURGE [MASTER] LOGS, and SET GLOBAL.


ON {table_name | * | *.* | database_name.*}

Grants privileges from the specified table_name, from all tables within the current database using an asterisk (*), from all tables in all databases with *.*, or from all tables in the specified database_name with database_name.*.


TO grantee_name [IDENTIFIED BY 'password'] [,...]

Names the user or users who will gain the specified privilege. You may enter multiple users separated by commas. When granting privileges to a new user, you may also optionally set the new password for the new named user at the same time using the IDENTIFIED BY clause.


WITH GRANT OPTION

Entitles the grantee to assign the granted privilege to other users.

Since MySQL is focused on speed, you can implement server-wide features that provide high-speed performance. For example, you can enable the SKIP_GRANT_TABLES startup option to disable checks for privileges. This can speed up queries, but obviously no permission checking is done. This means that all users have full access to all resources in the database.

The following are access privileges that are usable with tables: SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, GRANT, INDEX, and ALTER. At the column level, you can apply INSERT, UPDATE, and SELECT.

In any situation, the host, table, database, and column names may each be up to 60 characters in size. The username (a.k.a. the grantee_name) may be up to 16 characters.

MySQL also supports the possibility of granting rights to a specific user on a specific host if the grantee_name is in the form USER@HOST. Wildcards can be included in the hostname of a grantee_name to provide the access privilege to a large number of users at one time. Also, a missing hostname is the same as the "%" wildcard. For example:

GRANT SELECT ON employee TO katie@% IDENTIFIED BY 'audi',

   annalynn IDENTIFIED BY 'cadillac',

   cody@us% IDENTIFIED BY 'bmw';

The preceding GRANT statement grants read privileges on the employee table to the user katie explicitly at any hostname. Similarly, the GRANT statements grants read privileges to the user annalynn implicitly at any hostname. And finally, the GRANT statement grants read privileges to the user cody explicitly at any hostname starting with "US".

The grantee_name must be 16 or fewer characters. When specifying the user, password protection may be enforced by including the IDENTIFIED BY clause.

The following example grants permissions to three users with passwords:

GRANT SELECT ON employee TO dylan IDENTIFIED BY 'porsche',

  kelly IDENTIFIED BY 'mercedes',

  emily IDENTIFIED BY 'saab';

In MySQL, if you grant permissions to a user that doesn't exist, it creates that user. The two statements that follow create a user and password with global privileges and another user that has no privileges (the USAGE privilege):

GRANT SELECT ON *.* TO tony IDENTIFIED BY 'humbolt';

GRANT USAGE ON sales.* TO alicia IDENTIFIED BY 'dakota';

Failing to include the IDENTIFIED BY clause on a GRANT statement that creates a new user will create a user without a password. This practice is insecure and dangerous.


If you do create a new user using the GRANT command, and you forget to specify a password, you can, and probably should, set a password using the SET PASSWORD command.

MySQL also allows you to issue grants on remote hosts, specified with @hostname, and include the wildcard character percent (%). For example, the following grant provides all permissions on all tables of the current database across all hosts in the notforprofit.org domain to the user annalynn:

GRANT ALL ON * TO annalynn@'%.notforprofit.org';

Privileges are written directly to system tables at four different levels:


Global level

Global privileges apply to all databases on a given server and are stored in the mysql.user system table.


Database level

Database privileges apply to all tables in a given database and are stored in the mysql.db system table.


Table level

Table privileges apply to all columns in a given table and are stored in the mysql.tables_priv system table.


Column level

Column privileges apply to single columns in a given table and are stored in the mysql.columns_priv system table.

Because of the usage and system tables involved, you may grant redundant permissions at different levels. For example, you could grant a user SELECT privileges on a specific table, and then grant global SELECT privileges on that same table to all users of the database. You would then have to revoke those privileges separately to ensure the user no longer had the privilege of SELECTing from the table.

The system tables are also somewhat unprotected, so it is possible to change permissions by issuing INSERT, UPDATE, and DELETE statements against the tables rather than by using GRANT or REVOKE. Normally, all privileges are read into memory when MySQL starts. Database, table, and column privileges issued by a GRANT statement are available immediately and take effect right away. User privileges issued by a GRANT statement are noticed immediately and take effect the next time the user connects. If you directly modify permissions in the system tables, none of the changes are noticed until you restart MySQL, or until you issue a FLUSH PRIVILEGES command.

Oracle

Oracle's implementation of the GRANT statement supports an enormous number of variations and permutations. The syntax is as follows:

GRANT { [object_privilege] [,...] |

   [system_privilege] [,...] |

   [role] [,...] }

[ ON { [schema_name.][object] [,...] |

   [DIRECTORY directory_object_name] |

   [JAVA [ { SOURCE | RESOURCE } ] [schema_name.][object] }

TO {{grantee_name [,...] | role_name [,...] | PUBLIC}

   [WITH { GRANT | HIERARCY } OPTION]

[IDENTIFIED BY password][WITH ADMIN OPTION];

You can grant multiple privileges with a single invocation of the command, but they must all be of the same type (object, system, or role).

For example, you could grant a user three object privileges on a single table in one GRANT statement, and then issue a separate grant of two system privileges to a role, and yet a third grant of several roles to a user, but not all of them in one GRANT statement.

Following are the parameters to Oracle's GRANT statement:


object_privilege

Grants the specified privileges to the specified grantee_name or role on the named schema object (for example, a table or view). You may combine several object privileges, schema objects, or grantees in a single statement. However, you may not grant system privileges or roles in the same statement as object privileges. The object privileges are:


ALL [PRIVILEGES]

Grants all available privileges on a named schema object and is available for use on tables.


ALTER

Grants the privilege to change an existing table using the ALTER TABLE statement, and is available for use on tables and sequences.


DEBUG

Grants access to a table through a debugger. The access granted applies to any triggers on the table or to information on SQL that directly references the table and is available for use on tables, views, procedures, functions, packages, Java objects, and types.


EXECUTE

Grants the privilege to execute a stored procedure, user-defined function, or a package, and is available for use on procedures, functions, packages, Java objects, libraries, types, indextypes, and user-defined operators.


INDEX

Grants the privilege to create indexes on a table.


{ ON COMMIT REFRESH | QUERY REWRITE }

Grants the privilege to create a refresh-on-commit materialized view or to create a materialized view for query rewrite on the specified table. It is available for materialized views only.


{ READ | WRITE }

Grants the privilege to read and write files against a named directory including full path name of the operating system directory. Since Oracle has the ability to store files outside of the database, the Oracle server process must run under a user context with privileges on the applicable directories. You can enable Oracle to enforce security on individual users via this security mechanism. Note that WRITE is only useful in connection with an external table, such as a logfile or an error file.


REFERENCES

Grants the privilege to define referential integrity constraints, and is available for use on tables.


{SELECT | INSERT | DELETE | UPDATE}

Grants the privilege to execute each of the respective SQL commands against the named schema object and is available for use on tables, views, sequences (SELECT only), and materialized views (SELECT only). Note that you must grant SELECT privileges to a user or role that requires DELETE privileges. You can grant column-level privileges, as a parentheses-encapsulated list following the object name, only when granting INSERT, REFERENCES, or UPDATE object privileges on a table or view.


UNDER

Grants the privilege to create a subview under the named view and is available for use on views and types only.


system_privilege

Grants the specified Oracle system privilege to one or more users or roles. For example, you could grant the CREATE TRIGGER privilege or the ALTER USER privilege. In each case, issuing a grant for a system privilege empowers the user or role to execute the command of the same name. Refer to Table 3-2 later in this section for a full list of system privileges.


role

Grants a role to the user or to another role. In addition to user-defined roles, there are a number of system roles that come predefined with Oracle:


CONNECT, RESOURCE, and DBA

Provided for backward compatibility with older versions of Oracle. Do not use these roles in current or newer versions of Oracle since they may be dropped in the future.


DELETE_CATALOG_ROLE, EXECUTE_CATALOG_ROLE, and SELECT_CATALOG_ROLE

Grant members of these roles the privilege deleting, executing, and selecting from data dictionary views and packages.


EXP_FULL_DATABASE and IMP_FULL_DATABASE

Grant members of these roles the privilege of executing the import and export utilities.


AQ_USER_ROLE and AC_ADMINISTRATOR_ROLE

Grant members of these roles the privilege to use or administrate Oracle's Advanced Queuing functionality.


SNMPAGENT

Assigned only to Oracle Enterprise Manager and Intelligent Agent.


RECOVERY_CATALOG_OWNER

Grants the privilege to create users who own their own recovery catalog.


HS_ADMIN_ROLE

Grants the privilege to access areas of the data dictionary used to support Oracle's heterogeneous services feature


ON schema_name

Grants the named privilege to a user or role on an object in the schema. Database objects include tables, views, sequences, stored procedures, user-defined functions, packages, materialized views, user-defined types, libraries, indextypes, user-defined operators, or a synonym for any of these. If you do not include the schema name, Oracle assumes the schema of the current user.

Oracle also supports two additional keywords for special cases:


DIRECTORY

Grants privileges on a directory object, which is an Oracle object corresponding to a filesystem directory.


JAVA

Grants privileges on a Java SOURCE or a RESOURCE schema object.


TO {grantee_name | role_name | PUBLIC} [ WITH { GRANT | HIERARCY } OPTION ]

Names the user or role who will get the specified privilege. PUBLIC may also be used to revoke privileges granted to the PUBLIC role. Multiple grantees can be listed with a comma between each, as in the following:


WITH GRANT OPTION

Enables the grantee to grant the specific privilege(s) to other users or to PUBLIC, but not to roles.


WITH HIERARCHY OPTION

Enables the grantee to receive privileges on all sub-objects when granted privileges on a parent object. This includes sub-objects created in the future. You can use this option only when granting the SELECT object privilege.


IDENTIFIED BY password [WITH ADMIN OPTION]

Establishes or changes a password that the grantee must use to enable a role being granted.


WITH ADMIN OPTION

Enables the grantee to exercise control over a role that you are granting to that grantee. First, this clause enables the grantee to grant and revoke the role to and from other users or non-GLOBAL roles. It further allows the grantee to drop the role, or to change the authorization needed to access a role.

Grants to users take effect right away. Grants to roles take effect right away, assuming the roles are enabled. Otherwise, a grant to a role takes effect as the role is enabled. Note that you can grant roles to users and to other roles (including PUBLIC). For example:

GRANT sales_reader TO sales_manager;

To grant privileges on a view, you must have the specific privilege and the WITH GRANT OPTION on all of the base tables for the view.

Any time you want a privilege available to all users, simply grant it to PUBLIC:

GRANT SELECT ON work_schedule TO public;

However, there are some restrictions when granting system privileges and roles:

  • A privilege or role should not appear more than once in the GRANT statement.

  • Roles cannot be granted to themselves.

  • Roles cannot be granted recursively. That is, you couldn't grant the role sales_reader to sales_manager and then grant sales_manager to sales_reader.

You can grant multiple privileges of the same type in a single statement. However, the grants must be on the same type of objects:

GRANT UPDATE (emp_id, job_id), REFERENCES (emp_id),

ON employees

TO sales_manager;

As an aside, granting any of the object permissions on a table allows the user (or role) to lock the table in any lock mode using Oracle's LOCK TABLE statement.

Nearly every supported Oracle feature or command is assignable with a GRANT command (as shown in Table 3-2). Privileges can be granted not only on database objects (such as tables and views) and system commands (such as CREATE ANY TABLE), but also on schema objects (such as DIRECTORY, JAVA SOURCE, and RESOURCE ).

The ANY option, shown in Table 3-2, grants the privilege to execute a given statement against objects of a specific type owned by any user within the schema. Without the ANY option, the user can only execute the statement against objects in their own schema. A more complete list of Oracle system privileges is shown in Table 3-2.

Table 3-2. Oracle system privileges

Options

Description

CREATE CLUSTER

Grants privilege to create a cluster in the grantee's own schema.

{CREATE | ALTER | DROP} ANY CLUSTER

Grants privilege to create, alter, or drop a cluster in any schema, respectively.

{CREATE | DROP} ANY CONTEXT

Grants privilege to create or drop any context namespace, respectively.

ALTER DATABASE

Grants privilege to alter the database.

ALTER SYSTEM

Grants privilege to issue ALTER SYSTEM statements.

AUDIT SYSTEM

Grants privilege to issue AUDIT sql_statements statements.

CREATE DATABASE LINK

Grants privilege to create private database links in grantee's own schema.

CREATE PUBLIC DATABASE LINK

Grants privilege to create public database links.

DROP PUBLIC DATABASE LINK

Grants privilege to drop public database links.

DEBUG CONNECT SESSION

Grants privilege to connect the current session to the Java Debug Wire Protocol (JDWP) debugger.

DEBUG ANY PROCEDURE

Grants the privilege to debug all PL/SQL objects in the database, similar to granting DEBUG on all procedures, functions, and packages.

CREATE DIMENSION

Grants privilege to create dimensions in the grantee's own schema.

{CREATE | ALTER | DROP } ANY DIMENSION

Grants privilege to create, alter, or drop dimensions in any schema.

{CREATE | DROP} ANY DIRECTORY

Grants privilege to create or drop directory database objects.

CREATE ROLE

Grants the privilege to create a database role.

GRANT ANY ROLE

Grants the privilege to grant a role to other users.

CREATE INDEXTYPE

Grants privilege to create an indextype in the grantee's own schema.

{CREATE | DROP | EXECUTE } ANY INDEXTYPE

Grants privilege to create, alter, drop, or execute an indextype in any schema.

{CREATE | ALTER | DROP} ANY INDEX

Grants privilege to create, alter, or drop an index in any schema or an index on any table in any schema.

{CREATE | DROP} ANY LIBRARY

Grants privilege to create or drop external procedure/function libraries in any schema.

CREATE MATERIALIZED VIEW

Grants privilege to create a materialized view in the grantee's own schema.

{CREATE | ALTER | DROP} ANY MATERIALIZED VIEW

Grants privilege to create, alter, or drop materialized views in any schema.

GLOBAL QUERY REWRITE

Enables rewrite using a materialized view, or creates a function-based index, when materialized view or index reference tables or views are in any schema.

QUERY REWRITE

Enables rewrite using a materialized view, or creates a function-based index, when that materialized view or index references tables and views that are in the grantee's own schema.

ON COMMIT REFRESH

Creates a refresh-on-commit materialized view on any table in the database or alters any refresh-on-demand materialized view into a refresh-on-commit materialized view.

FLASHBACK ANY TABLE

Grants the privilege to issue a SQL flashback query on any table, view, or materialized view in any schema. This privilege is not required for DBMS_FLASHBACK procedures.

CREATE OPERATOR

Grants privilege to create an operator and its bindings in the grantee's own schema.

{CREATE | DROP | EXECUTE} ANY OPERATOR

Grants privilege to create, drop, or execute an operator and its bindings in any schema.

{CREATE | DROP | ALTER} ANY OUTLINE

Grants privilege to create, alter, or drop outlines that can be used in any schema that uses outlines.

SELECT ANY OUTLINE

Grants the privilege to clone private outlines from public ones.

CREATE PROCEDURE

Grants privilege to create stored procedures, functions, and packages in grantee's own schema.

{CREATE | ALTER | DROP | EXECUTE} ANY PROCEDURE

Grants privilege to create, alter, drop, or execute stored procedures, functions, and packages in any schema.

{CREATE | ALTER | DROP} PROFILE

Grants privilege to create, alter, or drop profiles.

ALTER RESOURCE COST

Sets costs for session resources.

{ALTER | DROP} ANY ROLE

Grants privilege to create, alter, drop, or grant roles in the database.

{CREATE | ALTER | DROP} ROLLBACK SEGMENT

Grants privilege to create, alter, or drop rollback segments.

CREATE SEQUENCE

Grants privilege to create sequences in grantee's own schema.

{CREATE | ALTER | DROP | SELECT} ANY SEQUENCE

Grants privilege to create, alter, drop, or select sequence in any schema in the database.

CREATE SESSION

Grants privilege to connect to the database.

ALTER SESSION

Grants privilege to issue ALTER SESSION statements.

RESTRICTED SESSION

Logs on after the instance is started using the SQL*Plus STARTUP RESTRICT statement.

CREATE SNAPSHOT

Grants privilege to create snapshots in grantee's own schema.

{CREATE | ALTER | DROP} ANY SNAPSHOT

Grants privilege to create, alter, or drop snapshots (a.k.a. materialized views) in any schema.

CREATE SYNONYM

Grants privilege to create synonyms in grantee's own schema.

{CREATE | DROP} ANY SYNONYM

Grants privilege to create or drop private synonyms in any schema.

{CREATE | DROP} PUBLIC SYNONYM

Grants privilege to create or drop public synonyms.

CREATE ANY TABLE

Grants privilege to create tables in any schema. The owner of the schema containing the table must have a space quota on the tablespace to contain the table.

ALTER ANY TABLE

Grants privilege to alter any table or view in the schema.

BACKUP ANY TABLE

Uses the export utility to incrementally export objects from the schema of other users.

DELETE ANY TABLE