Tuesday, January 22, 2019

Top 50 Oracle Interview Questions and Answers

1. Difference between varchar and varchar2 data types?

Varchar can store upto 2000 bytes and varchar2 can store upto 4000 bytes. Varchar will occupy space for NULL values and Varchar2 will not occupy any space. Both are differed with respect to space.

2. In which language Oracle has been developed?

Oracle has been developed using C Language.

 3. What is RAW datatype?

RAW datatype is used to store values in binary data format. The maximum size for a raw in a table in 32767 bytes.

4. What is the use of NVL function?

The NVL function is used to replace NULL values with another or given value. Example is –

NVL(Value, replace value)

5. Whether any commands are used for Months calculation? If so, What are they?

In Oracle, months_between function is used to find number of months between the given dates. Example is –

Months_between(Date 1, Date 2)

6. What are nested tables?

   Nested table is a data type in Oracle which is used to support columns containing multi valued attributes. It also hold entire sub table.

7. What is COALESCE function?

COALESCE function is used to return the value which is set to be not null in the list. If all values in the list are null, then the coalesce function will return NULL.

Coalesce(value1, value2,value3,…)

8. What is BLOB datatype?

A BLOB data type is a varying length binary string which is used to store two gigabytes memory. Length should be specified in Bytes for BLOB.

9. How do we represent comments in Oracle?

Comments in Oracle can be represented in two ways –

    Two dashes(–) before beginning of the line – Single statement
    /*—— */ is used to represent it as comments for block of statement

10. What is DML?

Data Manipulation Language (DML) is used to access and manipulate data in the existing objects.  DML statements are insert, select, update and delete and it won’t implicitly commit the current transaction.

11. What is the difference between TRANSLATE and REPLACE?

Translate is used for character by character substitution and Replace is used substitute a single character with a word.

12. How do we display rows from the table without duplicates?

Duplicate rows can be removed by using the keyword DISTINCT in the select statement.

13. What is the usage of Merge Statement?

Merge statement is used to select rows from one or more data source for updating and insertion into a table or a view. It is used to combine multiple operations.

14. What is NULL value in oracle?

NULL value represents missing or unknown data. This is used as a place holder or represented it in as default entry to indicate that there is no actual data present.

15. What is USING Clause and give example?

The USING clause is used to specify with the column to test for equality when two tables are joined.

[sql]Select * from employee join salary using employee ID[/sql]

Employee tables join with the Salary tables with the Employee ID.

16. What is key preserved table?

A table is set to be key preserved table if every key of the table can also be the key of the result of the join. It guarantees to return only one copy of each row from the base table.

17. What is WITH CHECK OPTION?

The WITH CHECK option clause specifies check level to be done in DML statements. It is used to prevent changes to a view that would produce results that are not included in the sub query.

18. What is the use of Aggregate functions in Oracle?

Aggregate function is a function where values of multiple rows or records are joined together to get a single value output. Common aggregate functions are –

    Average
    Count
    Sum

19. What do you mean by GROUP BY Clause?

A GROUP BY clause can be used in select statement where it will collect data across multiple records and group the results by one or more columns.

20. What is a sub query and what are the different types of subqueries?

Sub Query is also called as Nested Query or Inner Query which is used to get data from multiple tables. A sub query is added in the where clause of the main query.

There are two different types of subqueries:

    Correlated sub query

A Correlated sub query cannot be as independent query but can reference column in a table listed in the from list of the outer query.

    Non-Correlated subquery

This can be evaluated as if it were an independent query. Results of the sub query are submitted to the main query or parent query.

21. What is cross join?

Cross join is defined as the Cartesian product of records from the tables present in the join. Cross join will produce result which combines each row from the first table with the each row from the second table.

22. What are temporal data types in Oracle?

Oracle provides following temporal data types:

    Date Data Type – Different formats of Dates
    TimeStamp Data Type – Different formats of Time Stamp
    Interval Data Type – Interval between dates and time

23. How do we create privileges in Oracle?

A privilege is nothing but right to execute an SQL query or to access another user object. Privilege can be given as system privilege or user privilege.

[sql]GRANT user1 TO user2 WITH MANAGER OPTION;[/sql]

24. What is VArray?

VArray is an oracle data type used to have columns containing multivalued attributes and it can hold bounded array of values.

25. How do we get field details of a table?

Describe <Table_Name> is used to get the field details of a specified table.

26. What is the difference between rename and alias?

Rename is a permanent name given to a table or a column whereas Alias is a temporary name given to a table or column. Rename is nothing but replacement of name and Alias is an alternate name of the table or column.

27. What is a View?

View is a logical table which based on one or more tables or views.  The tables upon which the view is based are called Base Tables and it doesn’t contain data.

28. What is a cursor variable?

A cursor variable is associated with different statements which can hold different values at run time. A cursor variable is a kind of reference type.

29. What are cursor attributes?

Each cursor in Oracle has set of attributes which enables an application program to test the state of the cursor. The attributes can be used to check whether cursor is opened or closed, found or not found and also find row count.

30. What are SET operators?

SET operators are used with two or more queries and those operators are Union, Union All, Intersect and Minus.

31. How can we delete duplicate rows in a table?

Duplicate rows in the table can be deleted by using ROWID.

32. What are the attributes of Cursor?

Attributes of Cursor are

    %FOUND

Returns NULL if cursor is open and fetch has not been executed

Returns TRUE if the fetch of cursor is executed successfully.

Returns False if no rows are returned.

    %NOT FOUND

Returns NULL if cursor is open and fetch has not been executed

Returns False if fetch has been executed

Returns True if no row was returned

    %ISOPEN

Returns true if the cursor is open

Returns false if the cursor is closed

    %ROWCOUNT

Returns the number of rows fetched. It has to be iterated through entire cursor to give exact real count.

33. Can we store pictures in the database and if so, how it can be done?

Yes, we can store pictures in the database by Long Raw Data type. This datatype is used to store binary data for 2 gigabytes of length. But the table can have only on Long Raw data type.

34. What is an integrity constraint?

An integrity constraint is a declaration defined a business rule for a table column. Integrity constraints are used to ensure accuracy and consistency of data in a database. There are types – Domain Integrity, Referential Integrity and Domain Integrity.

35. What is an ALERT?

An alert is a window which appears in the center of the screen overlaying a portion of the current display.

36. What is hash cluster?

Hash Cluster is a technique used to store the table for faster retrieval. Apply hash value on the table to retrieve the rows from the table.

37. What are the various constraints used in Oracle?

Following are constraints used:

    NULL – It is to indicate that particular column can contain NULL values
    NOT NULL – It is to indicate that particular column cannot contain NULL values
    CHECK – Validate that values in the given column to meet the specific criteria
    DEFAULT – It is to indicate the value is assigned to default value

38. What is difference between SUBSTR and INSTR?

SUBSTR returns specific portion of a string and INSTR provides character position in which a pattern is found in a string.

SUBSTR returns string whereas INSTR returns numeric.

39. What is the parameter mode that can be passed to a procedure?

IN, OUT and INOUT are the modes of parameters that can be passed to a procedure.

40. What are the different Oracle Database objects?

There are different data objects in Oracle –

    Tables – set of elements organized in vertical and horizontal
    Views  – Virtual table derived from one or more tables
    Indexes – Performance tuning method for processing the records
    Synonyms – Alias name for tables
    Sequences – Multiple users generate unique numbers
    Tablespaces – Logical storage unit in Oracle

41. What are the differences between LOV and List Item?

LOV is property whereas list items are considered as single item. List of items is set to be a collection of list of items. A list item can have only one column, LOV can have one or more columns.

42. What are privileges and Grants?

Privileges are the rights to execute SQL statements – means Right to connect and connect. Grants are given to the object so that objects can be accessed accordingly. Grants can be provided by the owner or creator of an object.

43. What is the difference between $ORACLE_BASE and $ORACLE_HOME?

Oracle base is the main or root directory of an oracle whereas ORACLE_HOME is located beneath base folder in which all oracle products reside.

44. What is the fastest query method to fetch data from the table?

Row can be fetched from table by using ROWID. Using ROW ID is the fastest query method to fetch data from the table.

45. What is the maximum number of triggers that can be applied to a single table?

12 is the maximum number of triggers that can be applied to a single table.

46. How to display row numbers with the records?

Display row numbers with the records numbers –
Select rownum, <fieldnames> from table;
1
  
Select rownum, <fieldnames> from table;

This query will display row numbers and the field values from the given table.

47. How can we view last record added to a table?

Last record can be added to a table and this can be done by –
Select * from (select * from employees order by rownum desc) where rownum<2;
1
  
Select * from (select * from employees order by rownum desc) where rownum<2;



48. What is the data type of DUAL table?

The DUAL table is a one-column table present in oracle database.  The table has a single VARCHAR2(1) column called DUMMY which has a value of ‘X’.

49. What is difference between Cartesian Join and Cross Join?

There are no differences between the join. Cartesian and Cross joins are same. Cross join gives cartesian product of two tables – Rows from first table is multiplied with another table which is called cartesian product.

Cross join without where clause gives Cartesian product.

50. How to display employee records who gets more salary than the average salary in the department?

This can be done by this query –
Select * from employee where salary>(select avg(salary) from dept, employee where dept.deptno = employee.deptno;
1
  
Select * from employee where salary>(select avg(salary) from dept, employee where dept.deptno = employee.deptno;

Monday, May 29, 2017

Oracle Interview Questions and Answers - SQL Queries and Database

1. What is oracle database ?
Oracle Database is a relational database management system (RDBMS) which is used to store and retrieve the large amounts of data. Oracle Database had physical and logical structures. Logical structures and physical structures are separated from each other
2. Explain oracle grid architecture?
Grid computing is a information technology architecture that provides lower cost enterprise information systems. Using grid computing, independent hardware, and software components can be connected and rejoined on demand to meet the changing needs of businesses. It also enables the use of smaller individual hardware components.
3. What is the difference between large dedicated server and oracle grid?
Large dedicated server:
  • It has expensive costly components.
  • High incremental costs.
  • It has single point of failure.
  • Enterprise service at higher cost.
Oracle Grid:
  • It has low cost modular components.
  • Low incremental costs.
  • It has no single point of failure.
  • Enterprise service at low cost.
4. What are the computing components of oracle grid?
The computing componenets of oracle grid are:
  • Oracle Enterprise Manager and Grid Control
  • Oracle 10g Database and Real Application Clusters.
  • ASM Storage Grid.
5. What is server virtualization?
Oracle Real Application Clusters 10g (RAC) enables a single database to run across multiple clustered nodes in a grid, pooling the processing resources of several standard machines.

6. What is storage virtualization?
The Oracle Automatic Storage Management (ASM) is a feature of Oracle Database 10g which provides a virtual layer between the database and storage so that group of disks can be treated as a single disk group and disks can be dynamically added or removed while keeping databases online.
Also Read Basic to Advanced Oracle SQL Query Interview Question and Answers
7. What is Grid Management feature?
The Grid Management feature of Oracle Enterprise Manager 10g provides a single console to manage multiple systems together as a logical group.
8. When oracle allocates an SGA?
When Oracle starts, it reads the initialization parameter file to determine the values of initialization parameters. After this, it allocates an SGA and creates background processes.
9. What is an oracle instance?
When you start, the database instance comes into picture into system memory. Combination of the SGA and the Oracle processes is called an Oracle instance.
10. What are the several tools for interacting with the oracle database using sql?
There are several tools for interfacing with the database using SQL:
  • Oracle SQL*Plus and iSQL*Plus 
  • Oracle Forms, Reports, and Discoverer
  • Oracle Enterprise Manager 
  • Third-party tools
11. How oracle works?
  • An instance has started on the database server.
  • A client established a connection to the server, using the proper Oracle Net Services driver.
  • The server creates a dedicated server process on behalf of the user process.
  • The user executes SQL statement and commits the transaction.
  • The server process receives the statement and checks for any shared SQL area that contains a similar SQL.
  • The server process retrieves data from datafile (table) or SGA.
  • The server process modifies data in the SGA area. The DBWn process writes modified blocks permanently to disk. The LGWR process records the transaction in the redo log file.
  • The server process sends a message to the application.

12. What contains oracle physical database structure?
It contains
  • Datafiles
  • Control Files
  • Redo Log Files
  • Archive Log Files
  • Parameter Files
  • Alert and Trace Log Files
  • Backup Files
13. What is a Tablespace?
Oracle use Tablespace for logical data Storage. Physically, data will get stored in Datafiles. Datafiles will be connected to tablespace. A tablespace can have multiple datafiles. A tablespace can have objects from different schema's and a schema can have multiple tablespace's. Database creates "SYSTEM tablespace" by default during database creation. It contains read only data dictionary tables which contains the information about the database. 
14. What is a Control File ?
Control file is a binary file which stores Database name, associated data files, redo files, DB creation time and current log sequence number. Without control file database cannot be started and can hamper data recovery.
15. What are data blocks?
Oracle stores data in data blocks also called as logical blocks, Oracle blocks or pages. A data block represents specific number of bytes of space on disk.
16. What is an extent?
An extent is a specific number of consecutive data blocks allocated for storing a specific type of information.
17. What is a segment?
A segment is a group of extents, each of which has been allocated for a specific data structure and all of which are stored in the same table-space.
18. What is Rollback Segment ? 
Database contain one or more Rollback Segments to roll back transactions and data recovery.
19. What are the different type of Segments ? 
Data Segment(for storing User Data), Index Segment (for storing index), Rollback Segment and Temporary Segment.
20. What is an oracle schema?
A user account and its associated data including tables, views, indexes, clusters, sequences,procedures, functions, triggers,packages and database links is known as Oracle schema. System, SCOTT etc are default schema's. We can create a new Schema/User. But we can't drop default database schema's.
21. When and how oracle database creates a schema?
Oracle Database automatically creates a schema when you create a user.
22. What is a view?
A view is a tailored presentation of the data contained in one or more tables or other views. A view is output of a query and treats it as a table. Therefore, a view can be thought of as a stored query or a virtual table. A view is not assigned any storage space, nor does a view actually contain data.
23. How views are used?
  • It provides security by restricting access to a predetermined set of rows or columns of a table. It hides data complexity. It simplifies statements for the user.
  • An example would be the views, which allow users to select data from multiple tables without actually knowing how to perform a join.
  • It presents the data in a different perspective from that of the base table. It isolate applications from changes in definitions of base tables. It saves complex queries.
24. What are materialized views?
These are schema objects that are used to summarize, compute, replicate, and distribute data. They can be used in various environments for computation such as data warehousing, decision support, and distributed or mobile computing and it also provides local access to data rather than accessing from remote sites. In data warehouses, MVs are used to compute and store aggregated data.

New Oracle Interview questions - Multinationals Oracle Questions Dump

Oracle is a secured database that is widely used in multinational companies. The frequently asked questions from oracle database are given below.

1) What are the components of physical database structure of Oracle database?

Components of physical database structure are given below.
  • One or more data files.
  • Two or more redo log files.
  • One or more control files.

2) What are the components of logical database structure in Oracle database?

Components of logical database structure.
  • Tablespaces
  • Database's schema objects

3) What is a tablespace?

A database contains Logical Storage Unit called tablespaces. A tablespace is a set of related logical structures. Actually a tablespace groups related logical structures together.

4) What is a SYSTEM tablespace and when it is created?

When the database is created in Oracle database system, it automatically generate a SYSTEM named SYSTEM tablespace. The SYSTEM tablespace contains data dictionary tables for the entire database.

5) What is an Oracle table?

A table is basic unit of data storage in Oracle database. A table contains all the accessible information of a user in rows and columns.

6) In the Oracle version 9.3.0.5.0, what does each number shows?

Oracle version number refers:
  • 9 - Major database release number
  • 3 - Database maintenance release number
  • 0 - Application server release number
  • 5 - Component Specific release number
  • 0 - Platform Specific release number

7) What is bulk copy or BCP in Oracle?

Bulk copy or BCP in Oracle, is used to import or export data from tables and views but it does not copy structure of same data.
The main advantage of BCP is fast mechanism for coping data and you can also take the backup of data easily.

8) What is the relationship among database, tablespace and data file?

An Oracle database contains one or more logical storage units called tablespaces. These tablespaces collectively store whole data of databases and each tablespace in Oracle database consists of one or more files called datafiles. These datafiles are physical structure that confirm with the operating system in which Oracle is running.

9) What is a snapshot in Oracle database?

A snapshot is a replica of a target master table from a single point-in-time. In simple words you can say, snapshot is a copy of a table on a remote database.

10) What is the difference between hot backup and cold backup in Oracle? Tell about their benefits also.

Hot backup (Online Backup): A hot backup is also known as online backup because it is done while the database is active. Some sites can not shut down their database while making a backup copy, they are used for 24 hour a day, 7 days a week.
Cold backup (Offline Backup): A cold backup is also known as offline backup because it is done while the database has been shutdown using the SHUTDOWN normal command. If the database is suddenly shutdown with a uncertain condition it should be restarted with RESTRICT mode and then shutdown with NORMAL option.
For a complete cold backup the following files must be backed up.
All datafiles, All control files, All online redo log files(optional) and the init.ora file (you can recreate it manually).

11) How many memory layers are in the Oracle shared pool?

Oracle shared pools contains two layers:
  1. library cache
  2. data dictionary cache

12) What is save point in Oracle database?

Save points are used to divide a transaction into smaller parts. It allows rolling back of a transaction. Maximum five save points are allowed. It is used to save our data, whenever you encounter an error you can roll back from the point where you save your SAVEPOINT.

13) What is hash cluster in Oracle?

Hash cluster is a technique to store a data in hash table and improve the performance of data retrieval. Hash function is applied on table row's cluster key value and store in hash cluster.

14) What are the various Oracle database objects?

Tables: This is a set of elements organized in vertical and horizontal fashion.
Tablespaces: This is a logical storage unit in Oracle.
Views: It is virtual table derived from one or more tables.
Indexes: This is a performance tuning method to process the records.
Synonyms: This is a name for tables.

15) What is the difference between pre-select and pre-query?

A pre-query trigger fire before the query executes and fire once while you try to query. With the help of this trigger you can modify the where clause part dynamically.
Pre-select query fires during the execute query and count query processing after Oracle forms construct the select statement to be issued, but before the statement is actually issued.
Pre-query trigger fires before Pre-select trigger.

16) What are the different types of modules in Oracle forms?

Following are the different modules in Oracle forms:
  • Form module
  • Menu module
  • Pl/SQL Library module
  • Object Library module

17) What is the usage of ANALYZE command in Oracle?

ANALYZE command is used to perform various functions on index, table, or cluster. The following list specifies the usage of ANALYZE command in Oracle:
  • It is used to identify migrated and chained rows of the table or cluster.
  • It is used to validate the structure of the object.
  • It helps in collecting the statistics about object used by the optimizer. They are then stored in the data dictionary.
  • It helps in deleting statistics used by object from the data dictionary.

18) Can you create a synonym without having a table?

Yes. We can create a synonym without having a base table.

19) What types of joins are used in writing SUBQUERIES?

  • Self join
  • Outer Join
  • Equi-join

20) What is the usage of control file in Oracle?

In Oracle, control file is used for database recovery. The control file is also used to identify the database and redo log files that must be opened for database operation to go ahead, whenever an instance of an ORACLE database begins.

21) What is a synonym?

A synonym is also known as alias for a table, view, sequence or program unit.

22) What are the different types of synonyms?

There are two types of synonyms or alias:
Private: It can only accessed by the owner.
Public: It can be accessed by any database user.

23) What is the usage of synonyms?

  • Synonym can be used to hide the real name and owner of an object.
  • It provides public access to an object.
  • It also provides location transparency for tables, views or program units of a remote database.
  • It simplifies the SQL statements for database users.

24) How do you store pictures in a database?

Yes, you can store pictures in a database using Long Raw Data type. This data type is used to store binary data for 2 gigabytes of length. However, the table can have only one Long Raw data type.

25) What is BLOB data type in Oracle?

BLOB data type is a data type with varying length binary string. It is used to store two gigabytes memory. For BLOB data type, the length needs to be specified in bytes.

26) What is the difference between TRANSLATE and REPLACE in Oracle?

Translate is used to substitute a character by character while Replace is used to substitute a single character with a word.

27) What are the different types of database objects?

A list of different types of database objects:
  • Tables: This is a set of elements organized in vertical and horizontal fashion.
  • Tablespaces: This is a logical storage unit in Oracle.
  • Views: It is virtual table derived from one or more tables.
  • Indexes: This is a performance tuning method to process the records.
  • Synonyms: This is a name for tables.

28) What is the usage of Save Points in Oracle database?

Save Points are used to divide a transaction into smaller phases. It enables rolling back part of a transaction. There are maximum 5 save points allowed in Oracle Database. Whenever an error is encountered, it is possible to rollback from the point where the SAVEPOINT has been saved.

29) What is the difference between post-database commit and post-form commit?

The post-database commit trigger is executed after Oracle forms issue the commit to finalized transaction while, the post-form commit is fired during the post and commit transactions process, after the database commit occurs.

30) What is Logical backup in Oracle?

Logical backup is used to read a set of database records and writing them into a file. An Export utility is used to take the backup while an Import utility is used to recover from the backup.

31) What do you understand by Redo Log file mirroring?

Mirroring is a process of having a copy of Redo log files. It is done by creating group of log files together. This ensures that LGWR automatically writes them to all the members of the current on-line redo log group. If the group fails, the database automatically switches over to the next group. It diminishes the performance.

32) What is the meaning of recursive hints in Oracle?

The number of times a dictionary table is repeatedly called by various processes is known as recursive hint. Recursive hint is occurred because of the small size of data dictionary cache.

33) What are the limitations of CHECK constraint?

The main limitation of CHECK constraint is that the condition must be a Boolean expression evaluated using the values in the row being inserted or updated and can't contain sub queries.

34) What is the use of GRANT option in IMP command?

GRANT is used to import object grants.

35) What is the use of ROWS option in IMP command?

The ROWS option indicates whether the table rows should be imported.

36) What is the use of INDEXES option in IMP command?

The INDEXES option is used to determine whether indexes are imported.

37) What is the use of IGNORE option in IMP command?

The IGNORE option is used to specify how object creation errors should be handled.

38) What is the use of SHOW option in IMP command?

The SHOW option specifies when the value of show=y, the DDL within the export file is displayed.

39) What is the use of FILE param in IMP command?

FILE param is used to specify the name of the export file to import. Multiple files can be listed, separated by commas.

40) How to convert a date to char in Oracle? Give one example.

The to_char() function is used to convert date to character. You can also specify the format in which you want output.
  1. SELECT to_char ( to_date ('12-12-2012''DD-MM-YYYY') , 'YYYY-MM-DD'FROM dual;  
Or,
  1. SELECT to_char ( to_date ('12-12-2012''DD-MM-YYYY') , 'DD-MM-YYYY'FROM dual;  

41) What are actual and formal parameters?

Actual Parameters: Actual parameters are the variables or expressions referenced in the parameter list of a subprogram.
Let's see a procedure call which lists two actual parameters named empno and amt:
  1. raise_sal(empno, amt);  
Formal Parameters: Formal parameters are variables declared in a subprogram specification and referenced in the subprogram body.
Following procedure declares two formal parameters named empid and amt:
  1. PROCEDURE raise_sal(empid INTEGER, amt REALIS current_salary REAL;  

42) What are the extensions used by Oracle reports?

Oracle reports are use to make business enable with the facility to provide information of all level within or outside in a secure way. Oracle report uses REP files and RDF file extensions.

43) How to convert a string to a date in Oracle database?

Syntax: to_date (string , format)
Let us take an example :
  1. to_date ('2012-12-12''YYYY/MM/DD')  
It will return December 12, 2012.

44) How do you find current date and time in Oracle?

The SYSDATE() function is used in Oracle to find the current date and time of operating system on which the database is running.
  1. SELECT TO_CHAR (SYSDATE, 'MM-DD-YYYY HH24:MI:SS'"Current_Date" FROM DUAL;  

45) What will be the syntax to find current date and time in format "YYYY-MM-DD"?

  1. SELECT TO_CHAR (SYSDATE, 'YYYY-MM-DD HH24:MI:SS'"Current_Date" FROM DUAL;  

Monday, May 15, 2017

Introduction to PL/SQL -

What is so great about PL/SQL anyway?

  • PL/SQL is a procedural extension of SQL, making it extremely simple to write procedural code that includes SQL as if it were a single language. In comparison, most other programming languages require mapping data types, preparing statements and processing result sets, all of which require knowledge of specific APIs.
  • The data types in PL/SQL are a super-set of those in the database, so you rarely need to perform data type conversions when using PL/SQL. Ask your average Java or .NET programmer how they find handling date values coming from a database. They can only wish for the simplicity of PL/SQL.
  • When coding business logic in middle tier applications, a single business transaction may be made up of multiple interactions between the application server and the database. This adds a significant overhead associated with network traffic. In comparison, building all the business logic as PL/SQL in the database means client code needs only a single database call per transaction, reducing the network overhead significantly.
    PL/SQL to Improve Performance
  • Oracle is a multi-platform database, making PL/SQL and incredibly portable language. If your business logic is located in the database, you are protecting yourself from operating system lock-in.
  • Programming languages go in and out of fashion continually. Over the last 35+ years Oracle databases have remained part of the enterprise landscape. Suggesting that any language is a safer bet than PL/SQL is rather naive. Placing your business logic in the database makes changing your client layer much simpler if you like to follow fashion.
  • Centralizing application logic enables a higher degree of security and productivity. The use of Application Program Interfaces (APIs) can abstract complex data structures and security implementations from client application developers, leaving them free to do what they do best.

PL/SQL Architecture

The PL/SQL language is actually made up of two distinct languages. Procedural code is executed by the PL/SQL engine, while SQL is sent to the SQL statement executor.
PL/SQL Architecture
For the most part, the tight binding between these two languages make PL/SQL look like a single language to most developers.

Overview of PL/SQL Elements

Blocks

Blocks are the organizational unit for all PL/SQL code, whether it is in the form of an anonymous block, procedure, function, trigger or type. A PL/SQL block is made up of three sections (declaration, executable and exception), of which only the executable section is mandatory.
[DECLARE
  -- delarations]
BEGIN
  -- statements
[EXCEPTION
  -- handlers
END;
Based on this definition, the simplest valid block is shown below, but it doesn't do anything.
BEGIN
  NULL;
END;
The optional declaration section allows variables, types, procedures and functions do be defined for use within the block. The scope of these declarations is limited to the code within the block itself, or any nested blocks or procedure calls. The limited scope of variable declarations is shown by the following two examples. In the first, a variable is declared in the outer block and is referenced successfully in a nested block. In the second, a variable is declared in a nested block and referenced from the outer block, resulting in an error as the variable is out of scope.
DECLARE
  l_number  NUMBER;
BEGIN
  l_number := 1;
  
  BEGIN
    l_number := 2;
  END;
END;
/

PL/SQL procedure successfully completed.

BEGIN
  DECLARE
    l_number  NUMBER;
  BEGIN
    l_number := 1;
  END;

  l_number := 2;
END;
/
  l_number := 2;
  *
ERROR at line 8:
ORA-06550: line 8, column 3:
PLS-00201: identifier 'L_NUMBER' must be declared
ORA-06550: line 8, column 3:
PL/SQL: Statement ignored

SQL>
The main work is done in the mandatory executable section of the block, while the optional exception section is where all error processing is placed. The following two examples demonstrate the usage of exception handlers for trapping error messages. In the first, there is no exception handler so a query returning no rows results in an error. In the second the same error is trapped by the exception handler, allowing the code to complete successfully.
DECLARE
  l_date  DATE;
BEGIN
  SELECT SYSDATE
  INTO   l_date
  FROM   dual
  WHERE  1=2; -- For zero rows
END;
/
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4


DECLARE
  l_date  DATE;
BEGIN
  SELECT SYSDATE
  INTO   l_date
  FROM   dual
  WHERE  1=2; -- For zero rows
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    NULL;
END;
/

PL/SQL procedure successfully completed.

SQL>

Variables and Constants

Variables and constants must be declared for use in procedural and SQL code, although the datatypes available in SQL are only a subset of those available in PL/SQL. All variables and constants must be declared before they are referenced. The declarations of variables and constants are similar, but constant definitions must contain the CONSTANT keyword and must be assigned a value as part of the definition. Subsequent attempts to assign a value to a constant will result in an error. The following example shows some basic variable and constant definitions, along with a subsequent assignment of a value to a constant resulting in an error.
DECLARE
  l_string  VARCHAR2(20);
  l_number  NUMBER(10);
  
  l_con_string  CONSTANT VARCHAR2(20) := 'This is a constant.';
BEGIN
  l_string := 'Variable';
  l_number := 1;
  
  l_con_string := 'This will fail';
END;
/
  l_con_string := 'This will fail';
  *
ERROR at line 10:
ORA-06550: line 10, column 3:
PLS-00363: expression 'L_CON_STRING' cannot be used as an assignment target
ORA-06550: line 10, column 3:
PL/SQL: Statement ignored

SQL>
In addition to standard variable declarations used within SQL, PL/SQL allows variable datatypes to match the datatypes of existing columns, rows or cursors using the %TYPE and %ROWTYPE qualifiers, making code maintenance much easier. The following code shows each of these definitions in practice.
DECLARE
  -- Specific column from table.
  l_username  all_users.username%TYPE;
  
  -- Whole record from table.
  l_all_users_row  all_users%ROWTYPE;
  
  CURSOR c_user_data IS
    SELECT username,
           created
    FROM   all_users
    WHERE  username = 'SYS';
    
  -- Record that matches cursor definition. 
  l_all_users_cursor_row  c_user_data%ROWTYPE;
BEGIN
  -- Specific column from table.
  SELECT username
  INTO   l_username
  FROM   all_users
  WHERE  username = 'SYS';
  
  DBMS_OUTPUT.put_line('l_username=' || l_username);
  
  -- Whole record from table.
  SELECT *
  INTO   l_all_users_row
  FROM   all_users
  WHERE  username = 'SYS';

  DBMS_OUTPUT.put_line('l_all_users_row.username=' ||
                        l_all_users_row.username);
  DBMS_OUTPUT.put_line('l_all_users_row.user_id=' ||
                        l_all_users_row.user_id);
  DBMS_OUTPUT.put_line('l_all_users_row.created=' ||
                        l_all_users_row.created);
  
  -- Record that matches cursor definition. 
  OPEN  c_user_data;
  FETCH c_user_data
  INTO  l_all_users_cursor_row;
  CLOSE c_user_data;

  DBMS_OUTPUT.put_line('l_all_users_cursor_row.username=' ||
                        l_all_users_cursor_row.username);
  DBMS_OUTPUT.put_line('l_all_users_cursor_row.created=' ||
                        l_all_users_cursor_row.created);
END;
/
l_username=SYS
l_all_users_row.username=SYS
l_all_users_row.user_id=0
l_all_users_row.created=18-MAR-2004 08:02:17
l_all_users_cursor_row.username=SYS
l_all_users_cursor_row.created=18-MAR-2004 08:02:17

PL/SQL procedure successfully completed.

SQL>
The %TYPE qualifier signifies that the variable datatype should match that of the specified table column, while the %ROWTYPE qualifier signifies that the variable datatype should be a record structure that matches the specified table or cursor structure. Notice that the record structures use the dot notation (variable.column) to reference the individual column data within the record structure.
Values can be assigned to variables directly using the ":=" assignment operator, via a SELECT ... INTO statement or when used as OUT or IN OUT parameter from a procedure. All three assignment methods are shown in the example below.
DECLARE
  l_number  NUMBER;
  
  PROCEDURE add(p1  IN  NUMBER,
                p2  IN  NUMBER,
                p3  OUT  NUMBER) AS
  BEGIN
    p3 := p1 + p2;
  END;
BEGIN
  -- Direct assignment.
  l_number := 1;
  
  -- Assignment via a select.
  SELECT 1
  INTO   l_number
  FROM   dual;
  
  -- Assignment via a procedure parameter.
  add(1, 2, l_number);
END;
/

Using SQL in PL/SQL

The SQL language is fully integrated into PL/SQL, so much so that they are often mistaken as being a single language by newcomers. It is possible to manuallly code the retrieval of data using explicit cursors, or let Oracle do the hard work and use implicit cursors. Examples of both explicit implicit cursors are presented below, all of which rely on the following table definition table.
CREATE TABLE sql_test (
  id           NUMBER(10),
  description  VARCHAR2(10)
);

INSERT INTO sql_test (id, description) VALUES (1, 'One');
INSERT INTO sql_test (id, description) VALUES (2, 'Two');
INSERT INTO sql_test (id, description) VALUES (3, 'Three');
COMMIT;
The SELECT ... INTO statement allows data from one or more columns of a specific row to be retrieved into variables or record structures using an implicit cursor.
SET SERVEROUTPUT ON
DECLARE
  l_description  VARCHAR2(10);
BEGIN
  SELECT description
  INTO   l_description
  FROM   sql_test
  WHERE  id = 1;
  
  DBMS_OUTPUT.put_line('l_description=' || l_description);
END;
/
l_description=One

PL/SQL procedure successfully completed.

SQL>
The previous example can be recoded to use an explicit cursor a shown below. Notice that the cursor is now defined in the declaration section and is explicitly opened and closed, making the code larger and a little ugly.
SET SERVEROUTPUT ON
DECLARE
  l_description  VARCHAR2(10);
  
  CURSOR c_data (p_id  IN  NUMBER) IS
    SELECT description
    FROM   sql_test
    WHERE  id = p_id;
BEGIN
  OPEN c_data (p_id => 1);
  FETCH c_data
  INTO  l_description;
  CLOSE c_data;

  DBMS_OUTPUT.put_line('l_description=' || l_description);
END;
/
l_description=One

PL/SQL procedure successfully completed.

SQL>
When a query returns multiple rows is can be processed within a loop. The following example uses a cursor FOR-LOOP to cycle through multiple rows of an implicit cursor. Notice there is no need for a variable definition as "cur_rec" acts as a pointer to the current record of the cursor.
SET SERVEROUTPUT ON
BEGIN
  FOR cur_rec IN (SELECT description
                  FROM   sql_test)
  LOOP
    DBMS_OUTPUT.put_line('cur_rec.description=' || cur_rec.description);
  END LOOP;
END;
/
cur_rec.description=One
cur_rec.description=Two
cur_rec.description=Three

PL/SQL procedure successfully completed.

SQL>
The explicit cursor version of the previous example is displayed below. Once again the cursor management is all done manually, but this time the exit from the loop must be managed manually also.
SET SERVEROUTPUT ON
DECLARE
  l_description  VARCHAR2(10);
  
  CURSOR c_data IS
    SELECT description
    FROM   sql_test;
BEGIN
  OPEN c_data;
  LOOP
    FETCH c_data
    INTO  l_description;
    EXIT WHEN c_data%NOTFOUND;

    DBMS_OUTPUT.put_line('l_description=' || l_description);
  END LOOP;
  CLOSE c_data;
END;
/
l_description=One
l_description=Two
l_description=Three

PL/SQL procedure successfully completed.

SQL>
In most situations the implicit cursors provide a faster and cleaner solution to data retrieval than their explicit equivalents.

Branching and Conditional Control

The IF-THEN-ELSE and CASE statements allow code to decide on the correct course of action for the current circumstances. In the following example the IF-THEN-ELSE statement is used to decide if today is a weekend day.
SET SERVEROUTPUT ON
DECLARE
  l_day  VARCHAR2(10);
BEGIN
  l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));
  
  IF l_day IN ('SATURDAY', 'SUNDAY') THEN
    DBMS_OUTPUT.put_line('It''s the weekend!');
  ELSE
    DBMS_OUTPUT.put_line('It''s not the weekend yet!');
  END IF;
END;
/
First, the expression between the IF and the THEN is evaluated. If that expression equates to TRUE the code between the THEN and the ELSE is performed. If the expression equates to FALSE the code between the ELSE and the END IF is performed. The IF-THEN-ELSE statement can be extended to cope with multiple decisions by using the ELSIF keyword. The example below uses this extended form to produce a different message for Saturday and Sunday.
SET SERVEROUTPUT ON
DECLARE
  l_day  VARCHAR2(10);
BEGIN
  l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));
  
  IF l_day = 'SATURDAY' THEN
    DBMS_OUTPUT.put_line('The weekend has just started!');
  ELSIF l_day = 'SUNDAY' THEN
    DBMS_OUTPUT.put_line('The weekend is nearly over!');
  ELSE
    DBMS_OUTPUT.put_line('It''s not the weekend yet!');
  END IF;
END;
/
SQL CASE expressions were introduced in the later releases of Oracle 8i, but Oracle 9i included support for CASE statements in PL/SQL for the first time. The CASE statement is the natural replacement for large IF-THEN-ELSIF-ELSE statements. The following code gives an example of a matched CASE statement.
SET SERVEROUTPUT ON
DECLARE
  l_day  VARCHAR2(10);
BEGIN
  l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));
  
  CASE l_day
    WHEN 'SATURDAY' THEN
      DBMS_OUTPUT.put_line('The weekend has just started!');
    WHEN 'SUNDAY' THEN
      DBMS_OUTPUT.put_line('The weekend is nearly over!');
    ELSE
      DBMS_OUTPUT.put_line('It''s not the weekend yet!');
  END CASE;
END;
/
The WHEN clauses of a matched CASE statement simply state the value to be compared. If the value of the variable specified after the CASE keyword matches this comparison value the code after the THEN keyword is performed.
A searched CASE statement has a slightly different format, with each WHEN clause containing a full expression, as shown below.
SET SERVEROUTPUT ON
DECLARE
  l_day  VARCHAR2(10);
BEGIN
  l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));
  
  CASE
    WHEN l_day = 'SATURDAY' THEN
      DBMS_OUTPUT.put_line('The weekend has just started!');
    WHEN l_day = 'SUNDAY' THEN
      DBMS_OUTPUT.put_line('The weekend is nearly over!');
    ELSE
      DBMS_OUTPUT.put_line('It''s not the weekend yet!');
  END CASE;
END;
/

Looping Statements

Loops allow sections of code to be processed multiple times. In its most basic form a loop consists of the LOOP and END LOOP statement, but this form is of little use as the loop will run forever.
BEGIN
  LOOP
    NULL;
  END LOOP;
END;
/
Typically you would expect to define an end condition for the loop using the EXIT WHEN statement along with a Boolean expression. When the expression equates to true the loop stops. The example below uses this syntax to pint out numbers from 1 to 5.
SET SERVEROUTPUT ON
DECLARE
  i  NUMBER := 1;
BEGIN
  LOOP
    EXIT WHEN i > 5;
    DBMS_OUTPUT.put_line(i);
    i := i + 1;
  END LOOP;
END;
/
The placement of the EXIT WHEN statement can affect the processing inside the loop. For example, placing it at the start of the loop means the code within the loop may be executed "0 to many" times, like a while-do loop in other language. Placing the EXIT WHEN at the end of the loop means the code within the loop may be executed "1 to many" times, like a do-while loop in other languages.
The FOR-LOOP statement allows code within the loop to be repeated a specified number of times based on the lower and upper bounds specified in the statement. The example below shows how the previous example could be recorded to use a FOR-LOOP statement.
SET SERVEROUTPUT ON
BEGIN
  FOR i IN 1 .. 5 LOOP
    DBMS_OUTPUT.put_line(i);
  END LOOP;
END;
/
The WHILE-LOOP statement allows code within the loop to be repeated until a specified expression equates to TRUE. The following example shows how the previous examples can be re-coded to use a WHILE-LOOP statement.
SET SERVEROUTPUT ON
DECLARE
  i  NUMBER := 1;
BEGIN
  WHILE i <= 5 LOOP
    DBMS_OUTPUT.put_line(i);
    i := i + 1;
  END LOOP;
END;
/
In addition to these loops a special cursor FOR-LOOP is available as seen previously.

GOTO

The GOTO statement allows a program to branch unconditionally to a predefined label. The following example uses the GOTO statement to repeat the functionality of the examples in the previous section.
SET SERVEROUTPUT ON
DECLARE
  i  NUMBER := 1;
BEGIN
  LOOP
    IF i > 5 THEN
      GOTO exit_from_loop;
    END IF;
    DBMS_OUTPUT.put_line(i);
    i := i + 1;
  END LOOP;
  
  << exit_from_loop >>
  NULL;
END;
/
In this example the GOTO has been made conditional by surrounding it with an IF statement. When the GOTO is called the program execution immediately jumps to the appropriate label, defined using double-angled brackets.

Procedures, Functions and Packages

Procedures and functions allow code to be named and stored in the database, making code reuse simpler and more efficient. Procedures and functions still retain the block format, but the DECLARE keyword is replaced by PROCEDURE or FUNCTION definitions, which are similar except for the additional return type definition for a function. The following procedure displays numbers between upper and lower bounds defined by two parameters, then shows the output when it's run.
CREATE OR REPLACE PROCEDURE display_numbers (
  p_lower  IN   NUMBER,
  p_upper  IN   NUMBER)
AS
BEGIN
  FOR i IN p_lower .. p_upper LOOP
    DBMS_OUTPUT.put_line(i);
  END LOOP;
END;
/
 
SET SERVEROUTPUT ON
EXECUTE display_numbers(2, 6);
2
3
4
5
6

PL/SQL procedure successfully completed.

SQL>
The following function returns the difference between upper and lower bounds defined by two parameters.
CREATE OR REPLACE FUNCTION difference (
  p_lower  IN   NUMBER,
  p_upper  IN   NUMBER)
  RETURN NUMBER
AS
BEGIN
  RETURN p_upper - p_lower;
END;
/

VARIABLE l_result NUMBER
BEGIN
  :l_result := difference(2, 6);
END;
/

PL/SQL procedure successfully completed.

PRINT l_result

  L_RESULT
----------
         4

SQL>
Packages allow related code, along with supporting types, variables and cursors, to be grouped together. The package is made up of a specification that defines the external interface of the package, and a body that contains all the implementation code. The following code shows how the previous procedure and function could be grouped into a package.
CREATE OR REPLACE PACKAGE my_package AS

PROCEDURE display_numbers (
  p_lower  IN   NUMBER,
  p_upper  IN   NUMBER);
  
FUNCTION difference (
  p_lower  IN   NUMBER,
  p_upper  IN   NUMBER)
  RETURN NUMBER;

END;
/

CREATE OR REPLACE PACKAGE BODY my_package AS

PROCEDURE display_numbers (
  p_lower  IN   NUMBER,
  p_upper  IN   NUMBER)
AS
BEGIN
  FOR i IN p_lower .. p_upper LOOP
    DBMS_OUTPUT.put_line(i);
  END LOOP;
END;
  
FUNCTION difference (
  p_lower  IN   NUMBER,
  p_upper  IN   NUMBER)
  RETURN NUMBER
AS
BEGIN
  RETURN p_upper - p_lower;
END;

END;
/
Once the package specification and body are compiled they can be executed as before, provided the procedure and function names are prefixed with the package name.
SET SERVEROUTPUT ON
EXECUTE my_package.display_numbers(2, 6);
2
3
4
5
6

PL/SQL procedure successfully completed.

VARIABLE l_result NUMBER
BEGIN
  :l_result := my_package.difference(2, 6);
END;
/

PL/SQL procedure successfully completed.

PRINT l_result

  L_RESULT
----------
         4

SQL>
Since the package specification defines the interface to the package, the implementation within the package body can be modified without invalidating any dependent code, thus breaking complex dependency chains. A call to any element in the package causes the whole package to be loaded into memory, improving performance compared to loading several individual procedures and functions.

Records

Record types are composite data structures, or groups of data elements, each with its own definition. Records can be used to mimic the row structures of tables and cursors, or as a convenient was to pass data between subprograms without listing large number of parameters.
When a record type must match a particular table or cursor structure it can be defined using the %ROWTYPE attribute, removing the need to define each column within the record manually. Alternatively, the record can be specified manually. The following code provides an example of how records can be declared and used in PL/SQL.
SET SERVEROUTPUT ON
DECLARE
  -- Define a record type manually.
  TYPE t_all_users_record IS RECORD (
    username  VARCHAR2(30),
    user_id   NUMBER,
    created   DATE
  );
  
  -- Declare record variables using the manual and %ROWTYPE methods.
  l_all_users_record_1  t_all_users_record;
  l_all_users_record_2  all_users%ROWTYPE;
BEGIN
  -- Return some data into once record structure.
  SELECT *
  INTO   l_all_users_record_1
  FROM   all_users
  WHERE  username = 'SYS';
  
  -- Display the contents of the first record.
  DBMS_OUTPUT.put_line('l_all_users_record_1.username=' ||
                        l_all_users_record_1.username);
  DBMS_OUTPUT.put_line('l_all_users_record_1.user_id=' ||
                        l_all_users_record_1.user_id);
  DBMS_OUTPUT.put_line('l_all_users_record_1.created=' ||
                        l_all_users_record_1.created);

  -- Assign the values to the second record structure in a single operation.
  l_all_users_record_2 := l_all_users_record_1;
    
  -- Display the contents of the second record.
  DBMS_OUTPUT.put_line('l_all_users_record_2.username=' ||
                        l_all_users_record_2.username);
  DBMS_OUTPUT.put_line('l_all_users_record_2.user_id=' ||
                        l_all_users_record_2.user_id);
  DBMS_OUTPUT.put_line('l_all_users_record_2.created=' ||
                        l_all_users_record_2.created);

  l_all_users_record_1 := NULL;
  
  -- Display the contents of the first record after deletion.
  DBMS_OUTPUT.put_line('l_all_users_record_1.username=' ||
                        l_all_users_record_1.username);
  DBMS_OUTPUT.put_line('l_all_users_record_1.user_id=' ||
                        l_all_users_record_1.user_id);
  DBMS_OUTPUT.put_line('l_all_users_record_1.created=' ||
                        l_all_users_record_1.created);

END;
/
l_all_users_record_1.username=SYS
l_all_users_record_1.user_id=0
l_all_users_record_1.created=18-MAR-2004 08:02:17
l_all_users_record_2.username=SYS
l_all_users_record_2.user_id=0
l_all_users_record_2.created=18-MAR-2004 08:02:17
l_all_users_record_1.username=
l_all_users_record_1.user_id=
l_all_users_record_1.created=

PL/SQL procedure successfully completed.

SQL> 
Notice how the records can be assigned to each other directly, and how all elements within a record can be initialized with a single assignment of a NULL value.

Object Types

Oracle implements Objects through the use of TYPE declarations, defined in a similar way to packages. Unlike packages where the instance of the package is limited to the current session, an instance of an object type can be stored in the database for later use. The definition of the type contains a comma separated list of attributes/properties, defined in the same way as package variables, and member functions/procedures. If a type contains member functions/procedures, the procedural work for these elements is defined in the TYPE BODY.
To see how objects can be used let's assume we want to create one to represent a person. In this case, a person is defined by three attributes (first_name, last_name, date_of_birth). We would also like to be able to return the age of the person, so this is included as a member function (get_age).
CREATE OR REPLACE TYPE t_person AS OBJECT (
  first_name     VARCHAR2(30),
  last_name      VARCHAR2(30),
  date_of_birth  DATE,
  MEMBER FUNCTION get_age RETURN NUMBER
);
/

Type created.

SQL> 
Next the type body is created to implement the get_age member function.
CREATE OR REPLACE TYPE BODY t_person AS
  MEMBER FUNCTION get_age RETURN NUMBER AS
  BEGIN
    RETURN TRUNC(MONTHS_BETWEEN(SYSDATE, date_of_birth)/12);
  END get_age;
END;
/

Type body created.

SQL> 
Once the object is defined it can be used to define a column in a database table.
CREATE TABLE people (
  id      NUMBER(10) NOT NULL,
  person  t_person
);

Table created.

SQL> 
To insert data into the PEOPLE table we must use the t_person() constructor. This can be done as part of a regular DML statement, or using PL/SQL.
INSERT INTO people (id, person)
VALUES (1, t_person('John', 'Doe', TO_DATE('01/01/2000','DD/MM/YYYY')));

1 row created.

COMMIT;

Commit complete.

DECLARE
  l_person  t_person;
BEGIN
  l_person := t_person('Jane','Doe', TO_DATE('01/01/2001','DD/MM/YYYY'));
  INSERT INTO people (id, person)
  VALUES (2, l_person);
  COMMIT;
END;
/

PL/SQL procedure successfully completed.

SQL>
Once the data is loaded it can be queried using the dot notation.
alias.column.attibute
alias.column.function()
The query below shows this in action.
SELECT p.id,
       p.person.first_name,
       p.person.get_age() AS age
FROM   people p;

        ID PERSON.FIRST_NAME                     AGE
---------- ------------------------------ ----------
         1 John                                    5
         2 Jane                                    4

2 rows selected.

SQL> 

Collections

Oracle uses collections in PL/SQL the same way other languages use arrays. You can read more about the types of collections available here.

Triggers

Database triggers are stored programs associated with a specific table, view or system events, such that when the specific event occurs the associated code is executed. Triggers can be used to validate data entry, log specific events, perform maintenance tasks or perform additional application logic. The following example shows how a table trigger could be used to keep an audit of update actions.
-- Create and populate an items table and creat an audit log table.
CREATE TABLE items (
  id           NUMBER(10),
  description  VARCHAR2(50),
  price        NUMBER(10,2),
  CONSTRAINT items_pk PRIMARY KEY (id)
);

CREATE SEQUENCE items_seq;

INSERT INTO items (id, description, price) VALUES (items_seq.NEXTVAL, 'PC', 399.99);

CREATE TABLE items_audit_log (
  id           NUMBER(10),
  item_id      NUMBER(10),
  description  VARCHAR2(50),
  old_price    NUMBER(10,2),
  new_price    NUMBER(10,2),
  log_date     DATE,
  CONSTRAINT items_audit_log_pk PRIMARY KEY (id)
);

CREATE SEQUENCE items_audit_log_seq;

-- Create a trigger to log price changes of items.
CREATE OR REPLACE TRIGGER items_aru_trg
  AFTER UPDATE OF price ON items
  FOR EACH ROW
BEGIN
   INSERT INTO items_audit_log (id, item_id, description, old_price, new_price, log_date)
   VALUES (items_audit_log_seq.NEXTVAL, :new.id, :new.description, :old.price, :new.price, SYSDATE);
END;
/

-- Check the current data in the audit table, should be no rows.
COLUMN description FORMAT A10
SELECT * FROM items_audit_log;

no rows selected

-- Update the price of an item.
UPDATE items
SET    price = 499.99
WHERE  id    = 1;

-- Check the audit table again.
COLUMN description FORMAT A10
SELECT * FROM items_audit_log;

        ID    ITEM_ID DESCRIPTIO  OLD_PRICE  NEW_PRICE LOG_DATE
---------- ---------- ---------- ---------- ---------- --------------------
         1          1 PC             399.99     499.99 19-AUG-2005 10:14:11

1 row selected.

-- Clean up.
DROP TABLE items_audit_log;
DROP TABLE items;
From this you can see that the trigger fired when the price of the record was updated, allowing us to audit the action.
The following trigger sets the current_schema parameter for each session logging on as the APP_LOGON user, making the default schema that of the SCHEMA_OWNER user.
CREATE OR REPLACE TRIGGER APP_LOGON.after_logon_trg AFTER
LOGON ON APP_LOGON.SCHEMA BEGIN
  EXECUTE IMMEDIATE 'ALTER SESSION SET current_schema=SCHEMA_OWNER';
END;
/
You can read more about database triggers here.

Error Handling

When PL/SQL detects an error normal execution stops and an exception is raised, which can be captured and processed within the block by the exception handler if it is present. If the block does not contain an exception handler section the exception propagates outward to each successive block until a suitable exception handler is found, or the exception is presented to the client application.
Oracle provides many predefined exceptions for common error conditions, like NO_DATA_FOUND when a SELECT ... INTO statement returns no rows. The following example shows how exceptions are trapped using the appropriate exception handler. Assume we want to return the username associated with a specific user_id value, we might do the following.
SET SERVEROUTPUT ON
DECLARE
  l_user_id   all_users.username%TYPE := 0;
  l_username  all_users.username%TYPE;
BEGIN
  SELECT username
  INTO   l_username
  FROM   all_users
  WHERE  user_id = l_user_id;
  
  DBMS_OUTPUT.put_line('l_username=' || l_username);
END;
/
l_username=SYS

PL/SQL procedure successfully completed.

SQL>
That works fine for user_id values that exist, but look what happens if we use one that doesn't.
SET SERVEROUTPUT ON
DECLARE
  l_user_id   all_users.username%TYPE := 999999;
  l_username  all_users.username%TYPE;
BEGIN
  SELECT username
  INTO   l_username
  FROM   all_users
  WHERE  user_id = l_user_id;
  
  DBMS_OUTPUT.put_line('l_username=' || l_username);
END;
/
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 5

SQL>
This is not a very user friendly message, so we can trap this error and produce something more meaningful to the users.
SET SERVEROUTPUT ON
DECLARE
  l_user_id   all_users.username%TYPE := 999999;
  l_username  all_users.username%TYPE; 
BEGIN
  SELECT username
  INTO   l_username
  FROM   all_users
  WHERE  user_id = l_user_id;

  DBMS_OUTPUT.put_line('l_username=' || l_username);
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.put_line('No users have a user_id=' || l_user_id);
END;
/
No users have a user_id=999999

PL/SQL procedure successfully completed.

SQL>
It is possible to declare your own exceptions for application specific errors, or associate them with Oracle "ORA-" messages, which are executed using the RAISE statement. The example below builds on the previous example using a user defined exception to signal an application specific error.
SET SERVEROUTPUT ON
DECLARE
  l_user_id   all_users.username%TYPE := 0;
  l_username  all_users.username%TYPE;
  
  ex_forbidden_users  EXCEPTION;
BEGIN
  SELECT username
  INTO   l_username
  FROM   all_users
  WHERE  user_id = l_user_id;
  
  -- Signal an error is the SYS or SYSTEM users are queried.
  IF l_username IN ('SYS', 'SYSTEM') THEN
    RAISE ex_forbidden_users;
  END IF;
  
  DBMS_OUTPUT.put_line('l_username=' || l_username);
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.put_line('No users have a user_id=' || l_user_id);
  WHEN ex_forbidden_users THEN
    DBMS_OUTPUT.put_line('Don''t mess with the ' || l_username || ' user, it is forbidden!');
END;
/
Don't mess with the SYS user, it is forbidden!

PL/SQL procedure successfully completed.

SQL>
The code still handles users that don't exist, but now it also raises an exception if the user returned is either SYS or SYSTEM.

My Utopian Development Environment

I wrote a blog post about this many years ago. You can read it here. I think it's worth just spending a little time reiterating some of the main points here. It may not be to everyone's liking, but I've always found it to be the most secure and flexible approach I've come across.
I believe the use of PL/SQL Application Program Interfaces (APIs) should be compulsory. Ideally, client application developers should have no access to tables, but instead access data via PL/SQL APIs, or possibly views if absolutely necessary.
Physical Organisation
This has a number of beneficial effects, including:
  • Security and auditing mechanisms can be implemented and maintained at the database level, with little or no impact on the client application layer.
  • It removes the need for triggers as all inserts, updates and deletes are wrapped in APIs. Instead of writing triggers you simply add the code into the API.
  • It prevents people who don't understand SQL writing inefficient queries. All SQL should be written by PL/SQL developers or DBAs, reducing the likelihood of bad queries.
  • The underlying structure of the database is hidden from the client application developers, so it hides complexity and structural changes can be made without client applications being changed.
  • The API implementation can be altered and tuned without affecting the client application layer. Reducing the need for redeployments of applications.
  • The same APIs are available to all applications that access the database. Resulting in reduced duplication of effort.
This sounds a little extreme, but this approach has paid dividends for me again and again. Let's elaborate on these points to explain why this approach is so successful.
It's a sad fact that auditing and security are often only brought into focus after something bad has happened. Having the ability to revise and refine these features is a massive bonus. If this means you have to re-factor your whole application you are going to have problems. If on the other hand it can be revised in your API layer you are on to a winner.
Over-reliance on database triggers is a bad thing in my opinion. It seems every company I've worked for has at one time or another used triggers to patch a “hole” or implement some business functionality in their application. Every time I see this my heart sinks. Invariably these triggers get disabled by accident and bits of functionality go AWOL, or people forget they exist and recode some of their functionality elsewhere in the application. It's far easier to wrap the transactional processing in an API that includes all necessary functionality, thereby removing the need for table triggers entirely.
Many client application developers have to be able to work with several database engines, and as a result are not always highly proficient at coding against Oracle databases. Added to that, some development architectures such as J2EE positively discourage developers from working directly with the database. You wouldn't ask an inexperienced person to fix your car, so why would you ask one to write SQL for you? Abstracting the SQL in an API leaves the client application developers to do what they do best, while your PL/SQL programmers can write the most efficient SQL and PL/SQL possible.
During the lifetime of an application many changes can occur in the physical implementation of the database. It's nice to think that the design will be perfected before application development starts, but in reality this seldom seems to be the case. The use of APIs abstracts the developers from the physical implementation of the database, allowing change without impacting on the application.
In the same way, it is not possible to foresee all possible performance problems during the coding phase of an application. Many times developers will write and test code with unrealistic data, only to find the code that was working perfectly in a development environment works badly in a production environment. If the data manipulation layer is coded as an API it can be tuned without re-coding sections of the application, after all the implementation has changed, not the interface.
A problem I see time and time again is that companies invest heavily in coding their business logic into a middle tier layer on an application server, then want to perform data loads either directly into the database, or via a tool that will not link to their middle tier application. As a result they have to re-code sections of their business logic into PL/SQL or some other client language. Remember, it's not just the duplication of effort during the coding, but also the subsequent maintenance. Since every language worth using can speak to Oracle via OCI, JDBC, ODBC or web services, it makes sense to keep your logic in the database and let every application or data load use the same programming investment.
Of course, you may not always have full control of your development environment, but it's worth bearing these points in mind.