Monday, 11 February 2008

Oracle SQL Sort Merge Join

The use of a sort merge join in Oracle SQL is quite common, especially in cases where there are missing join predicate against one of the tables or a missing index.
In a sort merge join, Oracle must perform full scans on the target tables, sort the keys and join the rows together.
It's important not to confuse a merge join with a merge join cartesian, which is a special case which is usually avoided.
The Oracle docs note these hints for merge joins:

  • Sort merge join - Force a sort merge join (use_merge) The use_merge hint forces a sort merge join.
  • Merge anti join (merge_aj) - Transforms a NOT IN subquery into a merge anti-join.
  • Merge semi-join (merge_sj) - The merge_sj hint is placed into an EXISTS subquery; This converts the subquery into a special type of merge join between t1 and t2 that preserves the semantics of the subquery. That is, even if there is more than one matching row in t2 for a row in t1, the row in t1 is returned only once.
  • Turn off sort merge join (_sortmerge_inequality_join_off) - This hidden parameter will disable a sort merge join in cases where the predicate is an inequality.

Thursday, 7 February 2008

ORA-00918: column ambiguously defined

The Oracle docs note this on the ora-00918 error*:

ORA-00918 column ambiguously defined

Cause: A column name used in a join exists in more than one table and is thus referenced ambiguously. In a join, any column name that occurs in more than one of the tables must be prefixed by its table name when referenced. The column should be referenced as TABLE.COLUMN or TABLE_ALIAS.COLUMN. For example, if tables EMP and DEPT are being joined and both contain the column DEPTNO, then all references to DEPTNO should be prefixed with the table name, as in EMP.DEPTNO or E.DEPTNO.

Action: Prefix references to column names that exist in multiple tables with either the table name or a table alias and a period (.), as in the examples above.


*As a note, the ORA-00918 error does not exist in Oracle 10g, according to the Oracle documentation

When ORA-00918 is thrown, you have a column which has been ambiguously defined. If a column name in a join is referenced ambiguously, it exists in multiple tables.

  • Column names which occur in multiple tables should be prefixed when it is referenced by its table name.
  • Columns must be referenced as TABLE.COLUMN or TABLE_ALIAS.COLUM . Oracle documentation which reference ORA-00918 give the following example:
    if tables EMP and DEPT are being joined and both contain the column DEPTNO, then all references to DEPTNO should be prefixed with the table name, as in EMP.DEPTNO or E.DEPTNO.
To correct ORA-00918, references should be prefixed to column names existing in multiple tables (either with the table name or table alias and a period)

ORA-00904: STRING: invalid identifier tips

The Oracle docs note this on the ora-00904 error*:

ORA-00904 string: invalid identifier
Cause: The column name entered is either missing or invalid.

Action: Enter a valid column name. A valid column name must begin with a letter, be less than or equal to 30 characters, and consist of only alphanumeric characters and the special characters $, _, and #. If it contains other characters, then it must be enclosed in double quotation marks. It may not be a reserved word.


*According to Oracle documentation, ORA-00904 does not occur in Oracle 10g

When ORA-00904 occurs, you must enter a valid column name as it is either missing or the one entered is invalid.

To avoid ORA-00904, column names cannot be a reserved word, and must contain these four criteria to be valid:
  • begin with a letter
  • be less than or equal to twenty characters
  • consist only of alphanumeric and the special characters ($_#); other characters need double quotation marks around them

Another important factor in correcting ORA-00904 is remembering to run catproc.sql

You can also check your trace file to find the particular error which is causing the ORA-00904 to occur.

ORA-00304: requested instance_number is busy

The Oracle docs note this on the ora-00304 error:

ORA-00304: requested INSTANCE_NUMBER is busy
Cause: An instance tried to start by using a value of the initialization parameter INSTANCE_NUMBER that is already in use.
Action: Either a) specify another INSTANCE_NUMBER, b) shut down the running instance with this number c) wait for instance recovery to complete on the instance with this number.
You will see ORA 00304 if an INSTANCE_NUMBER parameter value is being used at the time of initializing an Oracle instance
To resolve ORA-00304, you may try one of the three options:

  1. Use a different INSTANCE_NUMBER
    In the initialization file, modify the initialization of the INSTANCE_NUMBER
  2. Shut down the instance number causing the ORA-00304 error
  3. On the instance with the ORA-00304, allow recovery to conclude

Monday, 4 February 2008

ORA-00984: Column Not Allowed Here

The Oracle docs note this on the ora-00984 error *

ORA-00984 column not allowed here
Cause: A column name was used in an expression where it is not permitted, such as in the VALUES clause of an INSERT statement.
Action: Check the syntax of the statement and use column names only where appropriate.

An ORA-00984 will be thrown if a column name (like in the VALUES clause of an INSERT statement), is used in an expression where it is not permitted. You may have used a column name in an expression where it is not permitted. Typically, ORA-00984 occurs while including a column name in the VALUES clause of an INSERT statement.

To correct ORA-00984, you simply need to view the syntax of the SQL statement and only use column names where they are appropriate.
You may also find it appropriate to include a character value, in the INSERT statement, instead of the column name.

*Note: ORA-00984 error does not exist in Oracle 10g, according to the Oracle documentation.

Sunday, 27 January 2008

Getting Table Details with SQL*Plus

You can use SQL*Plus to provide the following details about a table:

  1. Column Details
  2. PRIMARY KEY
  3. INDEXES
  4. FOREIGN KEYS
  5. CONSTRAINTS
  6. ROWCOUNT
  7. Other Tables That REFER to this Table
  8. PARTITIONED COLUMNS
  9. PARTITIONS
  10. TRIGGERS
  11. DEPENDANTS
Use the following code in SQL*Plus to provide this information:
      SET AUTOTRACE OFF
SET TIMING OFF
COLUMN COMMENTS FORMAT A50
COLUMN column_name FORMAT A35
COLUMN Data_Type FORMAT A15
COLUMN DATA_DEFAULT FORMAT A20
COLUMN "PK Column" FORMAT A35
COLUMN "FK Column" FORMAT A20

UNDEF Owner
ACCEPT Owner PROMPT 'Enter Owner :'

UNDEF Table_Name
ACCEPT Table_Name PROMPT 'Enter Table Name :'


SET HEADING OFF

PROMPT
PROMPT Comments for Table &Table_Name.
SELECT COMMENTS
FROM ALL_TAB_COMMENTS
WHERE TABLE_NAME = UPPER('&Table_Name.')
AND Owner = UPPER('&Owner.') ;

SET HEADING ON

PROMPT
PROMPT Column Details for Table &Table_Name.

SELECT
ROWNUM "Sr No", T.COLUMN_NAME , T.Data_Type , T.DATA_LENGTH,
DECODE(T.Nullable, 'N' , 'NOT NULL' , 'Y', ' ') NULLABLE , T.Data_Default , C.Comments
FROM
ALL_TAB_COLS T , All_Col_Comments C
WHERE
T.OWNER = C.OWNER
AND T.TABLE_NAME = C.TABLE_NAME
AND T.COLUMN_NAME = C.COLUMN_NAME
AND T.TABLE_NAME = UPPER('&Table_Name.')
AND T.Owner = UPPER('&Owner.') ;


PROMPT
PROMPT PRIMARY KEY for Table &Table_Name.

select COLUMN_NAME
FROM ALL_CONS_COLUMNS
WHERE TABLE_NAME = UPPER('&Table_Name.')
AND Owner = UPPER('&Owner.')
AND CONSTRAINT_NAME = ( SELECT CONSTRAINT_NAME
FROM ALL_CONSTRAINTS
WHERE TABLE_NAME = UPPER('&Table_Name.')
AND CONS! TRAINT_T YPE = 'P'
AND Owner = UPPER('&Owner.')
)
ORDER BY POSITION
/

PROMPT
PROMPT INDEXES for Table &Table_Name.

BREAK ON INDEX_NAME ON UNIQUENESS SKIP 1

SELECT I.INDEX_NAME , C.COLUMN_NAME , I.UNIQUENESS
FROM ALL_IND_COLUMNS C , ALL_INDEXES I
WHERE C.INDEX_NAME = I.INDEX_NAME
AND C.TABLE_NAME = I.TABLE_NAME
AND I.TABLE_NAME = UPPER('&Table_Name.')
AND I.Owner = UPPER('&Owner.')
AND C.Table_Owner = UPPER('&Owner.')
AND NOT EXISTS ( SELECT 'X'
FROM ALL_CONSTRAINTS
WHERE CONSTRAINT_NAME = I.INDEX_NAME
AND Owner = UPPER('&Owner.')
)
ORDER BY INDEX_NAME , COLUMN_POSITION
/

CLEAR BREAKS

PROMPT
PROMPT FOREIGN KEYS for Table &Table_Name.

BREAK ON CONSTRAINT_NAME ON TABLE_NAME ON R_CONSTRAINT_NAME SKIP 1
COLUMN POSITION NOPRINT

SELECT UNIQUE A.CONSTRAINT_NAME,
C.COLUMN_NAME "FK Column" ,
B.TABLE_NAME || '.' || B.COLUMN_NAME "PK Column",
A.R_CONSTRAINT_NAME ,
C.POSITION
FROM ALL_CONSTRAINTS A, ALL_CONS_COLUMNS B, ALL_CONS_COLUMNS C
WHERE A.R_CONSTRAINT_NAME=B.CONSTRAINT_NAME
AND B.OWNER=UPPER('&OWNER')
AND A.CONSTRAINT_NAME=C.CONSTRAINT_NAME
AND A.OWNER=C.OWNER
AND A.OWNER = B.OWNER
AND A.TABLE_NAME=C.TABLE_NAME
AND B.POSITION=C.POSITION
AND A.TABLE_NAME LIKE UPPER('&TABLE_NAME')
ORDER BY A.CONSTRAINT_NAME, C.POSITION
/

COLUMN POSITION NOPRINT
CLEAR BREAKS

PROMPT
PROMPT CONSTRAINTS for Table &Table_Name.

SELECT CONSTRAINT_NAME , SEARCH_CONDITION
FROM ALL_CONSTRAINTS
WHERE TABLE_NAME = UPPER('&Table_Name.')
AND Owner = UPPER('&Owner.')
AND CONSTRAINT_TYPE NOT IN ( 'P' , 'R');

PROMPT
PROMPT ROWCOUNT for Table &Table_Name.

SET FEEDBACK OFF
SET SERVEROUTPUT ON
DECLARE N NU MBER ;
V VARCHAR2(100) ;
BEGIN
V := 'SELECT COUNT(*) FROM ' || UPPER('&Table_Name.') ;
EXECUTE IMMEDIATE V INTO N ;
DBMS_OUTPUT.PUT_LINE (N);
END;
/

SET FEEDBACK ON

PROMPT
PROMPT Tables That REFER to Table &Table_Name.

BREAK ON TABLE_NAME ON CONSTRAINT_NAME skip 1

SELECT C.TABLE_NAME , C.CONSTRAINT_Name , CC.COLUMN_NAME "FK Column"
FROM ALL_CONSTRAINTS C
, All_Cons_colUMNs CC
WHERE C.Constraint_Name = CC.Constraint_Name
AND R_CONSTRAINT_NAME = ( SELECT CONSTRAINT_NAME
FROM ALL_CONSTRAINTS
WHERE TABLE_NAME = UPPER('&Table_Name.')
AND CONSTRAINT_TYPE = 'P'
AND Owner = UPPER('&Owner.')
)
AND C.Owner = UPPER('&Owner.')
/

CLEAR BREAKS


PROMPT
PROMPT PARTITIONED COLUMNS for Table &Table_Name.

SELECT COLUMN_NAME , COLUMN_POSITION
FROM All_Part_Key_Columns
WHERE NAME = UPPER('&Table_Name.')
AND Owner = UPPER('&Owner.') ;


PROMPT
PROMPT PARTITIONS for Table &Table_Name.

SELECT PARTITION_NAME , NUM_ROWS
FROM All_Tab_Partitions
WHERE TABLE_NAME = UPPER('&Table_Name.')
AND Table_Owner = UPPER('&Owner.') ;


PROMPT
PROMPT TRIGGERS for Table &Table_Name.

SELECT Trigger_Name
FROM All_Triggers
WHERE TABLE_NAME = UPPER('&Table_Name.')
AND Owner = UPPER('&Owner.') ;

PROMPT
PROMPT DEPENDANTS for Table &Table_Name.

BREAK ON TYPE SKIP 1

SELECT TYPE , NAME
FROM ALL_DEPENDENCIES
WHERE REFERENCED_NAME = UPPER('&Table_Name.')
ORDER BY TYPE ;

CLEAR BREAKS

SET TERMOUT OFF
SET AUTOTRACE ON
SET TIMING ON
SET TERMOUT ON