One approach is to write a script that describes one particular index, while the other is to write a script that lists all indexes on a table.. Since the previous section, Table Constrai
Trang 2PROJ_HOURS_FKTO_EMPLOYEE ENABLED
FOREIGN KEY TO JEFF.EMPLOYEE
EMPLOYEE_ID EMPLOYEE_ID
PROJ_HOURS_FKTO_PROJECT ENABLED
FOREIGN KEY TO JEFF.PROJECT
PROJECT_ID PROJECT_ID
HOURS_LOGGED_MUST_BE_INT CHECK ENABLED
hours_logged = trunc(hours_logged)
Indexes
Two views return information about indexes Each index gets an entry in the ALL_INDEXES view, and the
ALL_IND_COLUMNS view returns the columns included in each index
Listing Indexes for a Table
The problem of listing indexes for a table is much the same as that of listing constraints on a table You have a master-detail relationship between the index and its columns, and you may have multiple indexes on one table There are two approaches you can take One approach is to write a script that describes one particular index, while the other is to write
a script that lists all indexes on a table
The tradeoff between these two approaches is that one lets you look at indexes by name, while the other lets you look at indexes by table The problem is that you probably need both ways Sometimes, as when a unique index is violated, you
do need to look up an index by name Other times, you just want to see what indexes have been defined on a particular table
One thing to keep in mind when working with unique indexes is that Oracle will report a unique index violation as if it were a constraint violation The error message you get is the same as the one used when you violate a unique constraint, and it looks like this:
ORA-00001: unique constraint (JEFF.UNIQUE_BILLING_RATE) violated
The reason for this is no doubt because Oracle enforces both unique and primary key constraints by creating indexes on the constrained fields If you do get the error message just shown, there are two things you might want to check First, list the constraints on the table you are updating If you don't find one with a name that matches the one in the error message, check to see if there happens to be a unique index with that same name The SHOW_INDEX script in the next section will help you do this
Trang 3Beginning with Oracle8i, it is possible to define a unique or primary key constraint without having a corresponding index created
Index Scripts.
Since the previous section, Table Constraints, showed you how to write one script to list all constraints, let's take the opposite approach this time and write a script that describes just one index Following that, I'll show how you can
expand on that first script by writing a second script that does list indexes by table You can have it both ways.
The SHOW_INDEX.SQL script
Shown below is a SQL*Plus script that describes just one index The first part of the script resembles the other scripts shown in this chapter It looks at the input argument to see whether or not it was qualified by an owner name, defaults it
to the current user's userid if necessary, then stores the results in the substitution variables s_owner_name and
s_index_name Next, a SELECT is done on the ALL_INDEXES table to retrieve information that is not
column-specific about the index into a set of substitution variables These substitution variables are then used to define the page title So far, nothing has been displayed to the user Finally, the index columns themselves are selected, causing the page title to print
If the index does not exist, no columns will be selected and the page title will not be printed The result will be that there
is no output for the user to see To avoid leaving the user in doubt about why there is no output, an extra SELECT is done to cover this case This final SELECT statement only succeeds if the index does not exist, and it outputs a message informing the user that is the case
The last thing the script does is reset anything it changed back to the default values Here is the script:
DESCRIPTION
Displays information about an index The index name
is passed as a parameter to this script
INPUTS
param 1 Name of the index to be described
SET ECHO OFF
SET RECSEP OFF
SET NEWPAGE NONE
Trang 4
SET VERIFY OFF
SET PAGESIZE 9999
SET HEADING OFF
SET LINESIZE 80
SET FEEDBACK OFF
CLEAR COMPUTES
CLEAR COLUMNS
CLEAR BREAKS
Turn off terminal output to avoid spurious blank lines
caused by the SELECTS that are done only to load the
substitution variables
SET TERMOUT OFF
Dissect the input argument, and get the owner name and
table name into two separate substitution variables
The owner name defaults to the current user
DEFINE s_owner_name =
DEFINE s_index_name =
COLUMN owner_name NOPRINT NEW_VALUE s_owner_name
COLUMN index_name NOPRINT NEW_VALUE s_index_name
SELECT
DECODE(INSTR( &&1, ),
O,USER, /*Default to current user.*/
UPPER(SUBSTR(&&1,1,INSTR(&&1,.)-1))) owner_name,
DECODE(INSTR (&&1,.),
0,UPPER (&&1), /*Only the index name was passed in.*/
UPPER(SUBSTR(&&1,INSTR(¦& 1 & rsquo;,.)+1))) index_name
FROM dual;
Retrieve information about the index as a whole
DEFINE s_table_owner
DEFINE s_table_name
DEFINE s_index_type
DEFINE s_uniqueness
DEFINE s_tablespace_name
COLUMN table_owner NOPRINT NEW_VALUE s_table_owner
COLUMN table_name NOPRINT NEW_VALUE s_table_name
COLUMN index_type NOPRINT NEW_VALUE s_index_type
COLUMN uniqueness NOPRINT NEW_VALUE s_uniqueness
COLUMN tablespace_name NOPRINT NEW_VALUE s_tablespace_name
SELECT table_owner, table_name, index_type, uniqueness, tablespace_name
FROM all_indexes
WHERE owner = &&s_owner_name
AND index_name = &&s_index_name;
Information about the index as a whole is printed in
the page title
TTITLE SKIP 1 LEFT INDEX &&s_owner_name &&s_index_name -
&&s_index_type &&s_uniqueness SKIP 1 -
DEFINED ON TABLE &&s_table_owner &s_table_name SKIP 1 -
STORED IN TABLESPACE & &_tablespace_name SKIP 1-
CONTAINING COLUMNS:
Trang 5List the columns that make up the index
The indent column moves the column list over to the
right so that it comes after the CONTAINING COLUMNS:
portion of the header
SET TERMOUT ON
COLUMN indent FORMAT A19
COLUMN column_name FORMAT A30
SELECT indent,
column_name
FROM all_ind_columns
WHERE index_owner = &&s_owner_name
AND index_name = &&s_index_name
ORDER BY column_position;
Spit out an error message if the index does not exist
TTITLE SKIP 1
SELECT Index &&s_owner_name &&s_table_name does not exist
FROM DUAL
WHERE NOT EXISTS (
SELECT *
FROM all_indexes
WHERE owner =&&s_owner_name
AND index_name = &&s_index_name
);
Change all settings back to defaults
CLEAR COLUMNS
CLEAR BREAKS
UNDEFINE s_owner_name
UNDEFINE s_index_name
UNDEFINE s_index_type
UNDEFINE s_uniqueness
UNDEFINE s_tablespace_name
SET PAGESIZE 14
SET HEADING ON
SET NEWPAGE 1
SET FEEDBACK ON
Running the SHOW_INDEX script
To describe an index, simply invoke SHOW_INDEX and pass the index name as a parameter Here's an example:
SQL> @show_index project_hours_pk
INDEX JEFF.PROJECT_HOURS_PK NORMAL UNIQUE
DEFINED ON TABLE JEFF.PROJECT_HOURS
STORED IN TABLESPACE USERS
CONTAINING COLUMNS:
PROJECT_ID
EMPLOYEE_ID
TIME_LOG_DATE
Trang 6
If the specified index does not exist, you will get a message telling you that For example:
SQL> @show_index this_does_not_exist
Index JEFF.THIS_DOES_NOT_EXIST does not exist
Next you will see how you can write another script that uses SHOW_INDEX to describe all the indexes on a table
The LIST_INDEXES.SQL script
You now have a script that describes one specific index If you wanted to describe all the indexes for a particular table, the obvious solution would be to run SHOW_INDEX for each of those indexes The only thing that makes this at all difficult is that SQL*Plus has no built-in looping construct
You can't just write a simple loop to display each index for a table However, you do have a view, the ALL_INDEXES view, from which you can select the names of all the indexes on a table Instead of selecting just the index names, it's not too big a leap to select an expression such as this:
SELECT @SHOW_INDEX ¦¦ owner ¦¦ ¦¦ index_name
Executing a SELECT such as the previous one against the ALL_INDEXES view results in output that looks like this:
@SHOW_INDEX JEFF.PROJECT_HOURS_PK
@SHOW_INDEX JEFF.PROJECT_HOURS_UNIQUE
Using the SPOOL command, you can send this output to a file, which will then contain commands to describe each
index on a table Then you execute that file The following LIST_INDEXES.SQL script does this:
DESCRIPTION
Describe all the indexes that are defined on
the specified table
INPUTS
param 1 The table name, optionally qualified by
an owner name using the standard dot notation
SET ECHO OFF
SET TERMOUT OFF
SET FEEDBACK OFF
SET VERIFY OFF
CLEAR COLUMNS
Dissect the input argument, and get the owner name and
table name into two separate substitution variables
The owner name defaults to the current user
DEFINE s_owner_name =
Trang 7DEFINE s_table_name =
COLUMN owner_name NOPRINT NEW_VALUE s_owner_name
COLUMN table_name NOPRINT NEW_VALUE s_table_name
SELECT
DECODE (INSTR (&&, ),
0,USER, /*Default to current user.*/
UPPER(SUBSTR(&&1,1,INSTR(&&1,.)-1))) owner_name,
DECODE (INSTR (&&1 ,.),
0,UPPER(&&1), /*Only the table name was passed in.*/
UPPER(SUBSTR(&&1,INSTR(&&1,.)+1))) table_name
FROM dual;
Create a file of commands that will use the SHOW_INDEX script
to describe each index defined on the table
SET PAGESIZE 0
SET HEADING OFF
SPOOL list_indexes_1 sql
Generate the show index commands
SELECT @SHOW_INDEX ¦¦ owner ¦¦ ¦¦ index_name
FROM all_indexes
WHERE table_owner = &&s_owner_name
AND table_name = &&s_table_name;
Generate an error message if the table does not exist
SELECT PROMPT Table &&s_owner_name &&s_table_name does not exist
FROM DUAL
WHERE NOT EXISTS (
SELECT *
FROM all_tables
WHERE owner = &&s_owner_name
AND table_name = &&s_table_name
);
Generate a message if no indexes at all exist for the table
SELECT PROMPT Table &&s_owner_name &&s_table_name has no indexes defined FROM all_tables
WHERE owner = &&s_owner_name
AND table_name = &&s table_name
AND NOT EXISTS (
SELECT *
FROM all_indexes
WHERE table_owner = &&s_owner_name
AND table_name = &&s_table_name
);
SPOOL OFF
Reset everything back to its default
SET PAGESIZE 14
SET TERMOUT ON
SET FEEDBACK ON
SET VERIFY ON
Trang 9CLEAR COLUMNS
Tell the user what she is going to see
PROMPT
PROMPT INDEXES DEFINED ON TABLE &&s_owner_name &s_table_name
Execute the script that was just created to
display all the indexes on the table
@list_indexes_1
This script builds a file named LIST_INDEXES_1, which runs the SHOW_INDEX script for each index on the specified
table There are two extra SELECTs to cover the cases where the table does not exist, or where there are no indexes defined on the table This file is then executed in order to display information about each of the table's indexes
Running the LIST_INDEXES.SQL script
Here's what it looks like to run the LIST_INDEXES script on the PROJECT_HOURS table:
SQL> @list_indexes project_hours
INDEXES DEFINED ON TABLE JEFF PROJECT_HOURS
INDEX JEFF.PROJECT_HOURS_UNIQUE NORMAL UNIQUE
DEFINED ON TABLE JEFF.PROJECT_HOURS
STORED IN TABLESPACE USERS
CONTAINING COLUMNS:
PROJECT_ID
EMPLOYEE_ID
TIME_LOG_DATE
HOURS_LOGGED
DOLLARS_CHARGED
INDEX JEFF.PROJECT_HOURS_PK NORMAL UNIQUE
DEFINED ON TABLE JEFF.PROJECT_HOURS
STORED IN TABLESPACE USERS
CONTAINING COLUMNS:
PROJECT_ID
EMPLOYEE_ID
TIME_LOG_DATE
As you can see, information about each index on the PROJECT_HOURS table is displayed The next two examples show the results of running LIST_INDEXES with an invalid table name and for a table that does not have any indexes:
SQL> @list_indexes bad_table_name
INDEXES DEFINED ON TABLE JEFF.BAD_TABLE_NAME
Table JEFF.BAD_TABLE_NAME does not exist
SQL>
SQL> @list_indexes x
Trang 10
INDEXES DEFINED ON TABLE JEFF.X
Table JEFF.X has no indexes defined
Triggers
Information about triggers can be retrieved from two views, the ALL_TRIGGERS view and the
ALL_TRIGGER_COLS view Most of the time you will be able to find all the information you need in
ALL_TRIGGERS The ALL_TRIGGER_COLS view contains a list of all database columns referenced in the trigger This view is sometimes useful when you are troubleshooting because it can quickly show you which triggers reference
or modify any given database column
Looking at Trigger Definitions
Retrieving the definition of a trigger from the database actually turns out to be quite easy compared to the effort you go through to see indexes and constraints Mostly this is because you don't have a master/detail relationship to deal
witheverything you need is in the ALL_TRIGGERS view The DESCRIPTION field Oracle includes in the view helps
a lot too Everything you need to see is in just four columns
There are just a couple of caveats you need to be aware of when looking at the ALL_TRIGGERS view The first is that the format of the data in the DESCRIPTION and TRIGGER_BODY fields comes from the original CREATE
TRIGGER statement This can lead to some minor inconsistencies from one trigger to the next, depending on where the line breaks occur and whether the CREATE TRIGGER statement was entered in upper- or lowercase There's also no guarantee that lines of code in the trigger body won't exceed your line length For that reason, I usually set line length fairly high when I look at a trigger
The second caveat is that the WHEN clause is returned as one long line in the WHEN_CLAUSE field, regardless of whether or not it was on one line in the original CREATE TRIGGER statement Neither of these issues presents any great problem It just helps to be aware of them
Trigger Scripts
The following sections describe scripts that will let you list trigger definitions
The SHOW_TRIGGER.SQL script
The following script shows the definition and code for a trigger on a table Note the use of FOLD_BEFORE in the COLUMN commands This results in the four