Pages

PL/SQL compiler directives

As of the current release of PL/SQL, we have 4 directives

1)AUTONOMOUS_TRANSACTION.
2)RESTRICT_REFERENCES
3)EXCEPTION_INIT.
4)SERIALLY_REUSABLE.



AUTONOMOUS_TRANSACTION:
A subprogram marked with this pragma can do SQL operations and commit or roll back those operations, without committing or rolling back the data in the main transaction. 

RESTRICT_REFERENCES:
To be callable From SQL statements, a stored function must obey certain purity rules, which control side-effects. If any SQL statement inside the function body violates a rule, you get an error at run time. You can declare the pragma RESTRICT_REFERENCES only in a package spec or object type spec.

EXCEPTION_INIT:
The pragma EXCEPTION_INIT associates an exception name with an Oracle error number.A pragma is an instruction to the Oracle compiler that tells it to do something. In this case you are telling Oracle to associate an error that you choose to a variable that you choose

SERIALLY_REUSABLE:
The pragma SERIALLY_REUSABLE indicates that the package state is needed only for the duration of one call to the server. An example could be an OCI call to the database or a stored procedure call through a database link. PRAGMA
Signifies that the statement is a pragma (compiler directive). Pragmas are processed at compile time, not at run time


pl/sql interview questions 1


How to find dependencies referenced Inside PL/SQL Store Procedure

The Oracle data dictionary tracks the object types referenced in PL/SQL with the dba_dependencies view. To track the dependency among packages and tables, try this dictionary query:

select
  referenced_owner,
  referenced_name,
  referenced_type
from
  DBA_DEPENDENCIES
where
  name= 'YOUR_PROCEDURE or PACKAGE NAME' and   owner = 'SCOTT'
order by
  referenced_owner, referenced_name, referenced_type;

Finding PL/SQL compilation errors

PL/SQL does not always tell you about compilation errors.

SQL>SHOW ERRORS
No errors.

But how to see the error?

You have to give the full command as follows:

SQL>SHOW ERROR PROCEDURE 


Show Errors syntax:

Usage: SHOW ERRORS [{ FUNCTION | PROCEDURE | PACKAGE |
   PACKAGE BODY | TRIGGER | VIEW
   | TYPE | TYPE BODY | DIMENSION
   | JAVA SOURCE | JAVA CLASS } [schema.]name]

 
Finding Record count of all tables?

   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;
     /

SQL>SELECT COUNT(*) FROM EMP;
14 Records. 
SQL>SELECT COUNT(*) FROM DEPT;
4 Records. 
...
...

How do you find when an object was created , last modified date?

SELECT OWNER, OBJECT_NAME, CREATED, LAST_DDL_TIME
FROM DBA_OBJECTS
WHERE OBJECT_NAME = 'enter_object_name_here';
 
 
Sending E-Mail in PL/SQL

Oracle allows us to send email from PL/SQL. You can create a procedure to send mail as follows:

CREATE OR REPLACE PROCEDURE SEND_MAIL (
    msg_from     VARCHAR2 := 'sender@domain.com'
  , msg_to       VARCHAR
  , msg_subject  VARCHAR2 := 'E-Mail message from your database'
  , msg_text     VARCHAR2 := ''
)
IS
  c   UTL_TCP.CONNECTION;
  rc  INTEGER;
BEGIN
  c  := UTL_TCP.OPEN_CONNECTION('localhost', 25);       -- open the SMTP port 25 on local machine
  rc := UTL_TCP.WRITE_LINE(c, 'HELO localhost');
  rc := UTL_TCP.WRITE_LINE(c, 'MAIL FROM: '||msg_from);
  rc := UTL_TCP.WRITE_LINE(c, 'RCPT TO: '||msg_to);
  rc := UTL_TCP.WRITE_LINE(c, 'DATA');                  -- Start message body
  rc := UTL_TCP.WRITE_LINE(c, 'Subject: '||msg_subject);
  rc := UTL_TCP.WRITE_LINE(c, '');
  rc := UTL_TCP.WRITE_LINE(c, msg_text);
  rc := UTL_TCP.WRITE_LINE(c, '.');                     -- End of message body
  rc := UTL_TCP.WRITE_LINE(c, 'QUIT');
  UTL_TCP.CLOSE_CONNECTION(c);                          -- Close the connection
EXCEPTION
  WHEN others THEN
    RAISE_APPLICATION_ERROR(-20000, 'Unable to send e-mail message from PL/SQL routine.');
END;

SQL>send_mail('sender@domain.com','recipient@domain.com','Test message from first PLSQL','your message here ');

pl/sql interview questions

What is PL/SQL and what is it used for?
PL/SQL is Oracle's Procedural Language extension to SQL. PL/SQL's language syntax, structure and data types are similar to that of ADA. The PL/SQL language includes object oriented programming techniques such as encapsulation, function overloading, information hiding (all but inheritance). PL/SQL is commonly used to write data-centric programs to manipulate data in an Oracle database.

Should one use PL/SQL or Java to code procedures and triggers?
Internally the Oracle database supports two procedural languages, namely PL/SQL and Java. This leads to questions like "Which of the two is the best?" and "Will Oracle ever desupport PL/SQL in favour of Java?".
Many Oracle applications are based on PL/SQL and it would be difficult of Oracle to ever desupport PL/SQL. In fact, all indications are that PL/SQL still has a bright future ahead of it. Many enhancements are still being made to PL/SQL. For example, Oracle 9iDB supports native compilation of Pl/SQL code to binaries.
PL/SQL and Java appeal to different people in different job roles. The following table briefly describes the difference between these two language environments:
PL/SQL:
Data centric and tightly integrated into the database Proprietary to Oracle and difficult to port to other database systems Data manipulation is slightly faster in PL/SQL than in Java Easier to use than Java (depending on your background)
Java:
Open standard, not proprietary to Oracle Incurs some data conversion overhead between the Database and Java type systems Java is more difficult to use (depending on your background)



How can one see if somebody modified any code?
Code for stored procedures, functions and packages is stored in the Oracle Data Dictionary. One can detect code changes by looking at the LAST_DDL_TIME column in the USER_OBJECTS dictionary view. Example:
        SELECT OBJECT_NAME,
               TO_CHAR(CREATED,       'DD-Mon-RR HH24:MI') CREATE_TIME,
               TO_CHAR(LAST_DDL_TIME, 'DD-Mon-RR HH24:MI') MOD_TIME,
               STATUS
        FROM   USER_OBJECTS
        WHERE  LAST_DDL_TIME > '&CHECK_FROM_DATE';



How can one search PL/SQL code for a string/ key value?
The following query is handy if you want to know where a certain table, field or expression is referenced in your PL/SQL source code.
        SELECT TYPE, NAME, LINE
        FROM   USER_SOURCE
        WHERE  UPPER(TEXT) LIKE '%&KEYWORD%';



How can one keep a history of PL/SQL code changes?
One can build a history of PL/SQL code changes by setting up an AFTER CREATE schema (or database) level trigger (available from Oracle 8.1.7). This way one can easily revert to previous code should someone make any catastrophic changes. Look at this example:
        CREATE TABLE SOURCE_HIST                     -- Create history table
          AS SELECT SYSDATE CHANGE_DATE, USER_SOURCE.*
             FROM   USER_SOURCE WHERE 1=2;

        CREATE OR REPLACE TRIGGER change_hist        -- Store code in hist table
               AFTER CREATE ON SCOTT.SCHEMA          -- Change SCOTT to your schema name
        DECLARE
        BEGIN
          if DICTIONARY_OBJ_TYPE in ('PROCEDURE', 'FUNCTION',
                          'PACKAGE', 'PACKAGE BODY', 'TYPE') then
             -- Store old code in SOURCE_HIST table
             INSERT INTO SOURCE_HIST
                SELECT sysdate, user_source.* FROM USER_SOURCE
                WHERE  TYPE = DICTIONARY_OBJ_TYPE
                  AND  NAME = DICTIONARY_OBJ_NAME;
          end if;
        EXCEPTION
          WHEN OTHERS THEN
               raise_application_error(-20000, SQLERRM);
        END;
        /
        show errors



How can I protect my PL/SQL source code?
PL/SQL V2.2, available with Oracle7.2, implements a binary wrapper for PL/SQL programs to protect the source code.
This is done via a standalone utility that transforms the PL/SQL source code into portable binary object code (somewhat larger than the original). This way you can distribute software without having to worry about exposing your proprietary algorithms and methods. SQL*Plus and SQL*DBA will still understand and know how to execute such scripts. Just be careful, there is no "decode" command available.
The syntax is:
    wrap iname=myscript.sql oname=xxxx.plb



Can one print to the screen from PL/SQL?
One can use the DBMS_OUTPUT package to write information to an output buffer. This buffer can be displayed on the screen from SQL*Plus if you issue the SET SERVEROUTPUT ON; command. For example:
    set serveroutput on
    begin
       dbms_output.put_line('Look Ma, I can print from PL/SQL!!!');
    end;
    /
DBMS_OUTPUT is useful for debugging PL/SQL programs. However, if you print too much, the output buffer will overflow. In that case, set the buffer size to a larger value, eg.: set serveroutput on size 200000
If you forget to set serveroutput on type SET SERVEROUTPUT ON once you remember, and then EXEC NULL;. If you haven't cleared the DBMS_OUTPUT buffer with the disable or enable procedure, SQL*Plus will display the entire contents of the buffer when it executes this dummy PL/SQL block.



Can one read/write files from PL/SQL?
Included in Oracle 7.3 is an UTL_FILE package that can read and write operating system files. The directory you intend writing to has to be in your INIT.ORA file (see UTL_FILE_DIR=... parameter). Before Oracle 7.3 the only means of writing a file was to use DBMS_OUTPUT with the SQL*Plus SPOOL command.
Copy this example to get started:
    DECLARE
      fileHandler UTL_FILE.FILE_TYPE;
    BEGIN
      fileHandler := UTL_FILE.FOPEN('/tmp', 'myfile', 'w');
      UTL_FILE.PUTF(fileHandler, 'Look ma, I''m writing to a file!!!\n');
      UTL_FILE.FCLOSE(fileHandler);
    EXCEPTION
      WHEN utl_file.invalid_path THEN
         raise_application_error(-20000, 'ERROR: Invalid path for file or path not in INIT.ORA.');
    END;
    /


Can one call DDL statements from PL/SQL?
One can call DDL statements like CREATE, DROP, TRUNCATE, etc. from PL/SQL by using the "EXECUTE IMMEDATE" statement. Users running Oracle versions below 8i can look at the DBMS_SQL package (see FAQ about Dynamic SQL).
    begin
       EXECUTE IMMEDIATE 'CREATE TABLE X(A DATE)';
    end;
NOTE: The DDL statement in quotes should not be terminated with a semicolon.



Can one use dynamic SQL statements from PL/SQL?
Starting from Oracle8i one can use the "EXECUTE IMMEDIATE" statement to execute dynamic SQL and PL/SQL statements (statements created at run-time). Look at these examples. Note that statements are NOT terminated by semicolons:
    EXECUTE IMMEDIATE 'CREATE TABLE x (a NUMBER)';

    -- Using bind variables...
    sql_stmt := 'INSERT INTO dept VALUES (:1, :2, :3)';
    EXECUTE IMMEDIATE sql_stmt USING dept_id, dept_name, location;

        -- Returning a cursor...
    sql_stmt := 'SELECT * FROM emp WHERE empno = :id';
    EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id;
One can also use the older DBMS_SQL package (V2.1 and above) to execute dynamic statements. Look at these examples:
    CREATE OR REPLACE PROCEDURE DYNSQL AS
      cur integer;
      rc  integer;
    BEGIN
      cur := DBMS_SQL.OPEN_CURSOR;
      DBMS_SQL.PARSE(cur, 'CREATE TABLE X (Y DATE)', DBMS_SQL.NATIVE);
      rc := DBMS_SQL.EXECUTE(cur);
      DBMS_SQL.CLOSE_CURSOR(cur);
    END;
    /
More complex DBMS_SQL example using bind variables:
    CREATE OR REPLACE PROCEDURE DEPARTMENTS(NO IN DEPT.DEPTNO%TYPE) AS
      v_cursor integer;
      v_dname  char(20);
      v_rows   integer;
    BEGIN
      v_cursor := DBMS_SQL.OPEN_CURSOR;
      DBMS_SQL.PARSE(v_cursor, 'select dname from dept where deptno > :x', DBMS_SQL.V7);
      DBMS_SQL.BIND_VARIABLE(v_cursor, ':x', no);
      DBMS_SQL.DEFINE_COLUMN_CHAR(v_cursor, 1, v_dname, 20);
      v_rows := DBMS_SQL.EXECUTE(v_cursor);
      loop
        if DBMS_SQL.FETCH_ROWS(v_cursor) = 0 then
           exit;
        end if;
        DBMS_SQL.COLUMN_VALUE_CHAR(v_cursor, 1, v_dname);
        DBMS_OUTPUT.PUT_LINE('Deptartment name: '||v_dname);
      end loop;
      DBMS_SQL.CLOSE_CURSOR(v_cursor);
    EXCEPTION
      when others then
           DBMS_SQL.CLOSE_CURSOR(v_cursor);
           raise_application_error(-20000, 'Unknown Exception Raised: '||sqlcode||' '||sqlerrm);
    END;
    /



What is the difference between %TYPE and %ROWTYPE?
The %TYPE and %ROWTYPE constructs provide data independence, reduces maintenance costs, and allows programs to adapt as the database changes to meet new business needs.
%ROWTYPE is used to declare a record with the same types as found in the specified database table, view or cursor. Example:
    DECLARE
       v_EmpRecord  emp%ROWTYPE;
%TYPE is used to declare a field with the same type as that of a specified table's column. Example:
    DECLARE
       v_EmpNo  emp.empno%TYPE;



What is the result of comparing NULL with NULL?
NULL is neither equal to NULL, nor it is not equal to NULL. Any comparison to NULL is evaluated to NULL. Look at this code example to convince yourself.
    declare
      a number := NULL;
      b number := NULL;
    begin
      if a=b then
         dbms_output.put_line('True, NULL = NULL');
      elsif a<>b then
         dbms_output.put_line('False, NULL <> NULL');
      else
         dbms_output.put_line('Undefined NULL is neither = nor <> to NULL');
      end if;
    end;



How does one get the value of a sequence into a PL/SQL variable?
As you might know, one cannot use sequences directly from PL/SQL. Oracle (for some silly reason) prohibits this:
    i := sq_sequence.NEXTVAL;
However, one can use embedded SQL statements to obtain sequence values:
    select sq_sequence.NEXTVAL into :i from dual;
Thanks to Ronald van Woensel



Can one execute an operating system command from PL/SQL?
There is no direct way to execute operating system commands from PL/SQL in Oracle7. However, one can write an external program (using one of the precompiler languages, OCI or Perl with Oracle access modules) to act as a listener on a database pipe (SYS.DBMS_PIPE). Your PL/SQL program then put requests to run commands in the pipe, the listener picks it up and run the requests. Results are passed back on a different database pipe. For an Pro*C example, see chapter 8 of the Oracle Application Developers Guide.
In Oracle8 one can call external 3GL code in a dynamically linked library (DLL or shared object). One just write a library in C/ C++ to do whatever is required. Defining this C/C++ function to PL/SQL makes it executable. Look at this External Procedure example.



How does one loop through tables in PL/SQL?
Look at the following nested loop code example.
    DECLARE
       CURSOR dept_cur IS
       SELECT deptno
         FROM dept
        ORDER BY deptno;
       -- Employee cursor all employees for a dept number
       CURSOR emp_cur (v_dept_no DEPT.DEPTNO%TYPE) IS
       SELECT ename
         FROM emp
        WHERE deptno = v_dept_no;
    BEGIN
       FOR dept_rec IN dept_cur LOOP
          dbms_output.put_line('Employees in Department '||TO_CHAR(dept_rec.deptno));
          FOR emp_rec in emp_cur(dept_rec.deptno) LOOP
             dbms_output.put_line('...Employee is '||emp_rec.ename);
          END LOOP;
      END LOOP;
    END;
    /



How often should one COMMIT in a PL/SQL loop? / What is the best commit strategy?
Contrary to popular believe, one should COMMIT less frequently within a PL/SQL loop to prevent ORA-1555 (Snapshot too old) errors. The higher the frequency of commit, the sooner the extents in the rollback segments will be cleared for new transactions, causing ORA-1555 errors.
To fix this problem one can easily rewrite code like this:
    FOR records IN my_cursor LOOP
       ...do some stuff...
       COMMIT;
    END LOOP;
... to ...
    FOR records IN my_cursor LOOP
       ...do some stuff...
       i := i+1;
       IF mod(i, 10000) THEN    -- Commit every 10000 records
          COMMIT;
       END IF;
    END LOOP;
If you still get ORA-1555 errors, contact your DBA to increase the rollback segments.
NOTE: Although fetching across COMMITs work with Oracle, is not supported by the ANSI standard.



I can SELECT from SQL*Plus but not from PL/SQL. What is wrong?
PL/SQL respect object privileges given directly to the user, but does not observe privileges given through roles. The consequence is that a SQL statement can work in SQL*Plus, but will give an error in PL/SQL. Choose one of the following solutions:
•    Grant direct access on the tables to your user. Do not use roles!
    GRANT select ON scott.emp TO my_user;
   
•    Define your procedures with invoker rights (Oracle 8i and higher);
•    Move all the tables to one user/schema.



What is a mutating and constraining table?
"Mutating" means "changing". A mutating table is a table that is currently being modified by an update, delete, or insert statement. When a trigger tries to reference a table that is in state of flux (being changed), it is considered "mutating" and raises an error since Oracle should not return data that has not yet reached its final state.
Another way this error can occur is if the trigger has statements to change the primary, foreign or unique key columns of the table off which it fires. If you must have triggers on tables that have referential constraints, the workaround is to enforce the referential integrity through triggers as well.
There are several restrictions in Oracle regarding triggers:
•    A row-level trigger cannot query or modify a mutating table. (Of course, NEW and OLD still can be accessed by the trigger) .
•    A statement-level trigger cannot query or modify a mutating table if the trigger is fired as the result of a CASCADE delete.
•    Etc.



Can one pass an object/table as an argument to a remote procedure?
The only way the same object type can be referenced between two databases is via a database link. Note that it is not enough to just use the same type definitions. Look at this example:
    -- Database A: receives a PL/SQL table from database B
    CREATE OR REPLACE PROCEDURE pcalled(TabX DBMS_SQL.VARCHAR2S) IS
    BEGIN
       -- do something with TabX from database B
       null;
    END;
    /

    -- Database B: sends a PL/SQL table to database A
    CREATE OR REPLACE PROCEDURE pcalling IS
       TabX DBMS_SQL.VARCHAR2S@DBLINK2;
    BEGIN
       pcalled@DBLINK2(TabX);
    END;
    /



Is it better to put code in triggers or procedures? What is the difference?
In earlier releases of Oracle it was better to put as much code as possible in procedures rather than triggers. At that stage procedures executed faster than triggers as triggers had to be re-compiled every time before executed (unless cached). In more recent releases both triggers and procedures are compiled when created (stored p-code) and one can add as much code as one likes in either procedures or triggers.



Is there a PL/SQL Engine in SQL*Plus?
No. Unlike Oracle Forms, SQL*Plus does not have an embedded PL/SQL engine. Thus, all your PL/SQL code is sent directly to the database engine for execution. This makes it much more efficient as SQL statements are not stripped off and sent to the database individually.



Is there a limit on the size of a PL/SQL block?
Yes, the max size is not an explicit byte limit, but related to the parse tree that is created when you compile the code. You can run the following select statement to query the size of an existing package or procedure:
    SQL> select * from dba_object_size where name = 'procedure_name';

Mahindra Satyam and CGI questions


       Mahindra Satyam
                                      --By lakshmi

1.    Description about project?    
2.    What r the packages, functions, procedures u developed in your project what are their functionality?
3.    In which format u got the project?
4.    How u started with u r project?
5.    What r the steps u followed to create tables in your project?
6.    How you involved in db design process?
7.    What r the scripts u wrote for inserting and deleting data from db?
8.    How u export the data from db to excel file?
9.    Where u stored the files in db?
10.  How u execute the code in sql prompt?
11.  .Tell me some names of functions and procedures that u created in u r project?
12.  What is the name of requirement specification?
13.  What are the path names u provided to execute u r coded data?
14.  Steps to get the data from oracle to unix environment..
 CGI
1.    EXPLAIN BREIFLY ABOUT YOUR PROJECT
2.    HOW MANY TYPE OF ENVIROMENTS R THERE IN YOUR COMPANY?
3.    Exception handling
4.    How we will send error msg with no to ui environment.
5.    Romun,rowed
6.    Use of hint.
7.    In which format u will get requirements?
8.    Select stmt structure..
9.    Can we develop exceptions in cusor environment?
10.  After u work is completed how you produce the documentation for that?
11.  What is the documentation file called?
12.  Delete,truncate srtuctue..
13.  Query for top n records..
14.  Explain plan mechanisnm..
15.  Structure for the procedure in exception mechanism..






SQL Query Tuning Tips



Here are some very simple yet powerful SQL tips to remember.


 •  Avoid using the following:
Boolean operators >, <, >=, <=, is null,is not null.
Not in, !=
Like '%pattern', not exists
Calculations on unindexed columns or (use union instead)
Having (use a WHERE clause instead)
 Do use the following:

Enable aliases to prefix all columns
Place indexed columns higher in the WHERE clause
Use SQL Joins instead of using sub-queries
Make the table with the least number of rows the driving table by making it first in the FROM clause

Other important points for SQL Tuning:

Establish a tuning environment that reflects your production  database.
Establish performance expectations before you begin
Always Design and develop with performance in mind
Create Indexes to support selective WHERE clauses and join conditions.
Use concatenated indexes where appropriate
Consider indexing more than you think you should, to avoid table lookups.
Pick the best join method.
Nested loops joins are best for indexed joins of subsets.
Hash joins are usually the best choice for "big" joins.
Pick the best join order.
Pick the best "Driving" table.
Eliminate rows as early as possible in the join order
Use bind variables. Bind variables are key to application scalability.
Use Oracle hints where appropriate.
Compare performance between alternative syntax for your SQL statement.
Consider utilizing PL/ SQL to overcome difficult SQL tuning issues.
Consider using third party tools to make the job of SQL tuning easier.
Never do a calculation on an Indexed column (e.g., WHERE salary*5 > :myvalue).
Whenever possible, use the UNION statement instead of OR conditions.
Avoid the use of NOT IN or HAVING in the WHERE clause. Instead, use the NOT EXISTS clause.
Always specify numeric values in numeric form and character values in character form (e.g., WHERE emp_number = 565, WHERE emp_name = ‘Jones’).
Avoid specifying NULL in an indexed column.
Avoid the LIKE parameter if = will suffice. Using any Oracle function will invalidate the index, causing a full-table scan.
Never mix data types in Oracle queries, as it will invalidate the index. If the column is numeric, remember not to use quotes (e.g., salary = 50000). For char index columns, always use single quotes (e.g., name = ‘BURLESON’).
Avoid using subqueries when a JOIN will do the job.
Use the Oracle “decode” function to minimize the number of times a table has to be selected.
If your query will return more than 20 percent of the rows in the table, a full-table scan may be better than an index scan.
Always use table aliases when referencing columns.
To turn off an index you do not want to use (only with a cost-based optimizer), concatenate a null string to the index column name (e.g., name||') or add zero to a numeric column name (e.g., salary+0). With the rule-based optimizer, this allows you to manually choose the most selective index to service your query.
 These rules may seem simplistic but following them in a diligent manner will generally relieve more than half of the SQL tuning problems that are experienced:


Remember that Oracle’s rule-based optimizer looks at the order of table names in the FROM clause to determine the driving table. Always make sure that the last table specified in the FROM clause is the table that will return the smallest number of rows. In other words, specify multiple tables with the largest result set table specified first in the FROM clause.

SQL Query Tuning Tips

Efficient SQL statements play a very important role in maintaining the database. They not only improve the performance of the database but also help in reducing the network traffic. The following can be stated as some of the tips for tuning SQL statements used to retrieve data from the database:

1. Know your application and business data well: Before writing our SQL statements, we need to familiarize ourselves with different business data sources. We must be aware of the data volume and its distribution in the database along with thorough understanding of the business data model – such as relationships among business entities.
2. Test your queries with realistic data: After writing an SQL statement, we must test it in an environment which reflects the production database. The behavior of the SQL statement depends a lot on the environment wherein it is tested.
3. Write identical SQL statements in your applications: Use bind variables, stored procedures and packages whenever possible. The benefits of using identical SQL statements include reduced memory use on the database server and faster execution, as parsing is not done.
4. Use indexes carefully on the table: Be sure of creating the necessary indexes on the table used in the SQL statement. But creating too many of them may result in performance degradation of the server. Try to follow the below rules in creating indexes on a table:
1. Create indexes on the columns which are frequently used in the WHERE clause of the application SQL or the queries given by the end users.
2. Index those columns which are frequently used in joining tables in SQL statements.
3. Use only index columns that select small percent of rows with the same value.
4. Do not index the columns which are used with functions and operators in the WHERE clause of the SQL statement.
5. Do not index those columns which get modified frequently as the index maintenance will become an issue during execution of DML statements on the table.
6. Unique indexes are better than non-unique indexes due to better selectivity. Create unique indexes on PK columns and non-unique indexes on FK columns and the columns frequently used in the WHERE clause.
7. Create index so that the column used in the WHERE clause make up a leading portion of the index.
5. Make an indexed path available to SQL: Sometimes even after creating the indexes, they won’t get used in the execution of the query. One of the different ways of making the indexed path available to the optimizer is to use SQL hints.
6. Use Explain Plan and TKPROF wherever possible: These are the tools that come along with Oracle server and help in understanding the execution of our SQL statements. Explain Plan – helps us to know the access path the optimizer opted. TKPROF – shows the actual performance statistics of the SQL statement.
7. Understand the Optimizer: SQL statement can be executed using rule-based optimizer or cost-based optimizer. In older applications, Oracle has used rule-based approach whereas in newer applications, oracle is promoting more of cost-based approach. If you opt to use cost-based approach, then it is necessary to run ANALYZE schema regularly as doing that stores the recent database statistics in the data dictionary views which are used by the cost-based optimizer. The SQL query can tuned only if cost-based approach is opted for.
8. Think globally when acting locally: Keep in mind that the modifications you do to improve the performance of one SQL statement affects other SQL statements used by applications or other users.
9. The WHERE clause is crucial: The following can be said to be some of the cases where the WHERE clause will not use index even if it is created on a column. The index is created on column COL1 but it wont be used in the below illustrated examples.
1. COL1 < COL2
2. COL1 > COL2
3. COL1 <= COL2
4. COL1 >= COL2
5. COL1 is null – The index does not store null values hence when queries for null values index won’t get used
6. COL1 is not null – The index does not store null values hence when queries for null values index won’t get used.
7. COL1 not in (value1, value2...)
8. COL1 != expression1
9. COL1 like ‘%pattern1’ – index is not used in this case as the leading edge of the index is suppressed; but whereas if queried as COL1 like ‘pattern1%’, then index is used as they would result in a bounded-range index scan
10. Not exists (subquery)
11. Expression1 = expression2 – All expressions, functions or calculations involving indexes column would prohibit using the index on that column.
10. Use WHERE clause instead of HAVING clause to filter the records : Using an indexed column in HAVING clause of the query to filter records will result in full table scan and avoid the usage on the index on that column. Instead first filter the records using WHERE clause to filter the records which makes use of the index on the column. Below queries illustrate the usage of index, if an index is created on DEPTID column of EMP table.
1. Select dept_id, sum(salary) from emp group by dept_id having dept_id = 100;
2. Select dept_id, sum(salary) from emp where  dept_id = 100 group by dept_id;
In case a) Query will not use the index created on dept_id column whereas case b) query makes use of it.
11. Specify the leading index columns: In case of a compound index, it is used in an SQL query only if the leading column of it is used. Below queries are used to illustrate the same with an assumption of a compound index (PART_NUM, PRODUCT_ID) existing on the table PARTS.
1. Select * from parts where part_num = 2;
2. Select * from parts where product_id = 1002;
Case a) would use the index as the column used in the query WHERE clause is a leading column of the compound index; whereas case b) query would not use the index. If incase of case b), you want to make use of index we can re-write the query in the following way:

Select * from party where part_num > 0 and product_id = 1002;

12. Evaluate index scan v/s full table scans: If selecting more than 15 percent of the records from a table, it is better to use/force a full table scan on the table for such query. When using an index does more harm than good to the query, we can use techniques the following to suppress the usage of index.
1. Select /*+ full(a)*/ * from emp where salary = 5000;
A full hint forces the full table scan on the table and avoids the usage of index on salary column.
2. Select * from emp where salary + 0 = 5000;
The salary column in WHERE clause is modified to an expression which results in avoiding the usage of index on the column.
3. Select * from emp where salary = ‘5000’;
An implicit conversion on the indexed column results in avoiding the index usage.
4. Select * from emp where ss# ||’  ‘|| = ‘111-222-333’;
When the percentage of table rows accessed is 15 percent or less, an index scan will work better because it results in multiple logical reads per row accessed, whereas a full table scan can read all the rows in a block in one logical read. Thus, the performance of full table scan is better when accessing a large percentage of rows from a table.
            To illustrate this point, say the ANALYZE command is issued against the EMP table and all its indexes. Oracle generates the following statistics in the data dictionary table USER_TABLES and USER_INDEXES:
         
Table Statistics:
NUM_ROWS = 1000
BLOCKS = 100

Index Statistics:
BLEVEL = 2
AVG_LEAF_BLOCKS_PER_KEY = 1
AVG_DATA_BLOCKS_PER_KEY = 1
            Based on these statistics, the following would be the logical reads (block accessed) for different types of scans:        
  Use of index to return one row = 3
(BLEVEL+(AVG_LEAF_BLOCKS_PER_KEY - 1) + AVG_DATA_PER_KEY)

Use of index to return all rows = 3000
                                        (NUM_ROWS * Blocks accessed to return one row using index)
 Full table scan = 100(BLOCKS)

13. Use an ORDER BY clause for index scan: Oracle optimizer uses an index scan if the ORDER BY clause is used on an indexed column. The query would retrieve ROWID from index and access the table using the ROWID.
14. Know thy data: You need to know the data and its distribution in your database server in order to understand the usage of indexes on the columns and their execution. You need to keep in mind that the SQL query performance varies as the database grows and data distributions changes.
15. Know when to use large-table scans: A full table scan provides better performance when compared to an index scan on a very small table or a very large table. An index scan on a very large table may require scanning of many indexes and table blocks. When these blocks are brought to database buffer cache, they are kept as long as possible. But as these are not needed for other queries, the hit ratio of the database buffer declines resulting in performance degradation. The blocks read by a full table scan are removed from database buffer cache much earlier does not hamper the performance as an index scan on a very large table.
    16.   Minimize the table access (passes): Usually by reducing the number of table passes in a SQL statement improves the performance.
     Here’s an example to illustrate the same:
            The STUDENT table has four columns named NAME, STATUS, PARENT_INCOME, and SELF_INCOME. The name is the primary key. The values of the STATUS column are 0 for independent students and 1 for dependent students.
            The following query returns the name and income for dependent as well as independent students. It results in two passes through the STUDENT table, creates a temporary table for processing, and initiates a sort to eliminate duplicates:
         
SELECT NAME, PARENT_INCOME
FROM STUDENT
WHERE STATUS = 1
UNION
SELECT NAME, SELF_INCOME
FROM STUDENT
WHERE STATUS = 0;

          The same request can be fulfilled by this query, which results in only one pass through the table:
         
SELECT NAME, PARENT_INCOME*STATUS + SELF_INCOME (1-STATUS)
FROM STUDENT;

17. Join tables in the proper order: The order in which the tables are joined in a multiple table join is crucial. Perform the most restrictive search first in order to filter out the maximum number of rows and only a few records are processed in further levels. You need to make sure that the driving table (master table in a master-detail join) returns the least number of rows. For cost-based optimizer, the order in which the tables appear in WHERE clause is irrelevant as it picks the best execution plan on its own. We can use the ORDERED hint to control the order in which the tables are accessed in the execution plan.
18. Use index-only searches whenever possible: If possible, write the queries that use index-only searches. The optimizer will have to search only index and not the full table to satisfy the SQL resulting in improving the performance. For example, a compound index exists on L_NAME and F_NAME columns in EMP table.
1. Select f_name from emp where l_name = ‘Smith’;
2. Select f_name, salary from emp where l_name = ‘Smith’;

In Case a) query, the optimizer performs an index-only search whereas in case b) query, the optimizer performs a table search in order to get the data for a column – salary which is not a part of the compound index. Hence we need to observe the column list considered in the SELECT clause as well while writing a query.

19. Redundancy is good: Provide as much information as possible in the WHERE clause of the query. If in a WHERE clause of a query, there is COL1 = Col2 and Col1 = 10 then the optimizer infers that COL2 = 10. But at if there is a condition like COL1 = COL2 and COL2 = COL3, then the optimizer does not infer it as COL1 = COL3.
20. Keep it simple, stupid: Make your SQL statements as simple as possible as simple statements yield better performance than a single complex SQL statement. The lower the Explain Plan Cost of an SQL, the better the performance of the query. Hence we need to try to tune our queries to reduce the cost as much as possible.
21. You can reach the same destination in different ways: In many cases, more than one SQL can provide with the same desired results. Each query uses a different plan and performs differently. For example, the use of MINUS operator may perform faster than the use of NOT IN or NOT EXISTS predicates. If an SQL involves an OR in the WHERE clause, we can re-write the same by using a UNION. Hence we need to evaluate all the possible queries for a requirement and choose the best access path query.
22. Use the special columns: Make use of the special columns like ROWID and ROWNUM in your queries. ROWID searches are faster than searches performed on any columns. A ROWID is not a constant in the database; hence do not hard-coded the value in your SQLs and applications.
23. Use explicit cursors over implicit cursors: Implicit cursors are opened by Oracle for DELETE, UPDATE, SELECT and INSERT and use an extra fetch. Explicit cursors are opened by developers using DECLARE, PEN, FETCH and CLOSE cursor statements.
24. Explore and take advantage of the oracle parallel query option: Using the parallel query option, you can execute SQL in parallel for faster performance. This parallel query option can be used only in SMP and MPP systems containing multiple disk drivers. The Oracle database has to be configured for this feature to be used and SQLs specific for that feature should be written.
25. Reduce the network traffic and increase throughput: Using array processing and PL/SQL blocks can achieve better performance and reduce the network traffic. Array processing allows a single SQL to process multiple rows. Using arrays in an insert, we can insert 1000 rows in a table. Significance performance gain can be achieved in client/servers and batch systems using this technique. Multiple SQL statements can cause heavy network traffic. However, if the SQL statements are in a  single PL/SQL block, the entire block can be sent to Oracle server, processed there and results returned to the application running on the client.

SQL*Loader :

 SQL*Loader


SQL*Loader :
This is a CUI (Character User Interface) Tool, which is used to load data from flat files to tables. We have to feed control file to the SQL Loader this control file contains information about the flat file and into which table needs to be loaded.

1) DATA FILE :
This is file which actual data to be loaded.

2) CONTROL FILE:
This is key program to load the data.It provides information to SQL*Loader.In control file we specify name and location of the input data file, format of the records, name of the table or tables to be loaded,condition for selecting the data,name and location of bad and discard file.

3) BAD FILE :
This file contains the records which are rejected by SQL*Loader.Whenever SQL*Loader encounter a database error while to trying to load a record , it writes that record to a file known as BAD FILE. Extension of bad file (.bad)

4) DISCARD FILE:
This file will be created automatically when we executed control file. It contains the records which are rejected by control file, control file will reject the records if any of the condition was not satisfied mentioned in the file.

5) Log File:
This file contains the record of Loader activites during a load session.It contains names of control file, log file, bad file, discard file and data file, error messages for records that cause errors , sucessful record count.The extension of Log file is (.log)

CONTROL FILE SYNTAX:

LOAD DATA
INFILE ‘DATA FILE PATH’
INSERT INTO TABLE
FIELDS TERMINATED BY ‘,’ OPTIONALLY ENCLOSED BY ‘ “ ‘ TRAILING NULL COLS
(COLUMN..1,COLUMN..2,COLUMN..3,COLUMN..4………………………………….COLUMN..N)
TO EXECUTE CONTROL FILE:

SQLLDR CONTROL_FILE PATH USERNAME/PASSWORD @DATABASE.




EXAMPLE:
Step 1: CREATE DATA FILE IN THE EXTENSION OF ( .txt), ( .dat),( .csv)
DATA FILE……….. E:\RAJ\EMP.txt (CREATE THIS FILE IN NOTEPAD)
1,RAJKUMAR,20,22-MAY-2002
2,SIKINDAR,20,12-FEB-2004
3,VENU,30,11-MAR-2001
5,RAMU,40,15-DEC-2001
6,ANU,20,15-JAN-2000
7,ROJA RAMANI,50,18-FEB-1999

step2: connect to any of the user and create the table based on the given data.

Connect scott/tiger@prod
CREATE TABLE XX_EMP ( EMPNO NUMBER(5),
ENAME VARCHAR2(20),
DEPTNO NUMBER(3),
JOINDATA DATE)

step 3: Create control file ( .CTL PROGRAM )
CONTROL FILE…………E:\RAJ\ EMP.ctl
LOAD DATA
INFILE ‘E:\RAJ\APPS\EMP.TXT’
INSERT INTO TABLE XX_EMP
FIELDS TERMINATED BY ‘,’
(EMPNO,ENAME,DEPTNO,JOINDATE)

Collections in pl/sql


1.Associative array(or index-by table)
2.varray(variable-size arrray)
3.Nested table

Number of Elements::

 If the no of elements is specified ,it is the maximum  no of elements in the collection.
If the no of elements isunspecified, the maximum no of elements in the collection is
the upper limit of the index type

Dense or sparse::

A dense collection has no gap between elements-Every element in the list has a values
and a sparse collection has gap between  elements

Uninitialized Status::

An empty collection exists but has no elements To add elements to an empty collection
 invoke the extend method

An null collection does not exists  to change a null collection to an existing collection ,you
must initialize it, either by making it  empty or assigning a non-null value to it

Associative Arrays::
*****************

An associative array (formerly called PL/SQL table or index-by table) is a set of
key-value pairs. Each key is a unique index, used to locate the associated value with
the syntax variable_name(index).
The data type of index can be either a string type or PLS_INTEGER. Indexes are
stored in sort order

Like a database table, an associative array:
*Is empty (but not null) until you populate it
* Can hold an unspecified number of elements, which you can access without
knowing their positions
Unlike a database table, an associative array:
* Does not need disk space or network operations
* Cannot be manipulated with DML statements


Example=>  defines a type of associative array indexed by string, declares a variable
of that type, populates the variable with three elements, changes the value of one
element, and prints the values (in sort order, not creation order). (FIRST and NEXT are
collection methods


Associative array indexed by string::
******************************

  DECLARE
  -- Associative array indexed by string:
  TYPE population IS TABLE OF NUMBER  -- Associative array type
    INDEX BY VARCHAR2(64);            --  indexed by string
city_population  population;        -- Associative array variable
  i  VARCHAR2(64);                    -- Scalar variable
BEGIN
  -- Add elements (key-value pairs) to associative array:
  city_population('Chennai')  := 2000000;
  city_population('Mubai')     := 750000;
  city_population('Ap') := 1000000;
  -- Change value associated with key 'Ap':
  city_population('Ap') := 2001;
  -- Print associative array:
  i := city_population.FIRST;  -- Get first element of array
  WHILE i IS NOT NULL LOOP
    DBMS_Output.PUT_LINE
      ('Population of ' || i || ' is ' || city_population(i));
    i := city_population.NEXT(i);  -- Get next element of array
  END LOOP;
END;
/


Example #2 Function Returns Associative Array Indexed by PLS_INTEGER::
***************************************************************


DECLARE
  TYPE sum_multiples IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
  n  PLS_INTEGER := 5;   -- number of multiples to sum for display
  sn PLS_INTEGER := 10;  -- number of multiples to sum
  m  PLS_INTEGER := 3;   -- multiple
  FUNCTION get_sum_multiples (
    multiple IN PLS_INTEGER,
    num      IN PLS_INTEGER
) RETURN sum_multiples
  IS
    s sum_multiples;
  BEGIN
    FOR i IN 1..num LOOP
      s(i) := multiple * ((i * (i + 1)) / 2);  -- sum of multiples
    END LOOP;
    RETURN s;
  END get_sum_multiples;
BEGIN
  DBMS_OUTPUT.PUT_LINE (
    'Sum of the first ' || TO_CHAR(n) || ' multiples of ' ||
    TO_CHAR(m) || ' is ' || TO_CHAR(get_sum_multiples (m, sn)(n)));
end;
/

Example#3   Declaring Associative Array Constant::
*******************************************

CREATE OR REPLACE PACKAGE My_Types AUTHID DEFINER IS
  TYPE My_AA IS TABLE OF VARCHAR2(20) INDEX BY PLS_INTEGER;
  FUNCTION Init_My_AA RETURN My_AA;
END My_Types;
/
CREATE OR REPLACE PACKAGE BODY My_Types IS
  FUNCTION Init_My_AA RETURN My_AA IS
    Ret My_AA;
BEGIN
Ret(-10) := '-ten';
Ret(0) := 'zero';
Ret(1) := 'one';
Ret(2) := 'two';
Ret(3) := 'three';
Ret(4) := 'four';
Ret(9) := 'nine';
RETURN Ret;
  END Init_My_AA;
END My_Types;
/
DECLARE
  v CONSTANT My_Types.My_AA := My_Types.Init_My_AA();
BEGIN
  DECLARE
    Idx PLS_INTEGER := v.FIRST();
BEGIN
    WHILE Idx IS NOT NULL LOOP
      DBMS_OUTPUT.PUT_LINE(TO_CHAR(Idx, '999')||LPAD(v(Idx), 7));
Idx := v.NEXT(Idx);
    END LOOP;
  END;
END;
/

Varrays (Variable-Size Arrays)::
**************************

A varray (variable-size array) is an array whose number of elements can vary from
zero (empty) to the declared maximum size. To access an element of a varray variable,
use the syntax variable_name(index). The lower bound of index is 1; the upper
bound is the current number of elements. The upper bound changes as you add or
delete elements, but it cannot exceed the maximum size. When you store and retrieve a
varray from the database, its indexes and element order remain stable


Example#4 Varray (Variable-Size Array)::
**********************************

DECLARE
  TYPE Foursome IS VARRAY(4) OF VARCHAR2(15);  -- VARRAY type
  -- varray variable initialized with constructor:
  team Foursome := Foursome('John', 'Mary', 'Alberto', 'Juanita');
  PROCEDURE print_team (heading VARCHAR2) IS
  BEGIN
    DBMS_OUTPUT.PUT_LINE(heading);
    FOR i IN 1..4 LOOP
      DBMS_OUTPUT.PUT_LINE(i || '.' || team(i));
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('---');
  END;

BEGIN
  print_team('2001 Team:');
  team(3) := 'Pierre';  -- Change values of two elements
  team(4) := 'Yvonne';
  print_team('2005 Team:');
  -- Invoke constructor to assign new values to varray variable:
team := Foursome('Arun', 'Amitha', 'Allan', 'Mae');
  print_team('2009 Team:');
END;
/

Nested Tables::
*************

In the database, a nested table is a column type that stores an unspecified number of
rows in no particular order. When you retrieve a nested table value from the database
into a PL/SQL nested table variable, PL/SQL gives the rows consecutive indexes,
starting at 1. Using these indexes, you can access the individual rows of the nested
table variable. The syntax is variable_name(index). The indexes and row order of
a nested table might not remain stable as you store and retrieve the nested table from
the database.


Example#5  Nested Table of Local Type::
***********************************

DECLARE
  TYPE Roster IS TABLE OF VARCHAR2(15);  -- nested table type
  -- nested table variable initialized with constructor:
  names Roster := Roster('D Caruso', 'J Hamil', 'D Piro', 'R Singh');
  PROCEDURE print_names (heading VARCHAR2) IS
  BEGIN
    DBMS_OUTPUT.PUT_LINE(heading);
    FOR i IN names.FIRST .. names.LAST LOOP  -- For first to last element
      DBMS_OUTPUT.PUT_LINE(names(i));
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('---');
  END;

BEGIN
  print_names('Initial Values:');
  names(3) := 'P Perez';  -- Change value of one element
  print_names('Current Values:');
  names := Roster('A Jansen', 'B Gupta');  -- Change entire table
  print_names('Current Values:');
END;
/


Example#5  Nested Table of Standalone Stored Type::
**********************************************

CREATE OR REPLACE TYPE nt_type IS TABLE OF NUMBER;
/
CREATE OR REPLACE PROCEDURE print_nt (nt nt_type) IS
  i  NUMBER;
BEGIN
  i := nt.FIRST;
  IF i IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('nt is empty');
  ELSE
    WHILE i IS NOT NULL LOOP
      DBMS_OUTPUT.PUT('nt.(' || i || ') = '); print(nt(i));
      i := nt.NEXT(i);
    END LOOP;
  END IF;
  DBMS_OUTPUT.PUT_LINE('---');
END print_nt;
/
DECLARE
  nt nt_type := nt_type();  -- nested table variable initialized to empty
BEGIN
  print_nt(nt);
  nt := nt_type(90, 9, 29, 58);
  print_nt(nt);
END;
/


Collection Constructors::
*********************

A collection constructor (constructor) is a system-defined function with the same
name as a collection type, which returns a collection of that type. The syntax of a
constructor invocation is:
collection_type ( [ value [, value ]... ] )

Note: This topic applies only to varrays and nested tables.
Associative arrays do not have constructors. In this topic, collection
means varray or nested table


Example #5  Initializing Collection (Varray) Variable to Empty::
*****************************************************

DECLARE
  TYPE Foursome IS VARRAY(4) OF VARCHAR2(15);
  team Foursome := Foursome();  -- initialize to empty
  PROCEDURE print_team (heading VARCHAR2)
  IS
  BEGIN
    DBMS_OUTPUT.PUT_LINE(heading);
    IF team.COUNT = 0 THEN
      DBMS_OUTPUT.PUT_LINE('Empty');
    ELSE
      FOR i IN 1..4 LOOP
        DBMS_OUTPUT.PUT_LINE(i || '.' || team(i));
      END LOOP;
    END IF;
    DBMS_OUTPUT.PUT_LINE('---');
  END;
BEGIN
  print_team('Team:');
  team := Foursome('John', 'Mary', 'Alberto', 'Juanita');
  print_team('Team:');
END;
/

Assigning Values to Collection Variables::
***********************************

You can assign a value to a collection variable in these ways:
Invoke a constructor to create a collection and assign it to the collection variable
Use the assignment statement
Pass it to a subprogram as an OUT or IN OUT parameter, and then assign the value
inside the subprogram.

Data Type Compatibility::
............................................
You can assign a collection to a collection variable only if they have the same data
type. Having the same element type is not enough.

Example #8    Data Type Compatibility for Collection Assignment::
********************************************************

DECLARE
  TYPE triplet IS VARRAY(3) OF VARCHAR2(15);
  TYPE trio    IS VARRAY(3) OF VARCHAR2(15);
  group1 triplet := triplet('Jones', 'Wong', 'Marceau');
  group2 triplet;
group3 trio;
BEGIN
  group2 := group1;  -- succeeds
group3 := group1;  -- fails
end;
/

In Example #8, VARRAY types triplet and trio have the same element type,
VARCHAR(15). Collection variables group1 and group2 have the same data type,
triplet, but collection variable group3 has the data type trio. The assignment of
group1 to group2 succeeds, but the assignment of group1 to group3 fails

Assigning Null Values to Varray or Nested Table Variables::
....................................................................................................

To a varray or nested table variable, you can assign the value NULL or a null collection
of the same data type. Either assignment makes the variable null.

Example #9 Assigning Null Value to Nested Table Variable::
**************************************************

DECLARE
  TYPE dnames_tab IS TABLE OF VARCHAR2(30);
  dept_names dnames_tab := dnames_tab(
    'Shipping','Sales','Finance','Payroll');  -- Initialized to non-null value
  empty_set dnames_tab;  -- Not initialized, therefore null
  PROCEDURE print_dept_names_status IS
  BEGIN
    IF dept_names IS NULL THEN
      DBMS_OUTPUT.PUT_LINE('dept_names is null.');
    ELSE
      DBMS_OUTPUT.PUT_LINE('dept_names is not null.');
    END IF;
  END  print_dept_names_status;
BEGIN
  print_dept_names_status;
  dept_names := empty_set;  -- Assign null collection to dept_names.
  print_dept_names_status;
  dept_names := dnames_tab (
    'Shipping','Sales','Finance','Payroll');  -- Re-initialize dept_names
  print_dept_names_status;
END;
/

Example #9 initializes the nested table variable dname_tab to a non-null value;
assigns a null collection to it, making it null; and re-initializes it to a different non-null
value.

Assigning Set Operation Results to Nested Table Variables::
....................................................................................................
To a nested table variable, you can assign the result of a SQL MULTISET operation or
SQL SET function invocation.

The SQL MULTISET operators combine two nested tables into a single nested table.
The elements of the two nested tables must have comparable data types. For
information about the MULTISET operators, see Oracle Database SQL Language
Reference.
The SQL SET function takes a nested table argument and returns a nested table of the
same data type whose elements are distinct (the function eliminates duplicate
elements). For information about the SET function, see Oracle Database SQL Language
Reference.

Example #10   Assigning Set Operation Results to Nested Table Variable::
**************************************************************

DECLARE
  TYPE nested_typ IS TABLE OF NUMBER;
  nt1    nested_typ := nested_typ(1,2,3);
  nt2    nested_typ := nested_typ(3,2,1);
  nt3    nested_typ := nested_typ(2,3,1,3);
  nt4    nested_typ := nested_typ(1,2,4);
  answer nested_typ;
  PROCEDURE print_nested_table (nt nested_typ) IS
    output VARCHAR2(128);
  BEGIN
    IF nt IS NULL THEN
      DBMS_OUTPUT.PUT_LINE('Result: null set');
    ELSIF nt.COUNT = 0 THEN
      DBMS_OUTPUT.PUT_LINE('Result: empty set');
    ELSE
      FOR i IN nt.FIRST .. nt.LAST LOOP  -- For first to last element
        output := output || nt(i) || ' ';
      END LOOP;
      DBMS_OUTPUT.PUT_LINE('Result: ' || output);
    END IF;
  END print_nested_table;
BEGIN
  answer := nt1 MULTISET UNION nt4;
  print_nested_table(answer);
answer := nt1 MULTISET UNION nt3;
  print_nested_table(answer);
answer := nt1 MULTISET UNION DISTINCT nt3;
  print_nested_table(answer);
answer := nt2 MULTISET INTERSECT nt3;
  print_nested_table(answer);
answer := nt2 MULTISET INTERSECT DISTINCT nt3;
  print_nested_table(answer);
answer := SET(nt3);
  print_nested_table(answer);
answer := nt3 MULTISET EXCEPT nt2;
  print_nested_table(answer);
answer := nt3 MULTISET EXCEPT DISTINCT nt2;
  print_nested_table(answer);
END;
/

Example #10 assigns the results of several MULTISET operations and one SET
function invocation of the nested table variable answer, using the procedure print_
nested_table to print answer after each assignment. The procedure use the
collection methods FIRST and LAST

Multidimensional Collections::
***************************

Although a collection has only one dimension, you can model a multidimensional
collection with a collection whose elements are collections.

Example #11 Two-Dimensional Varray (Varray of Varrays)::
....................................................................................................

DECLARE
  TYPE t1 IS VARRAY(10) OF INTEGER;  -- varray of integer
  va t1 := t1(2,3,5);
  TYPE nt1 IS VARRAY(10) OF t1;      -- varray of varray of integer
  nva nt1 := nt1(va, t1(55,6,73), t1(2,4), va);
  i INTEGER;
  va1 t1;
BEGIN
  i := nva(2)(3);
  DBMS_OUTPUT.PUT_LINE('i = ' || i);
  nva.EXTEND;
  nva(5) := t1(56, 32);          -- replace inner varray elements
  nva(4) := t1(45,43,67,43345);  -- replace an inner integer element
  nva(4)(4) := 1;                -- replace 43345 with 1
  nva(4).EXTEND;    -- add element to 4th varray element
  nva(4)(5) := 89;  -- store integer 89 there
END;
/

In Example 11, nva is a two-dimensional varray—a varray of varrays of integers.

Example #12 Nested Tables of Nested Tables and Varrays of Integers::
***********************************************************

DECLARE
  TYPE tb1 IS TABLE OF VARCHAR2(20);  -- nested table of strings
  vtb1 tb1 := tb1('one', 'three');
  TYPE ntb1 IS TABLE OF tb1; -- nested table of nested tables of strings
  vntb1 ntb1 := ntb1(vtb1);
  TYPE tv1 IS VARRAY(10) OF INTEGER;  -- varray of integers
TYPE ntb2 IS TABLE OF tv1;          -- nested table of varrays of integers
  vntb2 ntb2 := ntb2(tv1(3,5), tv1(5,7,3));
BEGIN
  vntb1.EXTEND;
  vntb1(2) := vntb1(1);

  vntb1.DELETE(1);     -- delete first element of vntb1
  vntb1(2).DELETE(1);  -- delete first string from second table in nested table
END;
/

Example #13 Nested Tables of Associative Arrays and Varrays of Strings::
**************************************************************

DECLARE
  TYPE tb1 IS TABLE OF INTEGER INDEX BY PLS_INTEGER;  -- associative arrays
  v4 tb1;
  v5 tb1;
  TYPE ntb1 IS TABLE OF tb1 INDEX BY PLS_INTEGER;  -- nested table of
  v2 ntb1;                                         --  associative arrays
  TYPE va1 IS VARRAY(10) OF VARCHAR2(20);  -- varray of strings
  v1 va1 := va1('hello', 'world');
  TYPE ntb2 IS TABLE OF va1 INDEX BY PLS_INTEGER;  -- nested table of varrays
  v3 ntb2;
BEGIN
  v4(1)   := 34;     -- populate associative array
  v4(2)   := 46456;
  v4(456) := 343;
  v2(23) := v4;  -- populate nested table of associative arrays
  v3(34) := va1(33, 456, 656, 343);  -- populate nested table of varrays
  v2(35) := v5;      -- assign empty associative array to v2(35)
  v2(35)(2) := 78;
END;
/

In Example 13, ntb1 is a nested table of associative arrays, and ntb2 is a nested
table of varrays of strings

Collection Comparisons::
**********************

You cannot compare associative array variables to the value NULL or to each other.
Except for Comparing Nested Tables for Equality and Inequality, you cannot natively
compare two collection variables with relational operators

For example, a collection variable
cannot appear in a DISTINCT, GROUP BY, or ORDER BY clause.

Comparing Varray and Nested Table Variables to NULL::
************************************************
You can compare varray and nested table variables to the value NULL with the "IS
[NOT] NULL Operator"

Example #14 compares a varray variable and a nested table variable to NULL
correctly.

Example #14 Comparing Varray and Nested Table Variables to NULL::
***********************************************************

DECLARE
  TYPE Foursome IS VARRAY(4) OF VARCHAR2(15);  -- VARRAY type
  team Foursome;                               -- varray variable

  TYPE Roster IS TABLE OF VARCHAR2(15);        -- nested table type
  names Roster := Roster('Adams', 'Patel');    -- nested table variable
BEGIN
IF team IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('team IS NULL');
  ELSE
    DBMS_OUTPUT.PUT_LINE('team IS NOT NULL');
  END IF;
  IF names IS NOT NULL THEN
    DBMS_OUTPUT.PUT_LINE('names IS NOT NULL');
  ELSE
    DBMS_OUTPUT.PUT_LINE('names IS NULL');
  END IF;
END;
/

Comparing Nested Tables for Equality and Inequality::
.............................................................................................

If two nested table variables have the same nested table type, and that nested table
type does not have elements of a record type, then you can compare the two variables
for equality or inequality with the relational operators equal (=) and not equal (<>, !=,
~=, ^=). Two nested table variables are equal if and only if they have the same set of
elements (in any order)

Example #15 compares nested table variables for equality and inequality with
relational operators

Example #15 Comparing Nested Tables for Equality and Inequality::
...................................................................................................................

DECLARE
  TYPE dnames_tab IS TABLE OF VARCHAR2(30); -- element type is not record type
  dept_names1 dnames_tab :=
    dnames_tab('Shipping','Sales','Finance','Payroll');
  dept_names2 dnames_tab :=
    dnames_tab('Sales','Finance','Shipping','Payroll');
  dept_names3 dnames_tab :=
    dnames_tab('Sales','Finance','Payroll');
BEGIN
  IF dept_names1 = dept_names2 THEN
    DBMS_OUTPUT.PUT_LINE('dept_names1 = dept_names2');
  END IF;
IF dept_names2 != dept_names3 THEN
    DBMS_OUTPUT.PUT_LINE('dept_names2 != dept_names3');
  END IF;
END;
/
Comparing Nested Tables with SQL Multiset Conditions::
************************************************

You can compare nested table variables, and test some of their properties, with SQL
multiset conditions (described in Oracle Database SQL Language Reference).

Example #16   uses the SQL multiset conditions and two SQL functions that take
nested table variable arguments, CARDINALITY (described in Oracle Database SQL
Language Reference) and SET (described in Oracle Database SQL Language Reference).

Example #16 Comparing Nested Tables with SQL Multiset Conditions:

DECLARE
  TYPE nested_typ IS TABLE OF NUMBER;
  nt1 nested_typ := nested_typ(1,2,3);
  nt2 nested_typ := nested_typ(3,2,1);
  nt3 nested_typ := nested_typ(2,3,1,3);
  nt4 nested_typ := nested_typ(1,2,4);
  PROCEDURE testify (
    truth BOOLEAN := NULL,
    quantity NUMBER := NULL
  ) IS
  BEGIN
    IF truth IS NOT NULL THEN
      DBMS_OUTPUT.PUT_LINE (
        CASE truth
           WHEN TRUE THEN 'True'
           WHEN FALSE THEN 'False'
        END
      );
    END IF;
IF quantity IS NOT NULL THEN
        DBMS_OUTPUT.PUT_LINE(quantity);
    END IF;
  END;
BEGIN
  testify(truth => (nt1 IN (nt2,nt3,nt4)));        -- condition
  testify(truth => (nt1 SUBMULTISET OF nt3));      -- condition
  testify(truth => (nt1 NOT SUBMULTISET OF nt4));  -- condition
  testify(truth => (4 MEMBER OF nt1));             -- condition
  testify(truth => (nt3 IS A SET));                -- condition
  testify(truth => (nt3 IS NOT A SET));            -- condition
  testify(truth => (nt1 IS EMPTY));                -- condition
  testify(quantity => (CARDINALITY(nt3)));         -- function
  testify(quantity => (CARDINALITY(SET(nt3))));    -- 2 functions
END;
/

Collection Methods::
******************

A collection method is a PL/SQL subprogram—either a function that returns
information about a collection or a procedure that operates on a collection. Collection
methods make collections easier to use and your applications easier to maintain.

Note: With a null collection, EXISTS is the only collection method
that does not raise the predefined exception COLLECTION_IS_NULL

Method                    Type                  Description

DELETE                Procedure            Deletes elements from collection.
TRIM                   Procedure            Deletes elements from end of varray or nested table.
EXTEND              Procedure            Adds elements to end of varray or nested table.
EXISTS                Function               Returns TRUE if and only if specified element of varray or nested
                                                         table exists.
FIRST                  Function               Returns first index in collection.
LAST                   Function               Returns last index in collection.
COUNT               Function               Returns number of elements in collection.
LIMIT                  Function               Returns maximum number of elements that collection can have.
PRIOR                 Function               Returns index that precedes specified index.
NEXT                  Function               Returns index that succeeds specified index.


DELETE Collection Method::
************************

DELETE is a procedure that deletes elements from a collection. This method has these
forms:
DELETE deletes all elements from a collection of any type.
This operation immediately frees the memory allocated to the deleted elements.
From an associative array or nested table:
DELETE(n) deletes the element whose index is n, if that element exists;
otherwise, it does nothing.
DELETE(m,n) deletes all elements whose indexes are in the range m..n, if both
m and n exist and m <= n; otherwise, it does nothing.

Example #17 declares a nested table variable, initializing it with six elements; deletes
and then restores the second element; deletes a range of elements and then restores
one of them; and then deletes all elements. The restored elements occupy the same
memory as the corresponding deleted elements. The procedure print_nt prints the
nested table variable after initialization and after each DELETE operation. The type
nt_type and procedure print_nt are defined in Example #6.

Example 17 DELETE Method with Nested Table::

DECLARE
  nt nt_type := nt_type(11, 22, 33, 44, 55, 66);
BEGIN
  print_nt(nt);
  nt.DELETE(2);     -- Delete second element
  print_nt(nt);
nt(2) := 2222;    -- Restore second element
  print_nt(nt);
nt.DELETE(2, 4);  -- Delete range of elements
  print_nt(nt);
nt(3) := 3333;    -- Restore third element
  print_nt(nt);
nt.DELETE;        -- Delete all elements
  print_nt(nt);
END;

Example #18 populates an associative array indexed by string and deletes all
elements, which frees the memory allocated to them. Next, the example replaces the
deleted elements—that is, adds new elements that have the same indexes as the
deleted elements. The new replacement elements do not occupy the same memory as
the corresponding deleted elements. Finally, the example deletes one element and then
a range of elements. The procedure print_aa_str shows the effects of the
operations.


Example #18   DELETE Method with Associative Array Indexed by String::
**************************************************************

DECLARE
  TYPE aa_type_str IS TABLE OF INTEGER INDEX BY VARCHAR2(10);
  aa_str  aa_type_str;
  PROCEDURE print_aa_str IS
    i  VARCHAR2(10);
  BEGIN
    i := aa_str.FIRST;
    IF i IS NULL THEN
      DBMS_OUTPUT.PUT_LINE('aa_str is empty');
    ELSE
      WHILE i IS NOT NULL LOOP
        DBMS_OUTPUT.PUT('aa_str.(' || i || ') = '); print(aa_str(i));
        i := aa_str.NEXT(i);
      END LOOP;
    END IF;
    DBMS_OUTPUT.PUT_LINE('---');
  END print_aa_str;
BEGIN
  aa_str('M') := 13;
  aa_str('Z') := 26;
  aa_str('C') := 3;
  print_aa_str;
  aa_str.DELETE;  -- Delete all elements
  print_aa_str;
aa_str('M') := 13;   -- Replace deleted element with same value
aa_str('Z') := 260;  -- Replace deleted element with new value
aa_str('C') := 30;   -- Replace deleted element with new value
  aa_str('W') := 23;   -- Add new element
  aa_str('J') := 10;   -- Add new element
  aa_str('N') := 14;   -- Add new element
  aa_str('P') := 16;   -- Add new element
  aa_str('W') := 23;   -- Add new element
  aa_str('J') := 10;   -- Add new element
  print_aa_str;
  aa_str.DELETE('C');      -- Delete one element
  print_aa_str;
aa_str.DELETE('N','W');  -- Delete range of elements
  print_aa_str;
aa_str.DELETE('Z','M');  -- Does nothing
  print_aa_str;
END;
/

Example #19 declares a nested table variable, initializing it with six elements; trims
the last element; deletes the fourth element; and then trims the last two elements—one
of which is the deleted fourth element. The procedure print_nt prints the nested
table variable after initialization and after the TRIM and DELETE operations. The type
nt_type and procedure print_nt are defined in Example #6.


Example #19 TRIM Method with Nested Table::
*****************************************
DECLARE
  nt nt_type := nt_type(11, 22, 33, 44, 55, 66);
BEGIN
  print_nt(nt);
  nt.TRIM;       -- Trim last element
  print_nt(nt);
nt.DELETE(4);  -- Delete fourth element
  print_nt(nt);
nt.TRIM(2);    -- Trim last two elements
  print_nt(nt);
END;
/

Example #20 EXTEND Method with Nested Table::
*******************************************

DECLARE
  nt nt_type := nt_type(11, 22, 33);
BEGIN
  print_nt(nt);
  nt.EXTEND(2,1);  -- Append two copies of first element
  print_nt(nt);
nt.DELETE(5);    -- Delete fifth element
  print_nt(nt);
nt.EXTEND;       -- Append one null element
  print_nt(nt);
END;
/

Example #21 EXISTS Method with Nested Table::
******************************************

DECLARE
  TYPE NumList IS TABLE OF INTEGER;
  n NumList := NumList(1,3,5,7);
BEGIN
  n.DELETE(2); -- Delete second element
  FOR i IN 1..6 LOOP
    IF n.EXISTS(i) THEN
      DBMS_OUTPUT.PUT_LINE('n(' || i || ') = ' || n(i));
    ELSE
      DBMS_OUTPUT.PUT_LINE('n(' || i || ') does not exist');
    END IF;
  END LOOP;
END;
/

Example #22 FIRST and LAST Values for Associative Array Indexed by PLS_INTEGER:::
*************************************************************************

DECLARE
  TYPE aa_type_int IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
  aa_int  aa_type_int;
  PROCEDURE print_first_and_last IS
  BEGIN
    DBMS_OUTPUT.PUT_LINE('FIRST = ' || aa_int.FIRST);
    DBMS_OUTPUT.PUT_LINE('LAST = ' || aa_int.LAST);
  END print_first_and_last;
BEGIN
  aa_int(1) := 3;
  aa_int(2) := 6;
  aa_int(3) := 9;
  aa_int(4) := 12;
  DBMS_OUTPUT.PUT_LINE('Before deletions:');
  print_first_and_last;
  aa_int.DELETE(1);
aa_int.DELETE(4);
  DBMS_OUTPUT.PUT_LINE('After deletions:');
  print_first_and_last;
END;
/

COUNT Collection Method::
************************

COUNT is a function that returns the number of elements in the collection (ignoring
deleted elements, even if DELETE kept placeholders for them).

Example #26 COUNT and LAST Values for Varray::
******************************************

DECLARE
  TYPE NumList IS VARRAY(10) OF INTEGER;
  n NumList := NumList(1,3,5,7);
  PROCEDURE print_count_and_last IS
  BEGIN
    DBMS_OUTPUT.PUT('n.COUNT = ' || n.COUNT || ', ');
    DBMS_OUTPUT.PUT_LINE('n.LAST = ' || n.LAST);
  END  print_count_and_last;
BEGIN
  print_count_and_last;
  n.EXTEND(3);
  print_count_and_last;
n.TRIM(5);
  print_count_and_last;
END;
/

LIMIT Collection Method::
**********************

LIMIT is a function that returns the maximum number of elements that the collection
can have. If the collection has no maximum number of elements, LIMIT returns NULL.
Only a varray has a maximum size.

Example #28 LIMIT and COUNT Values for Different Collection Types::


DECLARE
  TYPE aa_type IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
  aa aa_type;                          -- associative array
  TYPE va_type IS VARRAY(4) OF INTEGER;
  va  va_type := va_type(2,4);   -- varray
  TYPE nt_type IS TABLE OF INTEGER;
  nt  nt_type := nt_type(1,3,5);  -- nested table
BEGIN
  aa(1):=3; aa(2):=6; aa(3):=9; aa(4):= 12;
  DBMS_OUTPUT.PUT('aa.COUNT = '); print(aa.COUNT);
  DBMS_OUTPUT.PUT('aa.LIMIT = '); print(aa.LIMIT);
  DBMS_OUTPUT.PUT('va.COUNT = '); print(va.COUNT);
  DBMS_OUTPUT.PUT('va.LIMIT = '); print(va.LIMIT);
  DBMS_OUTPUT.PUT('nt.COUNT = '); print(nt.COUNT);
  DBMS_OUTPUT.PUT('nt.LIMIT = '); print(nt.LIMIT);
END;

Example #29 PRIOR and NEXT Methods::
***********************************

DECLARE
  TYPE nt_type IS TABLE OF NUMBER;
  nt nt_type := nt_type(18, NULL, 36, 45, 54, 63);
BEGIN
  nt.DELETE(4);
  DBMS_OUTPUT.PUT_LINE('nt(4) was deleted.');
  FOR i IN 1..7 LOOP
    DBMS_OUTPUT.PUT('nt.PRIOR(' || i || ') = '); print(nt.PRIOR(i));
    DBMS_OUTPUT.PUT('nt.NEXT(' || i || ')  = '); print(nt.NEXT(i));
  END LOOP;
END;
/

Example #30 prints the elements of a sparse nested table from first to last, using
FIRST and NEXT, and from last to first, using LAST and PRIOR.

Example #30 Printing Elements of Sparse Nested Table::
************************************************

DECLARE
  TYPE NumList IS TABLE OF NUMBER;
  n NumList := NumList(1, 2, NULL, NULL, 5, NULL, 7, 8, 9, NULL);
  idx INTEGER;
BEGIN
  DBMS_OUTPUT.PUT_LINE('First to last:');
  idx := n.FIRST;
  WHILE idx IS NOT NULL LOOP
    DBMS_OUTPUT.PUT('n(' || idx || ') = ');
    print(n(idx));
    idx := n.NEXT(idx);
  END LOOP;
 
  DBMS_OUTPUT.PUT_LINE('--------------');
  DBMS_OUTPUT.PUT_LINE('Last to first:');
  idx := n.LAST;
  WHILE idx IS NOT NULL LOOP
    DBMS_OUTPUT.PUT('n(' || idx || ') = ');
    print(n(idx));
    idx := n.PRIOR(idx);
  END LOOP;
END;
/

Posted by Manoja at 01:01
Email This
BlogThis!
Share to Twitter
Share to Facebook

Labels: Assigning Values to Collection Variables, Associative arrays in pl/sql, Collection methods in pl/sql, Collections constructors in pl/sql, collections constructors in pl/sql language, collections methods first last next prior count in pl/sql, Comparing Nested Tables for Equality and Inequality, Declaring Associative Array Constant, DELETE Collection Method, EXTEND Method with Nested Table