You are on page 1of 1404

Release Date: August, 2016

Updates:
2
3
4
Evolution/Generations of Programming Languages:
1GL: First-generation programming languages; these are machine level languages specific to a particular
CPU
• 2GL: Second-generation programming languages; assembly languages specific to a particular CPU;
converted by an assembler into a machine language; commonly used for performance-oriented and
processing-intensive applications such as firmware interfaces and hardware drivers
• 3GL: Third-generation programming languages; converted into machine language by a compiler; less
cryptic and thus more programmer-friendly than 2GLs (ex., Visual Basic, C, C++, COBOL, FORTRAN, Java,
Pascal, PL/SQL)
• 4GL: Fourth-generation programming languages; less cryptic and thus more programmer-friendly than
2GLs; unlike the broad applicability of 3GLs, most 4GLs are used with databases, for queries, report
generation, data manipulation, etc. (ex., SQL, MySQL)
• 5GL: Fifth-generation programming languages; generally involve a visual or graphical development
environment that exports source language to a 3GL or 4GL compiler; 5GL may also refer to languages
that define a problem and a set of constraints, then let the computer find a solution; (ex., AI systems
such as PROLOG used with IBM’s Watson)
As an Oracle proprietary programming language, PL/SQL is only used with an Oracle database.

5
• Oracle generally pronounces SQL as “sequel.” Other vendors may pronounce SQL as separate letters,
“S”, “Q”, “L”.
• Although PL/SQL was developed after SQL, SQL is a 4GL while PL/SQL is a 3GL. Many third-generation
programming languages, such as COBOL, were in wide use when SQL was developed to access relational
databases. The new language SQL became the primary 4GL used to access relational databases. In the
early days of relational databases, SQL was sufficient, but as relational databases became more widely
used, it was necessary to add logic and control functionality. This was done by adding procedural
language features, in essence “extending” SQL to include logic and control functions. The “extended”
SQL structures are similar to the structures of earlier 3GLs, so PL/SQL is considered a 3GL even though it
was developed after the 4GL SQL.
• SQL and PL/SQL are both needed. They are not alternatives to each other. Only SQL can be used to
access database tables and only PL/SQL can be used to write the procedural logic.

6
7
8
9
10
11
12
As powerful as SQL is, it simply does not offer the flexibility and power developers need to create full-
blown applications. Oracle’s PL/SQL language ensures that we can stay entirely within the operating
system-independent Oracle environment and still write highly efficient applications that meet our users’
requirements.

13
14
15
PL/SQL is Oracle Corporation’s procedural language for relational databases which allows program logic and
control flow to be combined with SQL statements.

16
17
Release Date: August, 2016
Updates:
2
3
4
All of these benefits have a major impact on why PL/SQL was developed and how it is used.

5
Integration is a fantastic process. You can get your data to accomplish all types of tasks that are needed for
businesses.

6
Good programming practice uses modular programs to break program control into sections that may be
easier to understand and maintain.

7
8
Sending blocks of code to the database, instead of separate lines of SQL code, makes the program process
faster.

The following features also result in improved performance:


PL/SQL variables store data in the same internal binary format as the database does, so no data conversion
is needed.
PL/SQL is executed in the same memory space as the Oracle server and therefore there is no
communications overhead between the two programs.
PL/SQL functions can be called directly from SQL.
A special kind of PL/SQL procedure, called a trigger, can execute automatically whenever something
important happens in the database.

9
Oracle has tools for various tasks and PL/SQL is integrated into these tools.

10
11
12
13
14
PL/SQL requires an Oracle database or tool. You cannot create a PL/SQL program that runs all by itself. C
and Java programs do not require an Oracle database to run or compile. You can develop standalone
programs using Java and C.
PL/SQL has included some object-oriented features such as abstract data types, multi-level collections,
encapsulation, function overloading, and inheritance. Java is an object-oriented programming language and
C is not.
PL/SQL is tightly integrated with an Oracle database and is therefore highly efficient when accessing data.
Java and C are less efficient because they are not as integrated with the database.
PL/SQL is compatible with Oracle databases on different operating systems. Java also is highly portable.
Different C compilers and libraries are not 100% compatible on different operating systems.
PL/SQL is relatively easy to learn in relation to Java and C.

15
16
Blocks – The basic unit of PL/SQL programs; also known as modules.
Portability – The ability for PL/SQL programs to run anywhere an Oracle server runs.
Exceptions – An error that occurs in the database or in a user’s program during runtime.

17
18
Release Date: August, 2016
Updates:
2
3
4
Nested blocks will be covered later in the course.

5
DECLARE is not needed if no variables, constants, cursors or user-defined exceptions are required. But
nearly all real-life blocks will need variables and/or cursors, therefore nearly all real-life blocks will need
a DECLARE section.

6
7
8
PUT_LINE is a function in the DBMS_OUTPUT package that displays its argument (in this slide, the value
stored in v_date) on the screen for the user to see.

9
What happens if the SELECT statement finds more than one employee with that last name? There is
only room for one first name and one last name. Without the EXCEPTION section, the DECLARATIVE
section would abort and return an Oracle error message (ORA-01422: exact fetch returns more than
requested number of rows). With the EXCEPTION section, the abort is handled by the code in the
EXCEPTION section and the user (or later, the calling application) sees a friendlier error message.

10
11
12
13
These are examples of PL/SQL code blocks that are NOT anonymous blocks. The first block creates a
PROCEDURE that when called will display today's date. The second block creates a FUNCTION that will
return tomorrow's date (much like SYSDATE is a function that returns today's date).
You could call the PROCEDURE in the executable section of a PL/SQL block with the following code:
BEGIN PRINT_DATE; END;
You could call the FUNCTION using either a SQL statement or a PL/SQL block as shown below:
SELECT TOMORROW(SYSDATE) AS "Tomorrow's Date" FROM DUAL;
or
BEGIN DBMS_OUTPUT.PUT_LINE(TOMORROW(SYSDATE)); END;
The FUNCTION could also be used to initialize a variable:
DECLARE v_tomorrow DATE := TOMORROW(SYSDATE);
BEGIN DBMS_OUTPUT.PUT_LINE('Tomorrow is ' || v_tomorrow); END;
Feel free to run the CREATE blocks in Application Express and try the calls above to see the results.

14
This course will focus on Application Express and its SQL Workshop. You also will use Application Builder
in a project. The other tools are all free downloads with excellent documentation available from
www.oracle.com. All of these tools are widely-used in the business world.

15
16
17
18
Although not required, the convention is to follow all SQL statements with a forward slash (/), as well as
the anonymous blocks, in SQL script files.

19
20
21
22
The second DBMS_OUTPUT.PUT_LINE call in the slide shows that number values (v_emp_count) can be
displayed by PUT_LINE in combination with string values. In this example, the Oracle server has
performed an implicit datatype conversion (TO_CHAR(v_emp_count)) to convert the number to a
character string for concatenation.

23
Anonymous PL/SQL block – unnamed blocks of code not stored in the database and do not exist after
they are executed
Compiler – software that checks and translates programs written in high-level programming languages
into binary code to execute
Subprograms – named PL/SQL blocks that are stored in the database and can be declared as
PROCEDURES or FUNCTIONS
Procedures – subprograms that perform an action and may return one or more values
Functions – subprograms that return a single value

24
25
Release Date: August, 2016
Updates:
2
3
4
Variables are expressions that stand for something of value (in the equation x + y = 45, x and y are variables
that stand for two numbers that add up to 45). When defining a variable in a PL/SQL declaration section,
you label a memory location, assign a datatype, and, if needed, assign a starting value for the variable. A
variable can represent a number, character string, boolean (true/false value), or other datatypes.
Throughout the PL/SQL code, variable values can be changed by the assignment operator (:=).

Variables are mainly used for the storage of data and manipulation of those stored values. Consider the
SQL statement shown in the slide. The statement is retrieving the first_name and department_id from the
table. If you have to manipulate the first_name or the department_id, then you have to store the retrieved
value. Variables are used to temporarily store the values. You can use the value stored in these variables
for processing or manipulating the data.

Reusability is another advantage of declaring variables. After they are declared, variables can be used
repeatedly in an application by referring to them in the statements.

This is a lot of information and will be covered in detail as the course progresses.

5
6
A variable is a name or label that points to a value stored at a particular location in the computer's
memory.

7
In addition to variables, you also can declare cursors and exceptions in the declarative section. You will
learn how to declare cursors and exceptions later in the course.

8
9
10
The defining of data types and data structures in a programming language is a significant aid to readability.
In PL/SQL, you declare variables and constants in the declarative section of any PL/SQL block, subprogram,
or package.

References to a variable by its identifier are resolved according to its scope and visibility. The scope of an
identifier is that region of a program unit (block, subprogram, or package) from which you can reference
the identifier. An identifier is visible only in the regions from which you can reference the identifier using
an unqualified name. Identifiers declared in a PL/SQL block are considered local to that block and global to
all its sub-blocks. Although you cannot declare an identifier twice in the same block, you can declare the
same identifier in two different blocks. The two values represented by the identifiers are distinct, and any
change in one does not affect the other. These issues will be covered in more detail as the course
progresses.

What errors would be caused by the following variable definitions?

v_location VARCHAR2(10) := 'Washington DC';


v_grade NUMBER(4) := 'A';

11
12
13
A non-initialized variable contains the NULL value until a non-null value is explicitly assigned to it.

14
15
16
The syntax in this slide will be explained in more detail in later lessons. For now, you simply need to
understand that in PL/SQL, a variable can be passed from one program to another program, and we call
these variables parameters.

17
The concept, creation, and use of functions will be covered later in this course.

18
19
Parameters – values passed to a program by a user or by another program
Variables – used for temporary storage and manipulation of data

20
21
Release Date: August, 2016
Updates:
2
3
4
Identifiers are names for objects such as variables, functions, and procedures.

Reserved words are words already used by PL/SQL, such as BEGIN, END, and DECLARE, and words already
used by SQL, such as SELECT, INTO, FROM, etc.

Delimiters are symbols that have special meaning (+, ;, :=, ", etc.)

A literal is an explicit numeric, character string, date, or Boolean value (ex. a person's first name could be a
literal that is stored in a variable).

Comments explain what a piece of code is trying to achieve and are ignored when the code is processed.

5
6
Identifiers are names for objects such as variables, functions, procedures, and packages.

The words PROCEDURE, IS, VARCHAR2, BEGIN, SELECT, INTO, FROM, DUAL, and END are reserved words.

As the course progresses, you will learn more about each of these elements.

7
The convention is to begin variables with v_ and constants with c_.

• Identifiers are NOT case sensitive, so v_num, V_NUM, and V_Num are all the same identifier.

8
Be sure to name your objects carefully. Ideally, the identifier name should describe the object and its
purpose. Avoid using identifier names such as A, X, Y1, temp, etc., because they make your code more
difficult to read.

9
10
11
12
You have already learned that the symbol “;” is used to terminate a SQL or PL/SQL statement. It tells the
compiler that it is the end of the statement. Lines of code are not terminated at the physical end of the line.
They are terminated by the semi-colon. Often a single statement is spread over several lines to make the
code more readable.

13
The single-line comment indicator is shown with a space between the dashes for visual clarity. When used,
there should not be a space between any of the characters in a compound delimiter.

14
15
Be careful when copying code into the APEX SQL Commands window. Some word processors may default
to displaying "smart quotes." Smart quotes are curly or sloped. PL/SQL code requires the use of "straight
quotes."

16
17
18
19
The idea of Boolean variables and literals may be new to students because an Oracle database table cannot
contain columns with a Boolean data type. More information regarding the use of Boolean variables will be
covered later in the course.

Boolean literals are NOT case sensitive, so FALSE is the same as false, TRUE is the same as true, and NULL is
the same as null.

20
When programming code is converted into machine language for execution, comments are ignored.

However, adding comments is considered good programming practice in business and may be required by
instructors.

Adding comments to your programming code promotes readability and aids understanding. Comments
should describe the purpose and use of each block of code.

21
This example includes thorough commenting, especially for such a simple block of code, but is shown to
demonstrate various ways to add comments to your code.

22
Lexical Units – Building blocks of any PL/SQL block and are sequences of characters including letters, digits,
tabs, returns, and symbols.

Identifiers – A name, up to 30 characters in length, given to a PL/SQL object.

Reserved words – Words that have special meaning to an Oracle database and cannot be used as
identifiers.

Delimiters – Symbols that have special meaning to an Oracle database.

Literals – An explicit numeric, character string, date, or Boolean value that is not represented by an
identifier.

Comments – Describe the purpose and use of each code segment and are ignored by PL/SQL.

23
24
Release Date: August, 2016
Updates:
2
3
4
Scalar, Composite, and LOB data types are covered in this course.

Before a variable, constant, or parameter can be referenced in a PL/SQL program, it must be defined using
a data type in the declarative section of a PL/SQL program.

Variables, constants, and parameters can be characterized as a set of related elements: name, address,
value, type, lifetime, and scope.

Name is the identifying word that represents the variable, constant, or parameter. Address designates a
specific location in the computer's memory where the value is stored. Value is the content actually stored
at that memory location. Type (the focus of this lesson) determines the acceptable value, the maximum
size of the value, and the set of operations that can be applied to values of that type. Lifetime and scope
are related, and are dependent on where the variable, constant, or parameter is defined. Lifetime and
scope will be addressed later in this course.

For more information, refer to the PL/SQL User’s Guide and Reference manual.

5
The Character, Number, and Date categories include several data types. The different data types specify what type and size of data can be stored in
a particular location, the range of values the variable can have, and the set of operations that can be applied to values of that type. A few of each
are shown below. For more information and the complete list of scalar data types, refer to the PL/SQL User’s Guide and Reference.

The BOOLEAN data type may be new to you, as it is not a column data type used in table definitions.

SCALAR CHARACTER DATA TYPES


CHAR
VARCHAR2
LONG

SCALAR NUMERIC DATA TYPES


NUMBER
PLS_INTEGER

SCALAR DATE DATA TYPES


DATE
TIMESTAMP
TIMESTAMP WITH TIME ZONE

6
7
8
TIMESTAMP WITH LOCAL TIME ZONE - This data type differs from TIMESTAMP WITH TIME ZONE in that
when you insert a value into a database column, the value is normalized to the database time zone, and the
time-zone displacement is not stored in the column. When you retrieve the value, the Oracle server returns
the value in your local session time zone.

You also can specify the time zone by using a symbolic name. You can find the available names and
abbreviations for time zones in the TZNAME and TZABBREV columns of the V$TIMEZONE_NAMES data
dictionary view.

INTERVAL YEAR TO MONTH - Use the INTERVAL YEAR TO MONTH data type to store and manipulate
intervals of years and months.

INTERVAL DAY TO SECOND - Use the INTERVAL DAY TO SECOND data type to store and manipulate intervals
of days, hours, minutes, and seconds.

9
The BOOLEAN data type is available in PL/SQL, but is not valid in SQL.

10
For now, it may be helpful to think of a scalar type as being like a single column value in a table, while a
record data type is like a whole row of a table.

11
Composite data types are covered later in this course.

12
LOB data types are covered in detail in Section 11.

13
The character large object (CLOB) data type is used to store large blocks of text data in the database.

The binary large object (BLOB) data type is used to store large binary objects (ex. graphic image) in the
database. When you insert or retrieve such data to and from the database, the database does not interpret
the data. External applications that use this data must interpret the data.

The national language character large object (NCLOB) data type is used to store large blocks of NCHAR data
in the database.

The binary file (BFILE) data type is used to store large binary objects (ex. a video or audio file) in operating
system files outside the database.

14
BLOB, CLOB, and NCLOB objects can be stored in-line (inside the row) or out-of-line (outside the row, but
still in the database, as indicated in the image).

BFILE objects are stored outside the database in operating system files.

15
BFILE – Store large binary objects outside of the database.

BLOB – Store large binary objects in the database.

CLOB – Store large blocks of character data in the database.

Composite – Contain internal elements that that can be manipulated individually.

LOB – Data types that hold values called locators, which specify the location of large objects (such as
graphic images).

16
NCLOB (National Language Character Large Object) – Store large blocks of NCHAR data in the database.

Object – A schema object with a name, attributes, and methods.

Reference – Hold values, called pointers, which point to a storage location.

Scalar – Hold a single value with no internal components.

17
18
Release Date: August, 2016
Updates:
2
3
4
The internationally recognized two-character country abbreviations (ex. BR, CA, EG, IN, RO, UK, etc.) can be
defined using CHAR(2) since they are all two-characters in length.
Since the length of country names may vary, that variable should be defined using VARCHAR2.
Although the v_country_report could be defined as a LONG data type, the CLOB data type was introduced
in the Oracle8i database and should now be used for documents that use the database character set
exclusively.
Character data types also are known as strings and allow storage of alphanumeric data (letters, numbers,
and symbols). A string of data might be an address, "#12 Green Side, Waterbeach, Cambridgeshire, UK,
CB24 9HP." You can see the address contains letters, numbers, and a symbol.
Variables to hold this address might be defined as:
v_street_address VARCHAR2(25);
v_city VARCHAR2(25);
v_county VARCHAR2(25);
v_country_id CHAR(2);
v_postal_code VARCHAR2(8);

5
Again, all variables must be declared before being used in a program. In this course, the most common
number data type to be used will be NUMBER(p,s) with some form of precision and scale. Remember,
precision determines the maximum number of digits to be stored and includes scale. Scale determines
where rounding occurs as well as the fixed number of decimal places to store.
Some number datatypes apply a constraint to the variable. For instance, POSITIVE constrains the variable to
positive values. SIGNTYPE restricts the variable to the values -1, 0, and 1, which is useful in programming
tri-state logic.
INTEGER data type is the same as NUMBER(38,0).
Data types such as BINARY_FLOAT, BINARY_DOUBLE, PLS_INTEGER, and BINARY_INTEGER are used
primarily for high-speed scientific computation, as they are faster in calculations. The way BINARY_FLOAT
and BINARY_DOUBLE represent decimal data make them less suitable for financial applications, where
precise representation of fractional amounts is more important than pure performance.
While BINARY_FLOAT and BINARY_DOUBLE can be used as table column data types, PLS_INTEGER and
BINARY_INTEGER are PL/SQL-only data types that are more efficient than NUMBER or INTEGER for integer
calculations.
Notice the naming convention used in the example (v_ for variables that can vary and c_ for the variable
that must remain constant throughout this block of code).

6
Depending on the day you run the code in the slide and your server's location, your results will look similar
to this:
05-Apr-2015
12-Apr-2015
05-APR-15 12.18.37.000000 PM
05-APR-15 12.18.37.000000 PM -07:00
Depending on the configuration of your server, dates should be initialized using the following formats:
DD/MON/YYYY or DD-MON-YYYY
Choosing between DATE, TIMESTAMP, etc., is determined by what data you need to know in the future.

7
BOOLEAN allows a TRUE, FALSE, or NULL condition to be tested.
A BOOLEAN variable is NULL by default and may remain NULL (unless the NOT NULL constraint is included, in which case the variable must be
initialized to either TRUE or FALSE). Notice that when a BOOLEAN variable is initialized, the value is NOT a string and is not enclosed in single
quotes.
Remember, BOOLEAN is not valid as a table column data type. For a table column, you can simulate a BOOLEAN data type by using one of the
following:
column_name CHAR; -- store a 'Y' or an 'N' to simulate TRUE or FALSE
column_name NUMBER; -- store a 0 or a 1 to simulate TRUE or FALSE
Testing BOOLEAN variables is something you should practice. Consider the following three code examples. Can you predict the result of each code
sample? How can you change the initial value of v_valid to change the result? How can you change the test in each IF clause to change the result?
Sample 1:
DECLARE v_valid BOOLEAN := TRUE;
BEGIN IF v_valid THEN DBMS_OUTPUT.PUT_LINE('Value stored in v_valid equals TRUE');
ELSE DBMS_OUTPUT.PUT_LINE('Value stored in v_valid does not equal TRUE (it is either NULL or FALSE)');
END IF; END;
Sample 2:
DECLARE v_valid BOOLEAN;
BEGIN IF v_valid IS NULL THEN DBMS_OUTPUT.PUT_LINE('No value (neither TRUE nor FALSE) is stored in v_valid');
ELSE DBMS_OUTPUT.PUT_LINE('Value stored in v_valid equals either TRUE or FALSE');
END IF; END;
Sample 3:
DECLARE v_valid BOOLEAN := FALSE;
BEGIN IF v_valid = FALSE THEN DBMS_OUTPUT.PUT_LINE('Value stored in v_valid equals FALSE');
ELSE DBMS_OUTPUT.PUT_LINE('Value stored in v_valid does not equal FALSE (it is either NULL or TRUE)');
END IF; END;

8
BOOLEAN variables can be initialized in various ways and can be initialized in the executable section. Can you predict the result of the code below?
DECLARE
v_valid1 BOOLEAN;
v_valid2 BOOLEAN;
v_balance NUMBER(10,2) := 5000;
v_min_balance NUMBER(10,2) := 1000;
BEGIN
v_valid1 := v_balance > v_min_balance; -- will initialize variable to TRUE or FALSE
v_balance := 750; -- changes value of the variable
v_valid2 := v_balance > v_min_balance; -- will initialize variable to TRUE or FALSE
IF v_valid1 THEN -- same as IF v_valid1 = TRUE THEN
DBMS_OUTPUT.PUT_LINE('Value stored in v_valid1 equals TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE('Value stored in v_valid1 does not equal TRUE (it is either NULL or FALSE)');
END IF;
IF v_valid2 = FALSE THEN
DBMS_OUTPUT.PUT_LINE('Value stored in v_valid2 equals FALSE');
ELSE
DBMS_OUTPUT.PUT_LINE('Value stored in v_valid2 does not equal FALSE (it is either NULL or TRUE)');
END IF;
END;

9
Use meaningful and appropriate names for variables. For example, consider using v_new_salary and
v_old_salary instead of salary1 and salary2.
Impose the NOT NULL constraint when the variable must contain a value. Remember, you cannot assign
nulls to a variable defined as NOT NULL and the NOT NULL constraint must be followed by an initialization
clause such as:
v_pincode NUMBER(15) NOT NULL := 17642;
Impose the CONSTANT constraint when a variable value should not change within the block. The
CONSTANT constraint requires an initialization value. The syntax is:
c_pi CONSTANT NUMBER(6,5) := 3.14159
NUMBER variables are typically initialized to "0" so as to avoid calculations using a NULL value. BOOLEAN
variables are typically initialized to FALSE and tested for TRUE.

10
In this example, the code works because the Oracle server knows the identifier following the SELECT
keyword must be a column name and the identifier following the INTO keyword must be a variable name.
Likewise, the argument for the PUT_LINE function also must be a variable name.
Although this code works, and is simple enough that we know what is happening, more complex code could
be confusing to maintain or modify if variable names are identical to column names.
If you use the recommended naming conventions, this will not be a problem. For example:
Table column employee_id becomes variable v_employee_id.
Table column first_name becomes variable v_first_name.
Table column last_name becomes variable v_last_name.
Table column hire_date becomes variable v_hire_date.
Table column salary becomes variable v_salary.

11
The %TYPE reference is resolved at the time the code is compiled. It also establishes a dependency
between the code and the table column referenced. This means that if the table column is changed, the
code that references it is marked invalid. No changes are required to the invalid code, but the invalid code
must be recompiled to update the reference.

Defining a data type using the %TYPE attribute is referred to as an "anchored data type."

12
13
Using the %TYPE attribute to define an "anchored data type" for v_first_name would solve the problem.
Otherwise, a programmer would have to find and modify every place in every program with a variable
defined to hold an employee's first name.
With the %TYPE attribute, the code would look like this:
DECLARE
v_first_name employees.first_name%TYPE;
BEGIN
SELECT first_name
INTO v_first_name
FROM employees
WHERE last_name = 'Vargas';
DBMS_OUTPUT.PUT_LINE(v_first_name);
END;

14
15
In the examples,
v_first_name will have the same data type as the column first_name in the employees table.
v_salary will have the same data type as the column salary in the employees table.
v_old_salary will have the same data type as the variable v_salary.
v_new_salary will have the same data type as the variable v_salary.
v_min_balance will have the same data type as the variable v_balance.
A NOT NULL database column constraint does not apply to variables that are declared using %TYPE.
Therefore, if you declare a variable using the %TYPE attribute that uses a database column defined as NOT
NULL, that database constraint does NOT pass to the variable.

16
17
18
%TYPE – Attribute used to declare a variable according to another previously declared variable or table
column.
BOOLEAN – A datatype that stores one of the three possible values used for logical calculations: TRUE,
FALSE, or NULL.

19
20
Release Date: August, 2016
Updates:
2
3
4
Assigning a value to a variable: the variable must always be on the left side of the assignment symbol (:=);
the value will always be on the right side of the assignment symbol.

v_num := v_count + c_people

v_num is the variable memory location that will be assigned the value in the variable memory location
v_count plus the value of the memory location c_people.

5
Functions are used as short cuts. Someone already programmed a block of code to accomplish a specific
process. These blocks of code are called procedures and functions. Use them to make writing your program
easier. Later in this course, you will learn how to write your own procedures and functions.

6
SQL functions help you to manipulate data; they fall into the following categories:

Number Character
Date Conversion
Miscellaneous

In PL/SQL blocks, group functions, including AVG, MIN, MAX, COUNT, SUM, STDDEV, and VARIANCE, may
be used ONLY within a SQL statement.

The following functions are not available in procedural statements:

DECODE: (because it is not needed in PL/SQL; instead, we use CASE which is more powerful)

7
8
9
10
11
12
13
14
Whenever PL/SQL detects that a conversion is necessary, it attempts to change the values as required to
perform the operation.

In the chart, the cells marked 'X' show which implicit conversions can be done.

For this course, we will focus on implicit conversions between:

Characters and numbers


Characters and dates

For more information about the above chart, refer to “Converting PL/SQL Data Types” in the PL/SQL User’s
Guide and Reference.

15
16
17
18
19
20
21
Note that the DBMS_OUTPUT.PUT_LINE procedure expects an argument with a character type such as
VARCHAR2. In the above example, variable v_c is a number, therefore we should explicitly code:

DBMS_OUTPUT.PUT_LINE(TO_CHAR(v_c));

22
The examples in the slide show implicit and explicit conversions of the DATE data type.

Example #1 - Implicit conversion happens in this case and the date is assigned to v_date_of_joining.

Example #2 - PL/SQL gives you an error because the date that is being assigned is not in the default format.

Example #3 - This is how it should be done. Use the TO_DATE function to explicitly convert the given date in
a particular format and assign it to the DATE data type variable date_of_joining.

23
24
25
The second example is particularly elegant when you consider the same result could be obtained by the
following code:

IF v_sal BETWEEN 50000 AND 150000 THEN


v_good_sal := TRUE;
ELSE
v_good_sal := FALSE;
END IF;

26
Explicit conversion – Converts values from one data type to another by using built-in functions.
Implicit conversion – Converts data types dynamically if they are mixed in a statement.

27
28
Release Date: August, 2016
Updates:
2
3
4
5
6
7
Each block allows the grouping of logically related declarations and statements. This makes structured
programming easy to use due to placing declarations close to where they are used (in each block).

Answer: The scope of v_outer_variable includes both the outer and inner blocks. The scope of
v_inner_variable includes only the inner block. It is valid to refer to v_outer_variable within the inner block,
but referencing v_inner_variable within the outer block would return an error.

8
Answer: The scope of v_father_name and v_date_of_birth is both blocks (inner and outer). The scope of
v_child_name is the inner block only.

The scope of a variable is the block in which it is declared plus all blocks nested within the declaring block.

9
10
11
12
13
14
15
Answer: v_last_name is defined in the inner block and is not accessible in the outer block.

16
Answer: Yes. Both variables are defined in the outer block, so they are accessible in the inner block and the
outer block.

17
Answer:

v_outervar is accessible in the outer block, the middle block, and the inner block.

v_middlevar is accessible in the middle block and the inner block, but NOT the outer block.

18
19
Answer: Yes, they are valid, but the code could be confusing if it needs to be modified later. This is not
recommended.

20
Answer: The PUT_LINE will reference the v_date_of_birth declared in the inner block.

21
Answer: The PUT_LINE will reference the v_date_of_birth declared in the inner block.

22
1 Observe the code in the executable section of the inner PL/SQL block. You can print the father’s name,
the child’s name, and the child's date of birth. Only the child’s date of birth can be printed within the inner
block because the father’s date of birth is not visible here.
2 The father’s date of birth is visible here (having now returned to the outer block) and can now be printed.

23
24
25
26
27
Block label – A name given to a block of code which allows references to be made back to the variables and
their values within that block of code from other blocks of code.

Variable scope – Consists of all the blocks in which the variable is either local (the declaring block) or global
(nested blocks within the declaring block).

Variable visibility – The portion of the program where the variable can be accessed without using a
qualifier.

28
29
Release Date: August, 2016
Updates:
2
3
Several books and Web sites are available that address PL/SQL best practices.

4
Course work should follow the conventions described in this slide.

5
Course work should follow the conventions described in this slide.

6
Each organization will typically develop and require its own programming guidelines and conventions. In a
sense, it doesn’t matter which conventions are adopted, so long as a meaningful convention exists and is
used consistently.

7
While learning to program, we are often writing relatively simple code that can make it can seem
redundant to comment the code, but the habit of adding comments will payoff in the future.

Comments assist in future maintenance or modification by helping other programmers know what the
original programmer intended by the code written. Even the original programmer will benefit from
commenting his/her code when returning for the first time to that code six months hence.

Comments are strictly informational and do not enforce any conditions or behavior on logic or data. They
are ignored when code is compiled.

8
As mentioned earlier, it doesn’t matter which conventions are adopted, so long as a meaningful convention
exists and is used consistently.

The case convention described here is commonly used in SQL and PL/SQL, and is also the one used in the
Oracle product documentation.

9
Course work should follow the conventions described in this slide.

10
Course work should follow the conventions demonstrated in this slide.

11
Course work should follow the conventions demonstrated in this slide.

For clarity, and to enhance readability, indent each level of code using spaces or tabs, put a space before and after operators, and
begin new clauses on a new line by using carriage returns. Compare the following IF statements for readability:

OPTION #1:
BEGIN IF x>y THEN v_max:=x;ELSE v_max:=y;END IF;END;

OPTION #2:
BEGIN
IF x > y THEN
v_max := x;
ELSE
v_max := y;
END IF;
END;

With Option #2, it is much easier to see what is happening in the code. Depending on the code editor you are using, each new level
of code should be indented two spaces or one tab stop.

12
13
Release Date: August, 2016
Updates:
2
3
4
DML commands allow changes to tables by adding rows, deleting rows, and modifying data within a row.
Programmers must take care to know what their programs are trying to accomplish, as any of the DML
commands issued will change the data in the affected tables.

Important Notes:

In online/hosted versions of Application Express at iAcademy, the default setting for the APEX SQL
command processor is that AUTOCOMMIT is turned on. This means each statement executed will be
automatically committed as it is executed. There is no user control to disable AUTOCOMMIT.

If you have a locally installed version of APEX, there is an AUTOCOMMIT checkbox that can be unchecked
to disable AUTOCOMMIT. When AUTOCOMMIT is disabled, DML commands produce permanent changes
only when the COMMIT command is issued either within a PL/SQL block or by itself. If the user logs off
normally or closes the browser window before executing a COMMIT command, the changes will be rolled
back.

5
At the very least, you must list and initialize with a value each column that can not be NULL.

6
When inserting a row into a table, you must provide a value for each column that can not be NULL. You also
could insert the new employee by listing all the columns in the table and including NULL in the list of values
that are not known at the moment and can be updated later. For example:

INSERT INTO employees (employee_id, first_name, last_name, email, phone_number,


hire_date, job_id, salary, commission_pct, manager_id, department_head)
VALUES (305, 'Kareem', 'Naser', 'naserk@oracle.com', '111-222-3333', SYSDATE,
'SR_SA_REP', 7000, NULL, NULL, NULL);

Notice the hire_date column is receiving its value from the SYSDATE function. A column's value can be an
explicit value or the result of a function. It also can be the result of a subquery or the result of an
expression.

7
Although this syntax works, it is not recommended. In this example, the EMPLOYEES table has the same
eleven columns as listed in the explicit example. But what if the DBA later adds a twelfth column using a
DDL ALTER TABLE statement? The INSERT statement above would no longer work. It is good programming
practice to explicitly identify the columns when inserting a new row. For example:

INSERT INTO employees (employee_id, first_name, last_name, email, phone_number,


hire_date, job_id, salary, commission_pct, manager_id, department_head)
VALUES (305, 'Kareem', 'Naser', 'naserk@oracle.com', '111-222-3333', SYSDATE,
'SR_SA_REP', 7000, NULL, NULL, NULL);

The code above would continue to work even after the DBA adds a twelfth column, so long as the twelfth
column does not require a value when the row is inserted.

8
If the WHERE clause is omitted, ALL rows will be modified. Be very careful when running an UPDATE
statement without a WHERE clause as most UPDATE statements will include a WHERE clause.

9
Remember, if the WHERE clause is omitted, ALL rows will be modified. Be very careful when running an
UPDATE statement without a WHERE clause as most UPDATE statements will include a WHERE clause.

10
11
The first example deletes one row because employee_id is the primary key.

The second example may delete multiple rows. It will delete all rows that have the value 80 in the
department_id column.

12
13
14
15
16
17
Data Definition Language (DDL) -- When you create, change, or delete an object in a database.
Data Manipulation Language (DML) -- When you change data in an object (for example, by inserting or
deleting rows).
DELETE -- Statement used to remove existing rows in a table.
INSERT -- Statement used to add new rows to a table.
MERGE -- Statement used to INSERT and/or UPDATE a target table, based on matching values in a source
table.
UPDATE -- Statement used to modify existing rows in a table.

18
19
Release Date: August, 2016
Updates:
2
3
4
PL/SQL is tightly integrated with SQL and therefore the database. As a quick reminder, SELECT returns data
from one or more tables, INSERT creates new rows in a table, UPDATE changes existing data in a table,
DELETE removes an entire row from a table, and MERGE is a combination of INSERT and UPDATE.

If using a local APEX environment, any changes done by one or more DML statements can be saved in the
database by a COMMIT statement. Before a COMMIT statements is executed, statements can be undone
by a ROLLBACK statement. SAVEPOINTS can be created in between DML statements to allow a user to
ROLLBACK to a particular SAVEPOINT, rather than ROLLING back all transactions since the last issued
COMMIT or ROLLBACK.

If using the online APEX environment through iAcademy, all SQL statements are automatically committed.
The transaction control statements, COMMIT, ROLLBACK, and SAVEPOINT, are NOT available through
iAcademy.

5
6
DDL and DCL statements cannot simply run within the executable section of a PL/SQL block of code.

Consider the following example:

BEGIN
ALTER TABLE employees
ADD certifications VARCHAR2(50);
END;

The example tries to use a DDL statement directly in the block. If you execute the block, you will see the
following error:

ORA-06550: line 2, …
PLS-00103: Encountered the symbol "ALTER" when expecting…

7
Use the SELECT statement to retrieve data from the database. In the syntax:

select_list is a list of at least one column and can include SQL expressions, row functions, or group functions
variable_name is a scalar variable that holds a retrieved value
record_name is the PL/SQL record that holds the retrieved values
table specifies the database table name
condition is composed of column names, expressions, constants, and comparison operators, including
PL/SQL variables and constants

8
9
In the example in the slide, the v_emp_hiredate and v_emp_salary variables are declared in the declarative
section of the PL/SQL block. In the executable section, the values of the columns hire_date and salary for
the employee with the employee_id 100 is retrieved from the employees table and stored in the
v_emp_hiredate and v_emp_salary variables, respectively. Observe how the INTO clause, along with the
SELECT clause, retrieves the database column values into the PL/SQL variables.

Note: The SELECT statement is retrieving hire_date and then salary, That means the variables in the INTO
clause must be in the same order.

10
A SELECT statement with the INTO clause can retrieve only one row at a time. If your requirement is to
retrieve multiple rows and operate on the data, then you can make use of explicit cursors. PL/SQL explicit
cursors will be discussed in upcoming lessons.

11
In this example, the v_sum_sal and v_deptno variables are declared in the declarative section of the PL/SQL
block. In the executable section, the total salary for the employees in the department with the
department_id 60 is computed using the SQL group function SUM. The calculated total salary is assigned to
the v_sum_sal variable.

This SELECT statement complies with the embedded query rule as it will always return exactly one row,
even if there are many (or no) employees in department 60.

Group functions cannot be used directly in PL/SQL syntax. For example, the following code does not work:

v_sum_sal := SUM(employees.salary);

Group functions must be part of a SQL statement within a PL/SQL block.

12
Answer: when "retrieving" data from the DUAL table as in:

DECLARE
v_date DATE;
BEGIN
SELECT SYSDATE
INTO v_date
FROM DUAL;
DBMS_OUTPUT.PUT_LINE('The date is ' || v_date);
END;

13
14
This example attempts to retrieve the hire date from the employees table for employee_id 176. It raises an
unhandled run-time exception because in the WHERE clause, the PL/SQL variable name EMPLOYEE_ID is
the same as that of the database column name in the employees table.

Try running the SELECT statement from the slide (without the INTO clause) outside of a PL/SQL block and
you will see it returns more than one row, which we know violates the embedded query rule.

SELECT hire_date FROM employees


WHERE employee_id = employee_id;

15
To test the code, run the following statements:
CREATE TABLE emp_dup AS SELECT * from employees;
SELECT first_name, last_name FROM emp_dup;
DECLARE last_name VARCHAR2(25) := 'King';
BEGIN DELETE FROM emp_dup WHERE last_name = last_name; -- the result will say "1 row(s) deleted“ END;
SELECT first_name, last_name FROM emp_dup;
DROP TABLE emp_dup;
Answer:
Although the code returned the message "1 row(s) deleted," the DELETE statement actually removed ALL employees
from the employees table as opposed to just the row(s) that contain the last name “King.” This is because the Oracle
server first resolves WHERE clause data items to the table in the FROM clause. Since last_name is in the table
emp_dup, and the last_name column in each row is "equal" to itself, the DELETE statement deletes ALL rows in the
emp_dup table. Had the variable in the declarative section been named v_last_name as our naming convention
suggests, this mistake would not have happened.
The PL/SQL block should have been:
DECLARE v_last_name employees.last_name%TYPE := 'King';
BEGIN DELETE FROM emp_dup WHERE last_name = v_last_name;
END;

16
Avoid ambiguity in the WHERE clause by using a naming convention that clearly distinguishes database
column names from PL/SQL variable names (for example, ensure all variable names begin with v_).

There is no possibility for ambiguity in the SELECT clause because any identifier in the SELECT clause must
be a database column name. There is no possibility for ambiguity in the INTO clause because identifiers in
the INTO clause must be PL/SQL variables. There is the possibility of ambiguity or confusion only in the
WHERE clause.

17
18
Release Date: August, 2016
Updates:
2
3
4
5
A DML statement within a PL/SQL block can modify many rows (unlike a SELECT statement, which must
read exactly one row).

6
7
8
Important Note: The data in the EMPLOYEES table needs to remain unchanged for later in the course. Therefore we
use the COPY_EMP table in all these DML examples.

If you haven't already created the COPY_EMP table, do so now by executing this SQL statement:

CREATE TABLE copy_emp


AS SELECT *
FROM employees;

In the example in the slide, an INSERT statement is used within a PL/SQL block to insert a row into the COPY_EMP
table.

While using the INSERT command in a PL/SQL block, you can:

Use SQL functions, such as USER and SYSDATE.


Generate primary key values by using existing database sequences.
Derive values in the PL/SQL block.

9
There may be ambiguity in the SET clause of the UPDATE statement because although the identifier on the
left of the assignment operator is always a database column, the identifier on the right can be either a
database column or a PL/SQL variable. Recall that if column names and identifier names are identical in the
WHERE clause, then the Oracle server looks to the database first for the name.

Remember that the WHERE clause is used to determine which rows are affected. If no rows are modified,
then no error occurs (unlike the SELECT statement in PL/SQL). If the WHERE clause is not used, then all the
rows in a table will be removed, provided that no integrity constraints are violated.

PL/SQL variable assignments always use :=, and SQL column assignments always use =.

Although we are using the copy_emp table, it is ok to use the original table for the definition of the variable
datatype employees.salary%TYPE.

10
The DELETE statement removes unwanted rows from a table. If the WHERE clause is not used, then all the
rows in a table will be removed, provided that no integrity constraints are violated.

11
The MERGE statement inserts or updates rows in one table by using data from another table. Each row is
inserted or updated in the target table, depending on an equijoin condition.

The example shown matches the employee_id in the COPY_EMP table to the employee_id in the
EMPLOYEES table. If a match is found, then the row is updated to match the row in the EMPLOYEES table. If
the row is not found, then it is inserted into the copy_emp table.

12
13
The word “cursor” has several meanings in Oracle. It is sometimes used to mean a pointer to the private
memory area, rather than the memory area itself. It is also used to refer to an area of shared memory. In
thıs course, we focus only on its meaning in the PL/SQL environment.

14
Implicit cursors: Implicit cursors are created and managed by the Oracle server. Oracle uses an implicit
cursor for each SELECT, UPDATE, DELETE, or INSERT statement you execute in a program. You do not have
access to them. The Oracle server creates such a cursor when it has to execute a SQL statement. The
remaining pages in this lesson discuss implicit cursors.

Explicit cursors: Explicit cursors are declared by the programmer. As a programmer you may want to
retrieve multiple rows from a database table, have a pointer to each row that is retrieved, and work on the
rows one at a time. In such cases, you can declare cursors explicitly depending on your business
requirements. You declare these cursors in the declarative section of a PL/SQL block. Explicit cursors are
discussed in a later lesson.

15
You can test the attributes — SQL%ROWCOUNT, SQL%FOUND, and SQL%NOTFOUND — in the executable
section of a block to gather information after the appropriate command. PL/SQL does not return an error if
a DML statement does not affect any rows in the underlying table. However, if a SELECT statement does
not retrieve any rows, PL/SQL returns an exception.

Observe that the attributes are prefixed with the automatic name of the implicit cursor: “SQL.”

The SQL%NOTFOUND attribute is opposite to SQL%FOUND. This attribute may be used as the exit condition
in a loop. It is useful in UPDATE or DELETE statements when no rows are changed because exceptions are
not returned in these cases.

You will learn about explicit cursor attributes later in the course.

16
17
The example in the slide deletes all rows with department_id 50 from the copy_emp table. Using the
SQL%ROWCOUNT attribute, you can display the number of rows deleted.

18
19
Since every embedded SQL statement creates an implicit cursor, and all implicit cursors are called “SQL," each SQL statement in
turn will result in its own values in the cursor attributes. Therefore the SQL%ROWCOUNT value returned from the UPDATE
statement will be overwritten by the INSERT statement. The goal of the code in the slide is to store the number of rows updated by
the UPDATE statement in the RESULTS table. What actually happens, though, is an error. Upon starting the INSERT statement, the
previous cursor attributes are "erased." Until the INSERT statement completes, there are no new cursor attributes, so there is no
value to be inserted into the RESULTS table.

To use a previous implicit cursor attribute in a later SQL statement, you must save the value in an explicitly declared variable
before it is "erased" by the start of a new SQL statement. See the variable V_ROWCOUNT in the code below. Note also the
presence of the PUT_LINE statements that will show you the value in SQL%ROWCOUNT after the UPDATE statement and again
after the INSERT statement. Using PUT_LINEs in this way is an excellent debugging technique.

DECLARE
v_rowcount INTEGER;
BEGIN UPDATE copy_emp SET salary = salary + 100 WHERE job_id = 'ST_CLERK';
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' rows in COPY_EMP updated.');
v_rowcount := SQL%ROWCOUNT; -- not a SQL statement, does not alter SQL%ROWCOUNT
INSERT INTO results (num_rows)
VALUES (v_rowcount);
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' rows in RESULTS updated.');
END;

20
INSERT - Statement adds new rows to the table.
UPDATE - Statement modifies existing rows in the table.
DELETE - Statement removes rows from the table.
MERGE - Statement selects rows from one table to update and/or insert into another table. The decision
whether to update or insert into the target table is based on a condition in the ON clause.
Explicit cursors: Defined by the programmer for queries that return more than one row.
Implicit cursors: Defined automatically by Oracle for all SQL data manipulation statements, and for queries
that return only one row.

21
22
Release Date: August, 2016
Updates:
2
In iSQLPlus and most other Oracle development tools, the changes made by SQL DML statements are not
committed until a COMMIT statement is explicitly executed. However, in the online iAcademy Application
Express, DML statements are automatically committed when executed. The information in this lesson will
be presented as if you were issuing the commands in an installed/local database environment with the
ability to use COMMIT and ROLLBACK.

3
4
5
6
7
8
9
Remember, in the online, iAcademy Application Express environment, all statements are automatically
committed. This will not be the case with databases in a production environment.

10
Remember, in the online, iAcademy Application Express environment, all statements are automatically
committed. This will not be the case with databases in a production environment.

11
ROLLBACK and SAVEPOINT are useful commands, and a major component of real-world database
programming. They are used to restore the data to its original values, when and if, the transaction cannot
complete all of its steps.

You may think this simple example looks pointless. What is the purpose of coding and executing the first
INSERT statement if we are going to reverse out the change? Well, it is a simple example. In real-world
database programming, we usually include ROLLBACK statements if an error occurs, or as a result of a
conditional test (IF…ELSE…), or due to a hardware failure, or power failure.

Remember, in the online, iAcademy Application Express environment, all statements are automatically
committed. This will not be the case with databases in a production environment.

12
SAVEPOINTs are useful in application programs. If a procedure contains several functions, then you can
create a SAVEPOINT before each function begins. Then, if a function fails, it is easy to return the data to its
state before the function began and re-run the function with revised parameters or perform a recovery
action.

13
COMMIT – Statement used to make database changes permanent.
END – Keyword used to signal the end of a PL/SQL block, not the end of a transaction.
ROLLBACK – Used for discarding any changes that were made to the database after the last COMMIT.
SAVEPOINT – Used to mark an intermediate point in transaction processing.
Transaction – An inseparable list of database operations, which must be executed either in its entirety or
not at all.

14
15
Release Date: August, 2016
Updates:
WARNING:

When a user executes a PL/SQL block in APEX that contains an infinite loop, there is no way for the user to
stop the loop. It can only be stopped by the DBA who oversees the Academy database. If the loop does not
contain DML statements, closing the browser window and reopening it will allow the user to continue
coding. If the block contains a FOR UPDATE clause, the affected table(s) will remain locked until released by
the DBA, which may take a day or more.

Be careful executing loops. All loops required by this course should have some type of limiting condition.
NO infinite loops are required as part of this course.

2
3
4
5
The IF statement contains alternative courses of action in a block based on conditions. A condition is an
expression with a TRUE or FALSE value that is used to make a decision.

The CASE statement contains alternative courses of action in a block based on one condition. They are
different in that they can be used outside of a PLSQL block in a SQL statement.

LOOPs are control structures that allow iteration of statements. Loop control structures are repetition
statements that enable you to execute statements in a PLSQL block repeatedly. There are three types of
loop control structures supported by PL/SQL—BASIC, FOR, and WHILE.

6
Writing in pseudocode combines natural language with code-like elements. It is sometimes used when
introducing new structures and concepts. Pseudocode generally excludes syntax requirements and adds
words that capture the logic of the structure/concept under consideration.

7
CASE expressions will be discussed more fully in a future lesson.

8
Loops will be discussed more fully in a future lesson.

9
10
Please note the ELSIF does not have an 'E' after the 'S,' and there is no space. There can be many ELSIF
clauses within an IF statement. There can be only one ELSE clause within an IF statement (and it comes just
before the END IF). Also, each THEN clause within the IF statement ends with a semicolon.

11
12
13
14
15
16
17
18
19
20
21
22
The IF clause now contains multiple ELSIF clauses and an ELSE clause. Observe that the ELSIF clauses have
conditions, but the ELSE clause has no condition. The condition for ELSIF should be followed by the THEN
clause that is executed if the condition of the ELSIF clause returns TRUE. When you have multiple ELSIF
clauses, if the first condition is FALSE or NULL, the control shifts to the next ELSIF clause.

23
The IF clause now contains multiple ELSIF clauses and an ELSE clause. Observe that the ELSIF clauses have
conditions, but the ELSE clause has no condition. The condition for ELSIF should be followed by the THEN
clause that is executed if the condition of the ELSIF clause returns TRUE. When you have multiple ELSIF
clauses, if the first condition is FALSE or NULL, the control shifts to the next ELSIF clause.

24
25
26
27
28
29
30
31
CASE – An expression that determines a course of action based on conditions and can be used outside of a
PL/SQL block in a SQL statement.
Condition – An expression with a TRUE or FALSE value that is used to make a decision.
IF – Statement that enables PL/SQL to perform actions selectively based on conditions.
LOOP– Control structures- Repetition statements that enable you to execute statements in a PL/SQL block
repeatedly.

32
33
Release Date: August, 2016
Updates:
2
3
4
5
The WHEN clauses, “WHEN 5,” “WHEN 10,” “WHEN 12,” etc. mean: WHEN v_numvar is equal to 5, and
WHEN v_numvar is equal to 10, etc.

6
7
The same logic from above, rewritten using an IF statement:

DECLARE
v_num NUMBER := 15;
v_txt VARCHAR2(50);
BEGIN
IF v_num > 20 THEN v_txt := 'greater than 20';
ELSIF v_num > 15 THEN v_txt := 'greater than 15';
ELSE v_txt := 'less than 16';
END IF;
DBMS_OUTPUT.PUT_LINE(v_txt);
END;

8
9
A CASE expression is different from a CASE statement. A CASE expression is used to find/create a value to
be assigned to a variable. It must begin with a variable name that was previously declared. It ends with
END; (not END CASE;).

10
11
Answer:

Grade: C
Appraisal: Good

Statement processed.

12
Answer: "Same value" will be displayed. Remember, read the highlighted WHEN clause as, "When v_in_var
is equal to v_in_var, then assign "Same value" to v_out_var and skip to the line following the CASE
expression end." Since v_in_var is equal to itself, the code will display the phrase, "Same value."

13
Searched CASE expressions are more flexible, allowing non-equality conditions (and compound conditions)
to be tested and different variables to be used in different WHEN clauses.

14
We could have used a non-searched CASE expression. The example in the slide could be written as:

v_appraisal :=
CASE v_ grade
WHEN ‘A’ THEN ‘Excellent’
WHEN ‘B’ THEN ‘Good’
WHEN ‘C’ THEN ‘Good’
ELSE ‘No such grade’
END;

15
CASE expressions are actually functions, which always return exactly one value. A common, built-in
function is SYSDATE. Just like a CASE expression, SYSDATE assigns one value to a variable.

v_date := SYSDATE;

16
A CASE expression has only one terminating semicolon at the END;, while a CASE statement has a
semicolon after each executable statement in a WHEN clause.

17
You can build a simple Boolean condition by combining number, character, or date expressions with
comparison operators.

You can build a complex Boolean condition by combining simple Boolean conditions with the logical
operators AND, OR, and NOT. The logical operators are used to check the Boolean variable values and
return TRUE, FALSE, or NULL. In the Logic Table shown above:

AND returns TRUE only if both of its operands are TRUE


OR returns FALSE only if both of its operands are FALSE
NULL and TRUE always evaluates to NULL because it is not known whether the second operand evaluates
to TRUE or not

Note: The negation of NULL (NOT NULL) results in a null value because null values are indeterminate.

18
The AND Logic Table on the previous slide can help you evaluate the possibilities for the Boolean condition
in this slide.

Answers:
1. TRUE
2. FALSE
3. NULL
4. FALSE

19
CASE expression – An expression that selects a result and returns it into a variable.
CASE statement – A block of code that performs actions based on conditional tests.
Logic Tables – Shows the results of all possible combinations of two conditions.

20
21
Release Date: August, 2016
Updates:
WARNING:

When a user executes a PL/SQL block in APEX that contains an infinite loop, there is no way for the user to
stop the loop. It can only be stopped by the DBA who oversees the Academy database. If the loop does not
contain DML statements, closing the browser window and reopening it will allow the user to continue
coding. If the block contains a FOR UPDATE clause, the affected table(s) will remain locked until released by
the DBA, which may take a day or more.

Be careful executing loops. All loops required by this course should have some type of limiting condition.
NO infinite loops are required as part of this course.

2
3
4
Each loop is structured for a specific purpose. These loops are used to write code to handle all situations
(problems). Loops can repeat one statement, a group of statements, and/or a block. Loops have a scope
and loop variables have a life.

5
6
Be careful as you begin to write code using loops. Typically, your exercises in this course will not include
infinite loops. If you accidentally trigger an infinite loop, you may have to restart your computer, or at least
close and restart your browser and APEX.

7
8
9
10
11
The statement, EXIT WHEN v_counter > 10, is logically identical to:

IF v_counter > 10 THEN EXIT;


END IF;

However, in PL/SQL, the EXIT WHEN statement is the appropriate syntax. From a programmer's
perspective, it is the more elegant solution.

12
Basic Loop – A sequence of statements between the keywords LOOP and END LOOP; the statements must
execute at least once.
Counter – A counter is a variable that programmers use to keep track of the number of times a loop
executes (or repeats). When a specific value is reached, it triggers the execution of the EXIT command
which stops the loop from repeating, passing control to the first command following the END LOOP
command.
END LOOP – A PL/SQL command that marks the end of the statements within a loop and returns control to
the corresponding LOOP statement that introduced it (the loop begins again).
EXIT – Statement to terminate a loop.
LOOP – A PL/SQL command that marks the beginning of the statements within a loop.

13
14
Release Date: August, 2016
Updates:
WARNING:

When a user executes a PL/SQL block in APEX that contains an infinite loop, there is no way for the user to
stop the loop. It can only be stopped by the DBA who oversees the Academy database. If the loop does not
contain DML statements, closing the browser window and reopening it will allow the user to continue
coding. If the block contains a FOR UPDATE clause, the affected table(s) will remain locked until released by
the DBA, which may take a day or more.

Be careful executing loops. All loops required by this course should have some type of limiting condition.
NO infinite loops are required as part of this course.

2
3
4
The WHILE loop is a conditional loop that continues to execute as long as the condition in the loop control
evaluates to TRUE. Since the WHILE loop depends on a condition and is not fixed, use the WHILE loop when
you don’t know in advance the number of times a loop must execute.

5
6
7
Notice the similarities and differences to the basic loop from the previous lesson:

DECLARE
v_loc_id locations.location_id%TYPE;
v_counter NUMBER(2) := 1;
BEGIN
SELECT MAX(location_id) INTO v_loc_id FROM locations
WHERE country_id = 'CA';
LOOP
INSERT INTO locations(location_id, city, country_id)
VALUES((v_loc_id + v_counter), 'Montreal', 'CA');
v_counter := v_counter + 1;
EXIT WHEN v_counter > 3;
END LOOP;
END;

8
9
10
11
12
13
Note these examples for controlling the counter through the FOR loop:
FOR i IN 1..5 LOOP …; -- successive values 1,2,3,4,5
FOR i IN REVERSE 1..5 LOOP …; -- successive values 5,4,3,2,1
FOR i IN REVERSE 5..1 LOOP …; -- will cause an error.
What if we want to increase (or decrease) the loop counter by 2 each time instead of by 1, giving successive values
2,4,6 instead of 1,2,3 for use inside the loop?
We can do this by declaring an explicit variable and initializing it to twice the loop counter. For example:
DECLARE
v_counter INTEGER;

BEGIN
FOR i IN 1..3 LOOP
v_counter := i * 2;

END LOOP;

14
15
16
17
A basic loop allows the execution of its repetitive statement(s) at least once, even if the condition is already
met upon entering the loop. Without the EXIT statement, the loop would be infinite.

Use the WHILE loop to repeat a sequence of statements until the controlling condition is no longer TRUE.
The condition is evaluated at the start of each iteration. The loop terminates when the condition is FALSE. If
the condition is FALSE at the start of the loop, then no further iterations are performed.

FOR loops have a control statement before the LOOP keyword to determine the number of iterations that
PL/SQL performs. Use a FOR loop if the number of iterations is predetermined.

Note: All loops allow the use of an EXIT WHEN condition allowing the loop to terminate before the WHILE
condition is false or the upper bound of the FOR loop is reached

Remember that all the variables used within the loop block have a scope. The specific loop needed is
determined by the problem being solved.

18
FOR Loop – Repeats a sequence of statements until a set number of iterations are fulfilled.
Lower Bound – The FOR loop syntax that specifies the lower bound for the range of counter values.
REVERSE – A PL/SQL command that causes the FOR loop counter to decrement with each iteration from the
upper bound to the lower bound.
Upper Bound – The FOR loop syntax that specifies the upper bound for the range of counter values.
WHILE Loop – Repeats a sequence of statements until the controlling condition is no longer TRUE.

19
20
Release Date: August, 2016
Updates:
WARNING:

When a user executes a PL/SQL block in APEX that contains an infinite loop, there is no way for the user to
stop the loop. It can only be stopped by the DBA who oversees the Academy database. If the loop does not
contain DML statements, closing the browser window and reopening it will allow the user to continue
coding. If the block contains a FOR UPDATE clause, the affected table(s) will remain locked until released by
the DBA, which may take a day or more.

Be careful executing loops. All loops required by this course should have some type of limiting condition.
NO infinite loops are required as part of this course.

2
3
4
Feel free to run this block in APEX to see its successive iterations.

The slide example shows a FOR loop nested inside another FOR loop. But (for example) we could nest a
WHILE loop inside a FOR loop; or a FOR loop inside a basic loop; or etc. All combinations are allowed.

5
Notice that when V_INNER_DONE = 'YES', PL/SQL exits the inner loop but the outer loop continues
executing.

6
7
8
The loop labels are not required in this example, but they do make the code more readable.

9
In this example, the outer_loop label is necessary because we reference it in an EXIT statement within the
inner loop. The inner_loop label is not strictly necessary. The label names are included after the END LOOP
statements for clarity.

10
Label Delimiters – Characters placed before (<<) and after (>>) a loop label to identify the label as a loop
label.
Loop Label – A loop identifier that is required in order to exit an outer loop from within an inner loop.

11
12
Release Date: August, 2016
Updates:
2
3
4
5
6
7
A SQL cursor is a private Oracle SQL working area. The implicit cursor is used by the server to test and
parse the SQL statements. Using implicit cursors, we can test the outcome of SQL statements in PL/SQL.

An implicit cursor is always called “SQL”, and we can access its attributes: SQL%FOUND, SQL%NOTFOUND
and SQL%ROWCOUNT.

You can use explicit cursors to name a context area and access its stored data.

8
To limit the SELECT statement so it returns only one row, the WHERE clause must be matching on either
the primary key or other unique column. For example:

SELECT …
FROM employees
WHERE employee_id = 101;

Group functions without a GROUP BY clause also return exactly one row. For example:

SELECT COUNT(*) INTO v_number_of_employees


FROM employees;

In all situations where the SELECT statement may return more than one row, and in situations where
multiple rows are needed for processing, programmers should declare and use an explicit cursor.

9
As mentioned earlier, the point is not whether there is more than one row, but that there can be more
than one row. Programmers must think about the data that is possible as well as the data that actually
exists now in order to minimize the need to modify the program in the future.

Explicit cursors are a great tool to make programming in PL/SQL easier and faster. For queries that return
more than one row, you can explicitly declare a cursor to hold the data and then process the rows
individually.

It is possible in PL/SQL to write a SELECT statement which returns more than one row, without using
explicit cursors. This technique is called bulk binding, but it is beyond the scope of this course. Also, bulk
binding is not always possible, so we still need to understand and use explicit cursors.

10
As with variables to be used in the block of code, cursors are defined in the declarative section. To access
the data represented by the cursor definition, you must first OPEN the cursor, then FETCH the current row
from the cursor in order to process the data in that row. When all required data is processed and/or the
cursor is no longer needed, you must CLOSE the cursor.

The meaning and use of the keywords CURSOR, OPEN, FETCH, and CLOSE will be explained and
demonstrated over the next several slides.

11
The name and structure of the cursor is defined in the declarative section using the CURSOR keyword. The
OPEN statement executes the SELECT statement found in the CURSOR definition and populates the active
set with the results of the SELECT.

12
13
The FETCH statement retrieves the current row and advances the cursor to the next row until the last row
is retrieved or until a specified condition is met.

14
15
16
17
Remember, the ORDER BY clause is last. SQL SELECT statements can be complex…especially with joins and
subqueries combined. The code needs to be written so it is readable and understandable. Along with these
guidelines, remember to indent, capitalize keywords, and include empty space/blank lines for readability.

18
In the executable section, a single-row SELECT statement must have an INTO clause. However, a SELECT
statement in a cursor declaration cannot have an INTO clause. This is because you are not retrieving the
data into variables yet (that happens in the FETCH statement).

19
Note that even if there is currently only one employee in department #30, we should still declare a cursor,
because in the future there may be more than one employee.

20
21
22
23
24
25
26
As you can see on the slide, we can use explicit cursor attributes to test for the outcome of the FETCH. Here
we are using cur_emps%NOTFOUND to exit the LOOP.

27
Data type mismatching is the most common mistake that programmers make when writing their code. Data
types must be compatible between the table and the variables. Use of %TYPE is helpful in eliminating data
type mismatches.

The variables in the FETCH statement must line up with the columns in the cursor, so make sure to have the
same number of variables in your INTO statement as you have in your SELECT list. Loops are typically used
to fetch data from cursors. The %NOTFOUND cursor attribute is typically used to stop the loop.

28
29
Answer: The SELECT statement in the cursor declaration returns three columns, but the FETCH statement
references only two variables.

30
Answer: There needs to be an EXIT WHEN added after the FETCH line. The OPEN statement populates the
active set with exactly one row. The first time through the loop, that row will be fetched and displayed. The
second (and third, and fourth...) times through the loop, no test is made for the end of the cursor.
Therefore, the first row will be displayed over and over again (or possibly a time-out type error may occur
since the result of the code is an infinite loop).

31
Once a CURSOR is CLOSEd, the memory is released. But, the data is still in memory and will be overwritten
when a new OPEN statement is executed. So, if the CURSOR is no longer needed, the memory can be
released.
A cursor can be reopened only if it is closed.

32
Once a CURSOR is CLOSEd, the memory is released. But, the data is still in memory and will be overwritten
when a new OPEN statement is executed. So, if the CURSOR is no longer needed, the memory can be
released.
A cursor can be reopened only if it is closed.

33
Because a context area is a private memory area, any changes to database data (DML statements)
executed by other users will not be visible to our cursor until we close and reopen the cursor.

34
35
Active set – The set of rows returned by a multiple row query in an explicit cursor operation.
CLOSE – Disables a cursor, releases the context area, and undefines the active set.
Context Area – An allocated memory area used to store the data processed by a SQL statement.
Cursor – A label for a context area or a pointer to the context area.
Explicit Cursor – Declared by the programmer for queries that return more than one row.
FETCH – Statement that retrieves the current row and advances the cursor to the next row either until
there are no more rows or until a specified condition is met.
Implicit Cursor – Defined automatically by Oracle for all SQL DML statements.
OPEN – Statement that executes the query associated with the cursor, identifies the active set, and
positions the cursor pointer to the first row.

36
37
38
Release Date: August, 2016
Updates:
2
3
4
5
There are 11 columns in EMPLOYEES, so 11 variables must be declared and populated by the INTO clause in
the FETCH statement. And what if a twelfth column was added to the table later?

6
7
The record definition on the right is more efficient to write and to read.

8
PL/SQL variables and cursors have attributes, which are properties that let you reference the data type and
structure of an item without repeating its definition. A percent sign (%) serves as the attribute indicator.

PL/SQL Record Structure - The whole record is accessed with the name of the record. To reference an
individual field, use the dot notation as shown below:

record_name.field_name

For example, you reference the job_id field in the v_emp_record record as follows:

v_emp_record.job_id

9
The %ROWTYPE attribute provides a record type that represents a row in a table or a cursor. The record
can store an entire row of data selected from the table or fetched from a cursor. %ROWTYPE is used to
declare variables with a composite type that matches the type of an existing database cursor or table.

10
Note: The cursor must be declared before the record which references it. We reference the individual fields
in the record as record_name.field_name (look at the PUT_LINE arguments).

A major benefit of defining record types is the code still works even if another column is added to the
underlying table.

11
Answer: three fields
v_emp_dept_record.first_name
v_emp_dept_record.last_name
v_emp_dept_record.department_name

12
In order to be able to control the loop we need information about the cursor. The same four, built-in cursor
attributes we looked at in an earlier lesson for implicit cursors can also be used when we are working with
explicit cursors.

The %ISOPEN attribute is never true for implicit cursors, as Oracle is doing all the work for us, it
automatically OPENs, FETCHEs, and CLOSEs the cursor. %ISOPEN is useful in blocks where we may OPEN
and CLOSE the cursor conditionally. If you try to OPEN an OPEN cursor, you will get an error, so we may
need to test to see if the cursor is OPEN before we try to OPEN it.

The other three are useful attributes that help to identify where the pointer is in relation to the data in the
CURSOR.

13
%ISOPEN is useful in blocks where we may OPEN and CLOSE the cursor conditionally. For example:

DECLARE


BEGIN
IF some_condition THEN OPEN cursor_name;
END IF;
-- at this point, the cursor MAY be open or may not be open


-- at this point, we need the cursor open, but we can't open it if it is already open, so
-- we check to see if the cursor is open, and if it isn't, we open it
IF NOT cursor_name%ISOPEN THEN OPEN cursor_name;
-- if the first IF statement did not open the cursor, the

14
15
16
In this example, we exit from the loop and close the cursor when one of two conditions is true:

The active set contains 11 rows or less and we have fetched all of them.

The active set contains at least 12 rows, but we want to fetch only the first 11.

17
To avoid the error above, we would copy the cursor attribute value to a variable, then use the variable in the SQL
statement. For example:

DECLARE
CURSOR cur_emps IS ...;
v_emp_record emp_cursor%ROWTYPE;
v_count NUMBER;
v_rowcount NUMBER; -- declare variable to hold cursor attribute
BEGIN
OPEN cur_emps;
LOOP
FETCH cur_emps INTO v_emp_record;
EXIT WHEN cur_emps%NOTFOUND;
v_rowcount := cur_emps%ROWCOUNT; -- "copy" cursor attribute to variable
INSERT INTO top_paid_emps (employee_id, rank, salary)
VALUES
(v_emp_record.employee_id, v_rowcount, v_emp_record.salary); -- use variable in SQL statement

18
%ISOPEN – Returns the status of the cursor.
%NOTFOUND – An attribute used to determine whether a query found any rows matching the query
criteria.
Record – A composite data type in PL/SQL, consisting of a number of fields each with their own name and
data type.
%ROWCOUNT – An attribute that processes an exact number of rows or counts the number of rows
fetched in a loop.
%ROWTYPE – Declares a record with the same fields as the cursor or table on which it is based.

19
20
Release Date: August, 2016
Updates:
2
3
4
Cursors and Loops were made for one another. The majority of your PL/SQL programs will involve working
on many rows from the same table, so Oracle made that part easy for you by combining the declaration of
a PL/SQL RECORD and the use of a CURSOR in the cursor FOR loop syntax.

5
You can simplify your coding by using a cursor FOR loop instead of the OPEN, FETCH, and CLOSE
statements. A cursor FOR loop implicitly declares its loop counter as a record that represents a row
FETCHed from the database. Next, it OPENs a cursor, repeatedly FETCHes rows of values from the active set
into fields in the record, then CLOSEs the cursor when all rows have been processed.

6
7
The cursor FOR loop greatly simplifies the code writing and can make maintenance easier.

Although there are fewer lines of code, using a cursor FOR loop will NOT improve performance. The OPEN,
FETCH ... INTO, EXIT WHEN ...%NOTFOUND, and CLOSE are still happening, they just happen automatically
when combining a cursor with a FOR loop.

There is no need to declare the variable v_emp_rec in the declarative section when using the cursor FOR
loop. The FOR loop syntax handles that for you. The syntax "FOR v_emp_rec IN …" implicitly defines
v_emp_rec just as the explicit definition of "v_emp_rec cur_emps%ROWTYPE" when not using the FOR
loop.

The scope of the implicit record is restricted to the loop, so you cannot reference the fetched data outside
the loop. Within the loop, you can access fetched data using record_name.column_name (ex.
v_emp_rec.employee_id).

8
Answer: two fields, because the cursor whose %ROWTYPE it is based on SELECTs two table columns.

9
10
11
12
The downside to this simplification is you cannot reference explicit cursor attributes such as %ROWCOUNT
and %NOTFOUND because the cursor does not have an explicit name (there is no cur_emps or cur_depts).

13
14
Cursor FOR loop – Automates standard cursor-handling operations such as OPEN, FETCH, %NOTFOUND,
and CLOSE, so that they do not need to be coded explicitly

15
16
Release Date: August, 2016
Updates:
2
3
4
5
6
7
In a production environment, the location_id would not be hard-coded in the OPEN statement, but would
be "entered" by the user in the interface to the database.

8
We specify the datatype of the cursor parameter, but not the size. For example: VARCHAR2, not
VARCHAR2(20).

When the cursor is opened, the parameter value is passed to the Oracle server, which uses it to decide
which rows to retrieve into the active set of the cursor. This means that you can open and close an explicit
cursor several times in a block, or in different executions of the same block, returning a different active set
on each occasion.

9
10
11
12
The purpose of this code is to fetch and display all employees in the department with the highest
department_id. Note that the maximum department_id is stored in the v_deptid variable and is then
passed into the empcur cursor. Note also that the SELECT MAX(department_id) …. will always return
exactly one row, so an explicit cursor is not needed for this.

13
Parameters are placed inside parentheses following the CURSOR. FOR…END LOOP statements let you
execute a sequence of statements multiple times. The CURSOR will repeatedly use new value(s) that are
passed into the parameter.

14
15
16
17
Release Date: August, 2016
Updates:
2
If using the online/hosted Application Express at iAcademy, statements are automatically committed upon
completion (unlike a typical production database where a deliberate COMMIT statement must be issued to
actually modify data stored in the database). Therefore, all your DML statements will be committed upon
completion (thereby releasing all locks held), and you will not be able to demonstrate locking and lock
waits.

3
An open cursor provides a read-consistent view of the data fetched by the cursor. This means that any
updates made by other users since the cursor was opened will not be seen when we fetch the rows, even if
the updates were committed. Our session would have to close and re-open the cursor in order to see the
committed updates.

4
5
6
7
It may help to think of a lock as being like a red traffic light. If another session has already locked the rows,
the traffic light is red. Using the default, our session is an infinitely patient driver who will wait indefinitely
until the traffic light turns green (i.e. the locks are released). If we use NOWAIT, we have no patience at all;
we see the red light and immediately back off.

8
If we don’t specify a column-name, then rows of both tables are locked. This causes unnecessary extra
locking when (in this example) we want to lock only the EMPLOYEES rows, not the DEPARTMENTS rows.
Strangely, it doesn’t matter which column-name we use. The slide example would work the same if we
coded:

…. FOR UPDATE OF job_id;


or … FOR UPDATE OF last_name;
or … FOR UPDATE OF <any other column of EMPLOYEES>;

Individual columns are never locked, only whole rows.

9
10
11
12
13
14
FOR UPDATE – Declares that each row is locked as it is being fetched so other users can not modify the
rows while the cursor is open.
NOWAIT – A keyword used to tell the Oracle server not to wait if the requested rows have already been
locked by another user.

15
16
Release Date: August, 2016
Updates:
2
3
4
5
Answer: Because we will OPEN C_EMP several times (once for each department) and it must fetch a
different set of rows each time.

6
7
8
The inner CUR_EMP loop executes once for each row fetched by the CUR_DEPT cursor and fetches a
different subset of EMPLOYEES each time due to the parameter p_deptid.

9
In many situations involving multilevel reports, the tables will usually be related to each other by a foreign
key.

10
The inner CUR_DEPT loop executes once for each row fetched by the CUR_LOC cursor and, due to the
parameter p_locid, fetches a different subset of DEPARTMENTS each time.

11
This code is functionally identical to that in the previous slide, but is more compact and easier to maintain.

12
Answer: employees in department 1700 who currently earn less than 10000.

13
14
Release Date: August, 2016
Updates:
2
3
In previous lessons, we saw a record declared with %ROWTYPE based on a cursor's structure. We will now
examine a record based on a table's structure as we prepare to work with more complex record structures.

4
5
Answer: eleven, one for each column in the table.

6
In production environments it is not uncommon to have tables with forty or fifty columns.

7
8
A record typically holds logically related data and allows the data to be treated as a unit or individually.

9
10
Records, even if declared using %ROWTYPE, are not the same as rows in a table.

Table rows are stored on disk and the data in a table row is permanent (unless modified using DML).

Records are stored in memory (like other variables) and the data stored in a record will persist only for the
duration of the code block's execution.

11
Oracle scalar data types such as VARCHAR2, DATE, and NUMBER are pre-defined data types that are
automatically declared (with global scope) in every Oracle database. Using the TYPE keyword, you are
simply creating additional data types with a custom structure to be used within your block of code.

The type_name is the name you give to your custom data type.

The field_declaration contains the field name(s), data type(s), and any initialization values such as NOT
NULL or DEFAULT.

The identifier is the name of the variable that is declared using the custom data type you created.

Fields not assigned an initial value are initialized to NULL.

The DEFAULT keyword can be used when defining fields.

12
13
Answer: there are four fields that can be addressed in v_emp_dept_rec.

They are:

v_emp_dept_rec.first_name
v_emp_dept_rec.last_name
v_emp_dept_rec.dept_info.department_id
v_emp_dept_rec.dept_info.department_name

When user-defined types contain other user-defined types, you must use multiple levels of dot-notation to
reference individual scalar fields.

Using the code from the slide, create your own anonymous block that will initialize each of the four fields
and then execute a DBMS_OUTPUT.PUT_LINE to display the values for each field.

14
Procedures, functions, packages, and triggers will be covered late in this course.

15
What will be displayed by each of the PUT_LINEs?

Run the code in APEX and see if your predictions are correct.

16
PL/SQL record – a composite data type consisting of a group of related data items stored as fields, each
with its own name and data type.

Note: The code on the previous slide should have displayed the following:

Amy
Clara and Amy
Clara

17
18
Release Date: August, 2016
Updates:
2
3
4
5
INDEX BY tables are sometimes referred to as "Associative Arrays."

6
7
The primary key is not like a sequence. Values are not generated automatically, but must be specifically
inserted. Therefore some values can be missing, as the slide shows.

Although an INDEX BY table can have a VARCHAR2 primary key, a BINARY_INTERGER is frequently used to
its faster speed and more efficient storage.

8
9
10
11
12
EXISTS(n), PRIOR(n), and NEXT(n) take an index number (n) corresponding to a row in the INDEX BY table as
a parameter.

TRIM and DELETE also may take parameters.

13
The COUNT method returns the number of elements in the INDEX BY table.

Note: A full discussion of methods is beyond the scope of this course.

14
An INDEX BY table of records is just like any other INDEX BY table, except that the non-primary-key field is a
composite (a record) rather than a scalar. We populate it and use methods such as COUNT, EXISTS and
FIRST on it exactly as before.

Individual fields within a table of records can be referenced by adding an index value in parentheses after
the table of records name.

Syntax: table(index).field

Example: v_employees_tab(index).hire_date

The index value in the example could be an actual value (ex. 1, 5, 12, etc.) or a reference to a value
(v_emp_rec_tab.LAST).

15
16
Collection – A named set of multiple occurrences of the same kind of data
INDEX BY table – A collection which is based on a single field or column
INDEX BY table of records – A collection which is based on a composite record type

17
18
Release Date: August, 2016
Updates:
2
3
Computer programs should be written so that even unanticipated errors are handled, no program should
ever just crash or quit working.

4
Some examples of errors you may have seen:

Entering an incorrect username and/or password


Forgetting to include the @ in an email address
Entering a credit card number incorrectly
Entering an expiration date that has passed
Selecting more than one row into a single variable
Receiving “no rows returned” from a select statement

5
To confirm the spelling of Republic of Korea in the data, run a statement such as the following:

SELECT country_name
FROM countries
WHERE country_name LIKE '%Korea%';

6
Remember that a SELECT statement in PL/SQL must return exactly one row. This statement returns no rows
and therefore raises an exception in the executable section.

7
8
PL/SQL programs will start to get longer and more complicated due to the exception handling code needed
to handle all errors, but that is preferable to programs just crashing or quitting. By including exception
handling code, error messages can help the user understand what went wrong and how to correct it.

9
10
Programs are written to support or enhance the existing systems. If unhandled errors occur and the
program execution is stopped, users are frequently confused and might eventually be angry and frustrated
with the systems they are trying to use. So, errors need to be handled within the code to keep the
execution of the program running continuously.

11
12
13
Only one exception can occur at a time and only one handler (although it may include multiple statements)
may be executed.

14
When an exception is raised, the rest of the executable section of the block is NOT executed; instead, the
EXCEPTION section is searched for a suitable handler.

15
There is no exception handler in this block, therefore the block terminates unsuccessfully, returning an
"unhandled exception" status code to the calling environment (Application Express), which then reports the
exception as shown.

16
This code will successfully handle the exception inside the block, so PL/SQL returns a "success" status code
to the calling environment, which therefore will report Statement Processed (below the display of the
PUT_LINE).

17
18
19
20
21
If the exception NO_DATA_FOUND is raised by the program, then the statements in the corresponding
handler are executed.
If the exception TOO_MANY_ROWS is raised, then the statements in the corresponding handler are
executed.
However, if some other exception is raised, then the statements in the OTHERS exception handler are
executed.

22
23
24
Exception – Occurs when an error is discovered during the execution of a program that disrupts the normal
operation of the program.
Exception Handler – Code that defines the recovery actions to be performed when execution-time errors
occur.

25
26
Release Date: August, 2016
Updates:
2
3
4
5
6
An Oracle Server error is an error which is recognized and raised automatically by the Oracle server. There
are many thousands of such possible errors, and each one has a predefined error number and error
message.

User-defined errors (must be explicitly declared and raised by the PL/SQL programmer)

7
8
9
10
11
The EXCEPTION section can refer to exceptions only by name, not by number (i.e., we cannot code WHEN
ORA-##### THEN …).

12
13
14
15
The OTHERS handler will handle all types of raised exceptions: predefined, non-predefined, and user-
defined.

The EXCEPTION section can refer to exceptions only by name, not by number (i.e., we cannot code WHEN
ORA-##### THEN ….).

16
17
18
19
20
21
A full list of Oracle server error numbers can be found at http://docs.oracle.com/. Search for "database
error messages."

22
23
24
Why is the SQLCODE for NO_DATA_FOUND +100 instead of -01403?

Answer: some of these error codes are used in other (non-Oracle) databases, and +100 is an
internationally-agreed code when no rows are returned from a query. The code number -01403 is an
Oracle specific error code.

25
SQLCODE and SQLERRM are often used in a WHEN OTHERS handler. Someone (often the Database
Administrator) would be responsible for reading the ERROR_LOG table and taking suitable action.

Why can’t we use SQLCODE or SQLERRM directly in a SQL statement?

Answer: because that SQL statement (the INSERT INTO error_log in the slide) could also raise an exception,
which would change the values of SQLCODE and SQLERRM.

It is good programming practice to capture SQLERRM and SQLCODE in a WHEN OTHERS and insert the
returned values into an error table, so you can later go back and see what kind of problems your program
encountered, and if the same error shows up repeatedly, then include a specific handler for it.

26
Non-predefined Oracle Server Errors: Each of these has a standard Oracle error number (ORA-nnnnn) and
error message, but not a predefined name. We declare our own names for these so that we can reference
these names in the exception section.

Predefined Oracle Server Errors: Each of these has a predefined name. For example, if the error ORA-
01403 occurs when no rows are retrieved from the database in a SELECT statement, then PL/SQL raises the
predefined exception-name NO_DATA_FOUND.

PRAGMA EXCEPTION_INIT – Tells the compiler to associate an exception name with an Oracle error
number. That allows you to refer to any Oracle Server exception by name and to write a specific handler for
it.

SQLERRM – Returns character data containing the message associated with the error number

SQLCODE – Returns the numeric value for the error code (You can assign it to a NUMBER variable.)

27
28
29
Release Date: August, 2016
Updates:
2
3
Can you think of situations where the Oracle server would execute a statement successfully (and therefore
not raise an exception automatically), but there is still an "error" from the user’s viewpoint.

Answers:

A DML UPDATE or DELETE statement modifies no rows.


A SELECT statement successfully reads a row which should not exist yet.
A Stock Clerk has been identified as a manager, but our business rules state that clerks cannot be
managers.

4
5
6
Remember that an UPDATE or DELETE statement is treated as successful by the server even if it modifies
no rows. Therefore the Oracle server will not automatically raise an exception in this case. If we want to
raise an exception, we must do it ourselves.

7
Remember that an UPDATE or DELETE statement is treated as successful by the server even if it modifies
no rows. Therefore the Oracle server will not automatically raise an exception in this case. If we want to
raise an exception, we must do it ourselves.

8
9
10
11
12
13
14
15
16
Note that an error raised by RAISE_APPLICATION_ERROR is an unhandled exception which is propagated
back to the calling environment. The whole idea is to allow the calling application to display a business-
meaningful error message to the user. If the exception was handled successfully within the PL/SQL block,
the application would not see the error at all.

17
Imagine an office worker trying to create a report and he/she receives an error message. Which of these
messages would be more helpful?

ORA-01403: no data found


ORA-20201: This manager has no employees

18
In this example, when an invalid last name is entered, the user-defined exception e_name is raised using its
error number -20999. Because the PRAGMA EXCEPTION_INIT was used to define the error name e_name
and its error code –20999, when the error code is raised, the exception handler for e_name is run, showing
the user (or the calling environment) a list of valid last names.

You can imagine that as coding becomes more complicated, such as that required in commercial
applications, that a lot of code will deal with defining and handling errors that may arise in a real-world
environment.

19
RAISE - Use this statement to raise a named exception.
RAISE_APPLICATION_ERROR - A procedure used to return user-defined error messages from stored
subprograms.
User-Defined error - These errors are not automatically raısed by the Oracle Server, but are defined by the
programmer and are specific to the programmer's code.

20
21
Release Date: August, 2016
Updates:
2
3
4
A PL/SQL block nested within another PL/SQL block may be called a nested block, an enclosed block, a child
block, or a sub-block.

A PL/SQL block that calls another PL/SQL block, anonymous or named, may be referred to as either the
enclosing block or the parent block.

5
6
The general advantage of a nested block is that you create a scope for all the declared objects and
executable statements in that block. You can use this scope to improve your control over activity in your
program. This also means that if an error occurs in a block, then it is just in this block execution is halted,
once the error has been handled locally, program control continues outside that block.

CURSORs are a type of variable, and subject to the same scoping rules as more “obvious” variables.

7
8
9
10
Since employee_id 999 does not exist, the SELECT statement within the inner block results in an error and
reverts to the local exception handling section. Because the error is not handled there, the error
propagates to the calling environment. In this case, the calling environment is the outer block. The WHEN
OTHERS exception handler gets executed and the output is “Message 4.”

11
Answer: an error, E_MYEXCEP is not declared in the outer block.

12
13
14
Answer: "Message 4" is displayed.

15
Answer: since the "User-Defined Exception" is not handled by the code, it is returned to the calling
environment (in our case APEX).

16
An exception should be raised only when an error occurs that makes it impossible or undesirable to
continue processing. If there is no exception handler in the current block for a raised exception, the
exception propagates according to the following two rules:

1. If there is an enclosing block for the current block, the exception is passed on to that block. The
enclosing block then becomes the current block. If a handler for the raised exception is not found, the
process repeats.

2. If there is no enclosing block for the current block, an unhandled exception error is passed back to the
host environment.

17
18
Exception Scope – The portion of a program in which the exception is declared and is accessible.
Exception Visibility – The portion of the program where the exception can be accessed without using a
qualifier.
Propagation of exceptions – The inner block terminates unsuccessfully, and PL/SQL passes the exception to
the outer block.

19
20
Release Date: August, 2016
Updates:
2
3
4
5
Remember, every object stored in the database – tables, views, indexes, synonyms, sequences, and now
PL/SQL subprograms – must have a name.

An anonymous block is a block of code that is an unnamed block, and as it does not have a name it cannot
be stored in the database. This means that the only way to reuse these programs is to save them in files on
your pc, or as files in Oracle Application Express. By definition, an anonymous block can only be a
procedure. It cannot return a value so it cannot be a function.

6
7
The alternative to an anonymous block is a named block. How the block is named depends on what you are
creating. You can create a named procedure (does not return values except as out parameters), a function
(must return a single value not including out parameters), a package (groups functions and procedures
together), or a trigger.

The keyword DECLARE is replaced by CREATE PROCEDURE procedure-name IS | AS. In anonymous blocks,
DECLARE states, "this is the start of a block." Because CREATE PROCEDURE states, "this is the start of a
subprogram," we do not need (and must not use) DECLARE.

8
Almost every programming language supports subprograms. They are a part of structured programming.
We can consider it as a separate block of statements (with its own declarations and programming
statements), but still under the control of the main program.

The main block calls the subprogram by its name to execute its set of statements. This may be a part of the
conditions as well. That means the main program may or may not call subprogram based on certain
conditions.

Repeatable tasks are generally separated as subprograms to allow the user to use them as many times as
possible. This also improves the readability of the main program, which is being divided into several
meaningful tasks, where each task (subprogram) may have its own set of programming statements
(including local declarations).

9
Code Reuse: for example (in a school or college database), a single PL/SQL procedure which accepts a
student id number as a parameter and outputs a complete record describing that student. This procedure
could be used in a Student Grades application, also in a Sports Teams application, also in a Student Health
application…in fact in any application which needs information about a student.

10
Subprogram security and privileges will be covered in a later section. For now, if a subprogram contains a
SQL statement which SELECTs from a table, the subprogram owner needs SELECT privileges on that table,
but the user does not. This means that the only way the user can access the table is through the
subprogram, not by any other route. Therefore the user cannot see sensitive or confidential data unless the
subprogram code explicitly allows it.

11
Improved performance: a subprogram is compiled only once, when it is (re)CREATEd. An anonymous block
is compiled (while the user waits) every time it is executed.

12
A function MUST return a value using the RETURN statement.
A procedure can only return a value using an OUT or an IN OUT parameter.
Procedures and functions can both return data as OUT and IN OUT parameters.
The return statement in a function returns control to the calling program and returns the results of the
function.
The return statement within a procedure is optional. It returns control to the calling program before all of
the procedure's code has been executed.
Functions can be called from SQL, procedures cannot.
Functions are considered expressions, procedures are not.

Packages will be covered in a later section. For now, a package is a group of several related procedures
and/or functions which are created and managed as a single unit. Packages are very powerful and
important, but the "building blocks" are still procedures and functions.

13
14
There is no difference between IS and AS, either can be used.

An option of the CREATE PROCEDURE statement is to follow CREATE by OR REPLACE. The advantage of
doing so is that should you have already created the procedure in the database, you will not get an error.
On the other hand, should the previous definition be a different procedure of the same name, you will not
be warned, and the old procedure will be lost.

There can be any number of parameters, each followed by a mode and a type. The modes are IN (read-
only), OUT (write-only), and IN OUT (read and write). You will learn more about parameters and their
modes in the next two lessons.

15
16
To run the code above, you would first have to run:

CREATE TABLE dept AS SELECT * FROM departments;

If you create the dept table, please remember to DROP it when you are finished.

17
In a real-life procedure, the v_dept_id and v_dept_name values would be passed into the procedure as
parameters, not hard-coded as shown here.

To run the code above, you would first have to run:

CREATE TABLE dept AS SELECT * FROM departments;

If you create the dept table, please remember to DROP it when you are finished.

18
19
20
When a subprogram is CREATEd, the source code is stored in the database (therefore the named code
object is created) even if compilation errors occurred. This is why we need …OR REPLACE…

21
22
23
24
25
26
This is similar to the idea of nested anonymous blocks covered earlier in the course. The example shown
here shows nested procedures, but PL/SQL functions can also be nested in this way.

Why don't we just write all the code in a single (normal) procedure?

Answer: to restrict the scope of variables. Normal scoping rules apply, so a variable declared within the
nested subprogram cannot be referenced in the outer program. This helps to make it clear which variables
are used in which part of the code.

27
28
To develop a stored procedure when not using Oracle Application Express, perform the following steps:
1. Write the code to create a procedure in an editor or a word processor, and then save it as a SQL script
file (typically with a .sql extension).
2. Load the code into one of the development tools such as iSQL*Plus or SQL Developer.
3. Create the procedure in the database. The CREATE PROCEDURE statement compiles and stores source
code and the compiled m-code in the database. If compilation errors exist, then the m-code is not stored
and you must edit the source code to make corrections.
4. After successful compilation, execute the procedure to perform the desired action. Use the EXECUTE
command from iSQL*Plus or an anonymous PL/SQL block from environments that support PL/SQL.

29
30
Anonymous Blocks – Unnamed executable PL/SQL blocks that can not be reused no stored for later use.
IS or AS – Indicates the DECLARE section of a subprogram.
Procedures – Named PL/SQL blocks that can accept parameters and are compiled and stored in the
database.
Subprograms – Named PL/SQL blocks that are compiled and stored in the database.

31
32
Release Date: August, 2016
Updates:
2
3
4
5
6
Answer: normally you would not need to know the old (before) value. The next slide shows the procedure
code.

7
8
You were introduced to CURSORs with parameters earlier in the course, and the parameters for procedures
and functions are no different.

Parameter means the name, argument means the value. In the example on the previous slide,
p_student_id is a parameter while 1023 is an argument.

9
10
11
12
In this example, the PROCESS_EMPLOYEES procedure uses a cursor to process all the records in the
EMPLOYEES table and passes each employee’s ID to the RAISE_SALARY procedure. If there are 20 rows in
the EMPLOYEES table, RAISE_SALARY will execute 20 times. Every employee in turn receives a 10% salary
increase.

13
Subprograms pass information using parameters.

The parameters declared in a subprogram specification and referenced in the subprogram body are formal
parameters.

The variables or expressions passed from the calling subprogram are actual parameters. Actual parameters
contain the value being passed that will be used by the subprogram.

When you call a procedure, the actual parameters are evaluated and the results are assigned to the
corresponding formal parameters.

The actual parameter and its corresponding formal parameter must have compatible data types. If
necessary and possible, before assigning the value, PL/SQL converts the data type of the actual parameter
value to that of the formal parameter.

14
Answer: The formal parameter is called p_emp_id and the actual parameter is called v_emp_id. The value
stored in v_emp_id in the calling block is passed to the procedure. Within the fetch_emp procedure, that
value is referred to as p_emp_id, and the value stored in p_emp_id cannot be changed within fetch_emp.

p_emp_id is the formal parameter and v_emp_id is the actual parameter. We make the distinction because
the names can be different (as in this example). However, the data types must be compatible.

15
16
Because 2000 is a literal, not the name of a variable, it is both the actual parameter and the argument.

17
18
19
20
Argument – The actual value assigned to a parameter.
Actual Parameter – Can be literal values, variables, or expressions that are provided in the parameter list of
a called subprogram.
Formal Parameter – A parameter name declared in the procedure heading.
Parameters – Pass or communicate data between the caller and subprogram and are commonly referred to
as arguments.

21
22
Release Date: August, 2016
Updates:
2
3
4
IN parameters are constants within the procedure. They can be read but not modified.

Procedures with OUT or IN OUT parameters pass information back to the calling environment.

5
6
7
8
9
10
11
Formal parameters must be declared with datatypes, but no explicit sizes. In the slide example,
p_phone_no is declared as VARCHAR2, not VARCHAR2(n). The only exception to this rule is when a
parameter’s datatype is declared implicitly, for example when using %TYPE.

12
13
14
15
16
The most common method for passing parameters is the positional listing. All the earlier examples in this
section used the Positional notation.

If Combination notation is used, the positional parameters must come first before the named parameters.

17
So the following procedure with three parameters may be called in the following ways:

CREATE OR REPLACE PROCEDURE show_emps (p_emp_id IN NUMBER, p_department_id IN NUMBER,


p_hiredate IN DATE)…

Execute show_emps (101, 10, ’01-dec-2006’) – This is positional notation

Execute show_emps(p_department_id => 10, p_hiredate => ’01-dec-1007’, p_emp_id => 101) – this is
Named notation

Execute show_emps(101, p_hiredate => ’01-dec-2007’, p_department_id = 10) – this is the Combination
notation

18
19
20
21
22
23
Note: In Application Express, DESCRIBE procedure-name does not show which parameters have default
values.

24
The named notation for passing parameters is especially useful when the called procedure contains many
IN parameters, many of which have default values. Imagine a procedure which declares 10 İN parameters,
all of which have default values. We want to call the procedure, overriding the default value only for the
last parameter. We can simply code:

…. procedure_name(last_parameter_name => value);

Using the positional notation, all ten values must be passed, and the default values could not be used.

25
26
27
Combination Notation - Lists some of the actual parameters as positional (no special operator) and some as
named (with the => operator).
IN Parameter – Provides values for a subprogram to process.
IN OUT Parameter – Supplies an input value, which may be returned as a modified value.
Named Notation - Lists the actual parameters in arbitrary order and uses the association operator ( ‘=>'
which is an equal and an arrow together) to associate a named formal parameter with its actual parameter.
OUT Parameter – Returns a value to the caller.
Positional Notation - Lists the actual parameters in the same order as the formal parameters.

28
29
Release Date: August, 2016
Updates:
2
3
• In contrast, you should recall that a procedure is a named subprogram that may or may not return one or
more values and must be executed as a standalone statement (not as part of a SQL or PL/SQL statement).

4
If you disregard the caution above and do DML inside a function, often the message you get is “Mutating
table,” which will be covered in the next lesson.

5
6
PL/SQL parameters are used to pass information into and out of procedures, and into functions. They
support named and positional notation.

7
The phrase, “…return a value with a data type that is consistent…” means that (for example) if the function
header says:

CREATE OR REPLACE FUNCTION myfunc


RETURN NUMBER IS…

Then the body of the block could contain RETURN 123, but could not contain RETURN ‘Smith’ or RETURN
SYSDATE or RETURN TRUE.

8
This function accepts an employee_id as input and returns the employee’s salary.

9
From a business viewpoint, do you want this function to return a null or an error in this case? It depends.
Your call!

10
11
In PL/SQL expressions, the function identifier acts like a variable whose value depends on the parameters
passed to it.

12
13
In SQL expressions, a function must obey specific rules to control side effects. So, for example, if you want to call a stored function from a
SELECT statement, the stored function is not allowed to perform any DML statements before the RETURN statement in that function.
When a function is used in a SQL statement, it executes once for each row processed by the statement, just like Oracle-defined, single-
row functions such as UPPER, LOWER, ROUND, and so on.
As functions return a value when they are invoked, the call to them must have a mechanism to receive the value returned by the function.
So, if you need a function to verify the validity of a department number for an employee, you might develop the following function:
CREATE OR REPLACE FUNCTION valid_dept (p_dept_no departments.department_id%TYPE)
RETURN BOOLEAN IS v_valid VARCHAR2(1);
BEGIN
SELECT 'x‘ INTO v_valid
FROM departments WHERE department_id = p_dept_no;
RETURN(true);
EXCEPTION WHEN NO_DATA_FOUND THEN
RETURN(false);
WHEN OTHERS THEN NULL; END;
This function cannot be called from a SQL statement, as it returns a non-sql datatype (BOOLEAN), but it can be called from another PL/SQL
program, like this:
BEGIN …
IF valid_dept(v_departmentid) THEN -- this was a valid department, so we’ll do this part of the code, e.g. an insert into employees
ELSE -- valid_dept returned a false, so we are not doing the insert
END IF;
… END;

14
USER and SYSDATE can have optional parameters. There are other functions that do not need parameters
such as LOCALTIMESTAMP. Technically, these functions are part of a package SYS.STANDARD, and as such
they are not exactly like the stand-alone functions shown so far.

15
16
Functions accomplish only one task, returning only one value to a variable in the calling program. This
speeds up the process and makes the program more efficient. It can also save on duplication of effort,
rather than including formatting or calculations in many programs, we can code the formatting or
calculations in a function, and repeat calls to the function in multiple places.

17
18
Many programmers choose to not handle the exceptions in functions, but rather to pass them to the calling
environment, typically a procedure.

19
Although it is possible for a function to have OUT or IN OUT parameters, such a function cannot be used
within a SQL statement, and therefore the function has no advantages. It would be better to create a
procedure instead.

What is the difference between a procedure with exactly one OUT parameter and a function?

ANSWER: They both return exactly one value. The main difference (apart from syntax) is that functions can
be called in more flexible ways. In particular, functions can be used inside SQL statements, while
procedures cannot.

20
21
Stored Functions – A named PL/SQL block that can accept optional IN parameters and must return a single
output.

22
23
Release Date: August, 2016
Updates:
2
3
4
5
6
In this example, we used the system-defined UPPER function to insure all the rows we wanted were
returned by a single search. User-defined functions could be used in the same way.

Functions also could be used to eliminate unwanted rows. This is often called filtering the data.

The key point in either event is improving system efficiency and accuracy. In the example in the slide, we
reduce the network traffic (the number of calls from the application to the database) by returning all the
required rows in one SQL statement. If we used a function to filter the data, reducing the number of rows
returned by the SQL statement, this would also reduce network traffic by sending only the rows needed.

7
Without the REVERSE_NAME function, the names would have to be reversed by extra code within the
application, which is less efficient (and may not be possible).

8
Question: Without the user-defined database function how_many_months, how could you code this
SELECT statement?

Answer: SELECT employee_id, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) FROM employees;

If you needed this value in more than one place, it would be easier to create and save a user-defined
function for this calculation that could be called whenever needed.

Functions are used all the time in programming. Functions can be pre-written (called system-defined
functions or system functions) or newly created by the programmer (called user-defined functions). There
are many system functions in modern programming languages. Before creating new functions, check the
list of existing functions in your system so that you will not waste time by writing a function that already
exists.

For more information about system functions in Oracle databases, check out the latest Database SQL
Language Reference (for Database 12c, go to http://docs.oracle.com/database/121/SQLRF/toc.htm).

9
Question: Without the user-defined database function how_many_months, how could you code this
SELECT statement?

Answer: SELECT employee_id, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) FROM employees;

If you needed this value in more than one place, it would be easier to create and save a user-defined
function for this calculation that could be called whenever needed.

Functions are used all the time in programming. Functions can be pre-written (called system-defined
functions or system functions) or newly created by the programmer (called user-defined functions). There
are many system functions in modern programming languages. Before creating new functions, check the
list of existing functions in your system so that you will not waste time by writing a function that already
exists.

For more information about system functions in Oracle databases, check out the latest Database SQL
Language Reference (for Database 12c, go to http://docs.oracle.com/database/121/SQLRF/toc.htm).

10
While this may seem like a trivial function (“Why not just hard-code the * 0.08 in the SELECT statement?”),
this function is quite beneficial. Suppose you use this tax function in a hundred places in ten thousand lines
of code in a huge application, and then the government raises the tax rate to 8.5%. Using this function, you
only have to change one line of code and the whole application is up to speed with the new tax rate.

11
12
13
14
15
There are good reasons for these restrictions. For example, a SQL SELECT statement is not allowed to
modify stored data. Therefore, a function used within a SQL SELECT statement must not modify stored
data, i.e., cannot perform any DML.

16
The last bullet means that you cannot “cheat.” For example, a function used in a SELECT cannot contain
DML statements (first bullet). We could try to “cheat” by coding the DML statement in a separate
procedure, then calling the procedure from the function. This will not work, so do not waste time trying to
do it!

17
This function performs DML on EMPLOYEES, and yet we are trying to use it in a SQL statement which also
performs DML on the same table.

It is better programming practice to use procedures, rather than functions, to perform DML.

18
This function queries the EMPLOYEES table and the UPDATE statement performs DML on the same table.

19
User-Defined Function – A function created by the PL/SQL programmer that can be used anywhere there is
a value or function.

20
21
Release Date: August, 2016
Updates:
2
3
4
5
If you do not have privileges to use an object, you will not see any information about that object, not even
the fact that it exists.

6
7
8
9
Most object attributes are stored in the Dictionary in upper-case. To see all objects whose name begins
with EMP:

SELECT *
FROM user_objects
WHERE object_name LIKE 'EMP%';

10
11
12
13
14
15
16
ALL_* tables – Contain information about objects which you have privileges to use.
Data Dictionary – A catalog of all database objects contained in an Oracle database.
DBA_* tables – Contain information about everything in the database, no matter who owns them.
USER_* tables – Contain information about objects you own.

17
18
Release Date: August, 2016
Updates:
2
3
4
When you develop subprograms that are called from other subprograms, you should be aware of the effects that
handled and unhandled exceptions have on the transaction and the calling program.

When an exception is raised in a called procedure or function, the control immediately goes to the exception section
of that block. An exception is considered handled if the exception section provides a handler for the exception raised.

When an exception occurs and is handled in a called procedure or function, the following code flow takes place:

1. The exception is raised.


2. Control is transferred to the exception handler of the block that raised the exception.
3. The exception code is executed and the block is terminated.
4. Control returns to the calling program.
5. The calling program/block continues to execute.

If a transaction was started (that is, if any data manipulation language [DML] statements executed before executing
the called procedure in which the exception was raised), the transaction is unaffected (i.e., it is not automatically
committed or rolled back). However, if needed, you can explicitly end a transaction by executing a COMMIT or
ROLLBACK operation in the exception section.

5
The ADD_DEPARTMENT procedure creates a new department record by allocating a new department number from
an Oracle sequence, and sets the department_name, manager_id, and location_id column values using the arguments
of the p_name, p_mgr, and p_loc parameters, respectively. The procedure catches all raised exceptions in its own
handler.

The anonymous block makes three separate calls to the ADD_DEPARTMENT procedure.

When the anonymous block is executed, the following output is generated:

Added Dept: Media


Error adding dept: Editing
Added Dept: Advertising

The attempt to add an Editing department with manager_id of 99 is not successful because of a foreign key integrity
constraint violation on the manager_id (manager_id must be a valid employee and there is no employee number 99 in
the EMPLOYEES table). Because the exception was handled in the ADD_DEPARTMENT procedure, the anonymous
block continues to execute. A query on the DEPARTMENTS table shows Media and Advertising were added, but not
Editing.

6
As discussed, when an exception is raised in a called procedure, control immediately goes to the exception
section of that block. If the exception section does not provide a handler for the raised exception, then it is
not handled. The following code flow occurs:

1. The exception is raised.


2. Control is transferred to the exception handler of the block that raised the exception.
3. Since no exception handler exists, the block terminates and any DML operations performed within the
block that raised the exception are rolled back.
4. Control returns to the calling program and the exception propagates to the exception section of the
calling program.
5. If the exception is not handled by the calling program, the calling program terminates and any DML
operations performed prior to the occurrence of the unhandled exception are rolled back.

7
The ADD_DEPARTMENT_NOEX procedure is identical to the ADD_DEPARTMENT procedure (see slide #5),
except ADD_DEPARTMENT_NOEX does not have an exception section.

Running the anonymous block with calls to ADD_DEPARTMENT_NOEX results in the second call to
ADD_DEPARTMENT_NOEX raising an exception that it does not handle. This causes the anonymous block to
terminate without any departments being added to the DEPARTMENTS table.

When the anonymous block is executed:

1. The Media department is successfully inserted (but not committed).


2. The attempt to insert the Editing department raises an unhandled exception and returns control to the
anonymous block, propagating the unhandled exception to the anonymous block.
3. The rest of the executable section of the anonymous block is skipped (so no attempt is made to insert
the Advertising department) as control jumps to the exception section of the anonymous block.
4. Because the anonymous block does not handle the exception, the whole transaction is rolled back,
including the insert of the Media department.

8
The subprogram must be in your own schema or you must have the DROP ANY PROCEDURE system
privilege. If the subprogram you are dropping is called by any other stored subprogram, those subprograms
will have their status changed to invalid and they will not recompile until the "error" is corrected (either the
dropped subprogram is recreated or the call to it is removed).

9
10
To see source code for subprograms owned by others (where you have EXECUTE privilege), use the
following:

SELECT text
FROM ALL_SOURCE
WHERE name = 'TAX'
ORDER BY line;

11
12
ALL_SOURCE – The table that contains source code for subprograms that are owned by others who have
granted you the EXECUTE privilege.
USER_OBJECTS – The table that contains the names and types of procedures and functions.
USER_SOURCE – The table that contains source code for all of the subprograms that you own.

13
14
Release Date: August, 2016
Updates:
2
3
4
To grant an object privilege, you must be the owner of the object, have been granted object privileges with
the GRANT OPTION by the object owner, or have been granted the GRANT ANY OBJECT PRIVILEGE system
privilege. DBA’s can grant privileges on and access any object in the database.

5
6
7
Why do we need REFERENCES privilege? Look at EMPLOYEES and DEPARTMENTS. There is a foreign key
constraint which requires that every (foreign key) DEPARTMENT_ID in EMPLOYEES must also exist (as a
primary key) in DEPARTMENTS. Now a user needs to INSERT a new row into EMPLOYEES. How is the
constraint checked? By reading DEPARTMENTS to check that the required DEPARTMENT_ID exists. But we
may not want to grant SELECT on DEPARTMENTS to the user, because this would allow him/her to SELECT
all data from the table. So we grant REFERENCES on DEPARTMENTS instead.

The REFERENCES privilege allows a user’s session to read data from a table, but ONLY in order to CHECK
foreign key constraints.

8
To invoke a subprogram, a user needs only EXECUTE privilege on the subprogram. He/she MAY NOT need
any privileges on the objects referenced by SQL statements within the subprogram, but that depends on
the code in that stored subprogram, and how security is handled in that program.

Remember:

We can GRANT (or REVOKE) several privileges to/from several users in a single command by using comma-
separated lists, as shown in the first example.

Any privilege granted to PUBLIC is automatically granted to all users.

WITH GRANT OPTION allows the grantee to grant (pass on) the privilege to other users.

Only the UPDATE privilege can reference individual columns.

9
10
11
This can seem strange at first, but there is a good reason for it. If SUSAN needed (and was therefore
GRANTed) INSERT privilege on DEPARTMENTS, she would be able to access the table’s data without using
the ADD_DEPT procedure. The Oracle privilege system means that users can access the data ONLY by
invoking a carefully written and well-tested subprogram.

This means DBAs and programmers must be extra-careful about granting privileges on database objects
that contain or access confidential data.

12
This can seem strange at first, but there is a good reason for it. If SUSAN needed (and was therefore
GRANTed) INSERT privilege on DEPARTMENTS, she would be able to access the table’s data without using
the ADD_DEPT procedure. The Oracle privilege system means that users can access the data ONLY by
invoking a carefully written and well-tested subprogram.

This means DBAs and programmers must be extra-careful about granting privileges on database objects
that contain or access confidential data.

13
Requiring the procedure owner to have the required object privileges is called Definer’s Rights. In the next
lesson, students will learn how to change this by using Invoker’s Rights.

Definer’s Rights is the reason why DBAs are often unwilling to allow application developers to create
subprograms in production databases, because (since the privileges are checked every time the
subprogram is invoked) the developer would need to hold the object privileges for the lifetime of the
subprogram.

14
Requiring the procedure owner to have the required object privileges is called Definer’s Rights. In the next
lesson, students will learn how to change this by using Invoker’s Rights.

Definer’s Rights is the reason why DBAs are often unwilling to allow application developers to create
subprograms in production databases, because (since the privileges are checked every time the
subprogram is invoked) the developer would need to hold the object privileges for the lifetime of the
subprogram.

15
Answer: HANNAH needs SELECT and UPDATE on BILL.STUDENTS. HANNAH also needs SELECT on
BILL.GRADES. JIEP only needs EXECUTE on HANNAH.STUDENT_PROC.

16
CREATE PROCEDURE allows the grantee to create any kind of PL/SQL subprogram, except a trigger, within
their own schema. To create a trigger, you need the CREATE TRIGGER privilege (triggers will be discussed
later in this course).

The careful granting of privileges by DBAs insures a more secure and reliable database.

17
ALTER privilege – Allows the grantee to ALTER the table.
EXECUTE privilege – Allows the user to invoke and execute a PL/SQL subprogram.
INDEX privilege – Allows the grantee to create indexes on the table.
Object privilege – Allows the use of a specific database object, such as a table, a view, or a PL/SQL
procedure, by one or more database users.
REFERENCES privilege – Allows the grantee to check for the existence of rows in a table using foreign key
constraints.

18
19
Release Date: August, 2016
Updates:
2
3
4
5
By default, stored subprograms execute with the privileges of their definer, not their invoker. In default
mode (Definer's Rights), the stored subprograms are bound to the schema in which they reside.

6
The subprogram executes in the user’s database session (Sue), but with the privileges and table names of
the definer (Tom).

Answer: When Sue executes Tom's procedure, the procedure will access Tom's TESTS table. Sue does not
need SELECT privilege on Tom's TESTS table, but she does need EXECUTE privilege on the procedure
TOM.GRADES. This situation allows Sue to access Tom's TESTS table ONLY by executing the procedure
TOM.GRADES.

7
8
Answer: Larry will select from Sveta’s EMPLOYEE table using the synonym created by Curly. Sveta and Curly
will also select from Sveta’s EMPLOYEE table if they run Curly's function GET_EMP.

9
10
The AUTHID clause enables stored subprograms to execute with the privileges of their invoker. Using
Invoker's Rights, subprograms are not bound to a particular schema. They can be run by a variety of users,
and their definer need not know who those users will be.

11
Answer: Sue's execution of Tom's procedure GRADES will access Sue's TESTS table. Since Sue can access her
own tables, she only needs EXECUTE privilege to Tom's procedure GRADES.

12
13
Answer: Bill could change his procedure to access his TESTS table by using "… FROM bill.tests …."

14
Answer: Larry's execution of CURLY.GET_EMP will now access Larry's EMPLOYEES table.

15
Answer: Hakan needs INSERT privileges on Paul's DEPARTMENTS table AND Paul must point the procedure
to Paul's DEPARTMENTS table using a synonym or by changing the procedure's code to say "INSERT INTO
paul.departments…."

16
17
18
19
20
21
22
23
Autonomous Transaction – Subprograms that allow your session to have two or more active transactions at
the same time.
Definer’s Rights – Subprogram executes in the user’s database session, but with the privileges and table
names of the definer.
Invoker’s Rights – subprogram executes in the user’s database session, with the user’s privileges, table
references, and synonyms.

24
25
Release Date: August, 2016
Updates:
2
3
4
5
A package is a schema object that groups logically related subprograms and associated elements.

Packages have a long history in software engineering, offering important features for reliable,
maintainable, reusable code, often in team development efforts for large systems.

Packages let you encapsulate logically related types, items, and subprograms in a named PL/SQL module.
Each package is easy to understand, and the interfaces between packages are simple, clear, and well
defined. This aids application development.

6
The package specification is sometimes referred to as the Package Spec or Package Header.

It is possible to create a package specification with no corresponding package body. This is called a bodiless package,
and contains no executable code. Bodiless packages are outside the scope of this course.

When designing an application, all you need initially is the interface information in the package specifications. You can
code and compile a specification without its body. Then, stored subprograms that reference the package can be
compiled as well. You need not define the package body fully until you are ready to complete the application.

The principle of encapsulation states that, to invoke a subprogram, an application developer needs to know only how
to call it: the name of the subprogram and the variables which must be passed to it. The application developer does
not need to know how the package code works internally.

The specification (spec) is the interface for your applications; it declares the types, variables, constants, exceptions,
cursors, and subprograms available for use. The body fully codes the cursors and subprograms, and so implements the
spec.

The spec holds public declarations, which are visible to your application. You must declare subprograms at the end of
the spec after all other items. The body holds implementation details and private declarations, which are hidden from
your application.

7
It may help to think of a container truck being driven along a road. The truck has two parts: the cab and the
trailer. The cab can be driven without the trailer, but the trailer cannot go anywhere without the cab.

The principle of encapsulation states that, to invoke a subprogram, an application developer needs to know
only how to call it: the name of the subprogram and the variables which must be passed to it. The
application developer does not need to know how the package code works internally.

8
Note the Procedure B in the slide.

It was not declared in the specification and therefore is invisible to (cannot be invoked from) a calling
environment. This is an example of a private procedure, which will be explained in the next lesson.

9
10
11
Constructs declared in a package specification are visible to users granted EXECUTE privilege on the
package.

Private types and variables, and BEGIN initialization statements, will be discussed in later lessons.

12
So the Spec contains a reference to all constructs you want to be public (i.e., accessible from outside the
package). The Body contains all the actual code of the subprograms.

13
14
Although g_max_length_of_service is a constant, we have named it beginning with g_ (not c_) to show that
it is a global (not local) variable.

15
16
As with the Spec, the OR REPLACE option drops and re-creates the package body.

17
Private subprograms may only be called by other subprograms within the package.

18
Create the package specification with the CREATE PACKAGE statement. Create the package body with the
CREATE PACKAGE BODY statement.

19
The slide shows the package body for CHECK_EMP_PKG. The detailed code for CHK_DEPT_MGR has been
omitted to save space on the slide. The CHK_HIREDATE procedure is a validation procedure which checks
that a date passed as an IN argument is not more than 100 years ago.

Notice how this procedure references the constant declared in the package specification in slide #13.

Also point out that the procedure END statements include the procedure-name: END chk_hiredate; We
don’t have to include it, but it makes the code more readable.

20
We need to edit and recompile the specification only if the procedure’s name or parameters are changed.

Keeping the body of a package separate from the specification part of the package often makes life as a
developer easier, so we tend to keep them in two separate files. This is because changes to the Body are
far more frequent than changes to the Spec.

21
22
23
24
Encapsulation – A two-part structure in which the detailed package body code is invisible to the calling
environment, which can only see the specification. If changes to the code are needed, the body can be
edited and recompiled without having to edit or recompile the specification.
OR REPLACE – An option that drops and re-creates the package body.
Package body – This contains the executable code of the subprograms which were declared in the package
specification. It may also contain its own variable declarations.
Package specification – The interface to your applications that declares the constructs (procedures,
functions, variables and so on) which are visible to the calling environment.
PL/SQL packages – Containers that enable you to group together related PL/SQL subprograms, variables,
cursors, and exceptions.

25
26
Release Date: August, 2016
Updates:
2
3
4
Any package component can be either public or private. This includes not only procedures and functions,
but also variables, constants, cursor declarations, and exception declarations.

The package can hide the implementation of a private subprogram so that only the package (not your
application) is affected if the code of that private subprogram is changed. Also, by hiding implementation
details from users, you protect the integrity of the package.

5
Any package component can be either public or private. This includes not only procedures and functions,
but also variables, constants, cursor declarations, and exception declarations.

The package can hide the implementation of a private subprogram so that only the package (not your
application) is affected if the code of that private subprogram is changed. Also, by hiding implementation
details from users, you protect the integrity of the package.

6
7
Remember that a component declared in the specification is (by definition) visible throughout the package.
Therefore it does not make sense to talk about declaring local components within the specification.
Similarly, it does not make sense to talk about global components declared in the package body.

Public code is defined in the package specification and is available to any schema that has EXECUTE
authority on the package. Private code is defined in and visible only from within the package. External
programs using the package cannot see the private code, they can only use it indirectly (if it is called from a
public subprogram they are calling).

8
9
10
11
12
13
– Variable_1 can be used in both procedures A and B within the package body, but not outside the package

– Variable_2 can be used only in procedure A.

14
Why is Procedure A public?
Answer: because it is declared in the specification.

Why is Procedure B local?


Answer: because it is not declared in the specification.

What is the difference between global_var and variable_1?


Answer: they can both be referenced by any procedure in the package, but global_var can be referenced by
the calling environment, while variable_1 cannot.

15
The validation subprogram for checking whether the salary increase is within the 20% limit will be
implemented by a private function declared in the package body.

16
Validate_raise is a private function and can be invoked only from other subprograms in the same package.

Note that the function references the global variable g_max_sal_raise.

17
Validate_raise is a function returning a Boolean which is tested directly in the IF statement.

18
19
ANSWERS:
Invocations #1 and #4 are valid, the others are not.
Invocations #2 is invalid because the procedure-name has not been prefixed with the package-name.
Invocations #3 is invalid because validate_raise is a private function and cannot be referenced from outside
the package.
Invocations #5 is invalid because v_old_salary is a local variable which cannot be referenced from outside
the update_sal procedure.

Regarding the validity of invocation #4, remember that max_sal_raise is a global constant declared in the
specification and is therefore visible from outside the package.

20
The package must be in your own schema or you must have the DROP ANY PROCEDURE system privilege.

21
The source code for PL/SQL packages is also stored in the data dictionary tables, just as for stand-alone
procedures and functions. The source code is viewable in the data dictionary when you execute a SELECT
statement on the USER_SOURCE and ALL_SOURCE tables.

When querying the package, use a condition in which the TYPE column is:

Equal to 'PACKAGE' to display the source code for the package specification
Equal to 'PACKAGE BODY' to display the source code for the package body

Use ORDER BY line to display the lines of source code in the correct sequence.

Note: The values of the NAME and TYPE columns must be uppercase.

22
USER_ERRORS contains the most recent compiler errors for all subprograms in your schema.

23
Whenever we try to compile a subprogram, the PL/SQL compiler automatically logs errors in
USER_ERRORS, as well as the source code in USER_SOURCE.

24
25
26
Keep your packages as general as possible so they can be reused in future applications. Avoid writing
packages that duplicate features provided by the Oracle server. Well written and well constructed packages
can increase the efficiency of the system.

The package specification should reflect the design of your application, so it should be created before
creating the package body. The package specification should contain only those constructs that must be
visible to the users of the package. This prevents other developers from misusing the package by basing
code on irrelevant details.

Changes to the package body do not require recompilation of dependent constructs, whereas changes to
the package specification require recompilation of every stored subprogram that references the package.
To reduce the need for recompiling when code is changed, place as few constructs as possible in a package
specification.

27
Packages provide an alternative to creating procedures and functions as stand-alone schema objects, and they offer
several benefits.

Modularity and ease of maintenance: You encapsulate logically related programming structures in a named module.
Each package is easy to understand, and the interface between packages is simple, clear, and well defined.

Easier application design: All you need initially is the interface information in the package specification. You can code
and compile a specification without its body. Then stored subprograms that reference the package can compile as
well. You need not define the package body fully until you are ready to complete the application.

Hiding information: You decide which constructs are public (visible and accessible) and which are private (hidden and
inaccessible). Declarations in the package specification are visible and accessible to applications. The package body
hides the definition of the private constructs, so that only the package is affected (not your application or any calling
programs) if the definition changes. This enables you to change the implementation without having to recompile the
calling programs. Also, by hiding implementation details from users, you protect the integrity of the package.

Most real-life applications will have literally hundreds of individual subprograms. If they are all implemented as
standalone programs, they will be very hard to manage, document, and maintain. New developers joining your team
will easily be overwhelmed. Packages help you manage the number of stored programs, they make your data
dictionary and code more manageable.

28
Added functionality: Packaged global variables and cursors persist for the duration of a session. Thus, they
can be shared by all subprograms that execute in the environment. They also enable you to maintain data
across transactions without having to store it in the database. Private constructs also persist for the
duration of the session but can be accessed only within the package. More details in Lesson 4.

Better performance: When you call a packaged subprogram the first time, the entire package is loaded into
memory. Thus, later calls to related subprograms in the package require no further disk I/O. Packaged
subprograms also stop cascading dependencies and thus avoid unnecessary compilation. Dependencies are
explained in Section 12.

Overloading: With packages, you can overload procedures and functions, which means you can create
multiple subprograms with the same name in the same package, each taking parameters of different
number or data type. Overloading is explained in the next lesson.

29
Private components – are declared only in the package body and can be referenced only by other (public or
private) constructs within the same package body.
Public components – are declared in the package specification and can be invoked from any calling
environment, provided the user has been granted EXECUTE privilege on the package.
Visibility – Describes if a component can be seen, that is, referenced and used by other components or
objects.

30
31
Release Date: August, 2016
Updates:
2
3
4
5
Overloaded subprograms have the same name, but are differentiated based on their parameters which
must differ in quantity, order, or category of data type. When calling an overloaded subprogram, Oracle
will determine which of the overloaded subprograms to use based on the argument(s) passed when calling
the overloaded subprogram.

6
7
ANSWER: The second one. The call’s first actual parameter is a character string, not a number or a date,
and the second overloaded program is the only one with a character data type category (in this case,
VARCHAR2).

Note: The overloaded programs use basic data types for their arguments for clarity and simplicity. It is
better to specify data types using the %TYPE attribute for variables that correspond to database table
columns.

8
9
10
11
12
13
14
15
A package named STANDARD defines the PL/SQL environment and globally declares types, exceptions, and
subprograms that are available automatically to PL/SQL programs. Most of the built-in functions that are
found in the STANDARD package are overloaded. For example, the UPPER function has two different
declarations, as shown in the slide.

The contents of package STANDARD are directly visible to applications. You do not need to qualify
references to its contents by prefixing the package name.

Why not a third variant to accept and return a CHAR? Because CHAR and VARCHAR2 are in the same
category. Although a CLOB stores character data, it is in a different category (see Section 11 for more
information).

16
Oracle strongly recommends that you do NOT create a function with the same name as one of the built-in
functions.

17
ANSWER: The body will fail to compile because CALC_RATING is referenced (in AWARD_BONUS) before it
has been declared. You have the same problem if AWARD_BONUS is public (meaning it is listed in the
package specification) and CALC_RATING is private.

18
Note: If CALC_RATING is public (meaning it is listed in the package specification), the error does not occur
because the compiler can resolve the reference.

19
20
21
22
Your first thought might be something like this:

CREATE OR REPLACE PACKAGE taxes_pkg IS


g_tax NUMBER := (SELECT rate_value INTO g_tax FROM tax_rates ...);

END taxes_pkg;

Unfortunately, this doesn't work. You can't use SQL in a variable declaration.

23
The unnamed initialization block is terminated by the END keyword for the package body.

Note: If you initialize the variable in the declaration by using an assignment operation, it is overwritten by
the code in the unnamed initialization block at the end of the package body. This would not be a good
programming practice. If a variable is to be initialized by the unnamed initialization block, do not set a
default value when the variable is declared.

24
25
The main purpose of a bodiless package is to create standardized names which can be used everywhere in
your organization.

Remember that all public (global) constructs in a package can be invoked from outside the package. Also
remember that exceptions (like cursors) are a kind of variable.

26
As with any other PL/SQL procedure, function, or package, a user must be granted EXECUTE privilege in
order to use a bodiless package.

27
ANSWER: We could define the exceptions in every subprogram which invokes them. But do you really want
the same exact code in multiple subprograms? What if the exception needs to be changed?

28
29
30
31
This function works fine because it does not break any of the rules on the previous slide.

32
This example breaks the rule that a function called from a query must not execute DML. Imagine that when
the SELECT statement that calls the function SAL is executed, employee 100 has a salary of 10,000. What
value would be returned in the second column (salary) of the query's output? Would it be 10,000, as it was
when the SELECT statement started, or would it be 20,000, the result of running the function SAL? This
ambiguity is the reason this code would result in an error.

33
34
35
36
37
38
39
40
41
Bodiless Package – A package that has a specification but no executable code containing only public
variables.
Forward Declaration – Defines subprograms in logical or alphabetical order, defines mutually recursive
subprograms, and groups and logically organizes subprograms in a package body.
Initialization Block – An un-named block at the end of the package body that automatically executes once
and is used to initialize public and private package variables.
Overloading – Enables you to develop two or more packaged subprograms with the same name.
STANDARD – A package that defines the PL/SQL environment and globally declares types, exceptions, and
subprograms that are available automatically to PL/SQL programs.

42
43
Release Date: August, 2016
Updates:
Remember, when testing the persistent state of package variables, do NOT leave the SQL commands
window. If you leave SQL Commands and go to another Application Express page (for example, Home, SQL
Scripts, or Object Browser), Application Express ENDS your database session. When you return to SQL
Commands, a NEW session will be started and you will NOT see the previous values of the variables.

2
3
4
The collection of public and private package variables represents the package state for the user session.
That is, the package state is the set of values stored in all the package variables at a given point in time. In
general, the package state exists for the life of the user session.

Package variables are initialized (in their declarations, by an initialization block, or by default to NULL) the
first time a package is loaded into memory for a user session. The package variables are, by default, unique
to each session and hold their values until the user session is terminated. In other words, the variables are
stored in the private memory area allocated by the database for each user session.

The package state changes when a package subprogram is invoked and its logic modifies the variable state.
Public package state can be directly modified by operations appropriate to its type.

You need to familiarize yourself with the concept of persistence. A database is all about persistence. If you
insert a row into the database on Monday and commit the insert, that same row will be there on Friday,
still in the database. Then there is session persistence…if you connect to an Oracle database and execute a
program that assigns a value to a package-level variable, that variable is set for the length of your session,
and it retains its value even if the program that performed the assignment has ended.

5
6
7
8
9
10
11
12
13
The first looped call to fetch_n_rows displays the first three rows:
Id :100
Id :101
Id :102
The second time round the loop, the next three rows are fetched and displayed:
Id :103
Id :104
Id :107
And so on.

14
15
Package state – The collection of package variables and their current values for a session

16
17
Release Date: August, 2016
Updates:
2
3
4
5
Packages were created to help the programmer. Packages contain subprograms that everyone uses…so
these subprograms were created and grouped logically (packaged). It is beneficial to first check if Oracle
already has coded what you need before creating new subprograms within a package.

6
These are just a few of the most popular packages supplied by Oracle. Programmers should be familiar with
them and their uses in order to write efficient code.

Most Oracle-supplied PL/SQL packages are owned by the DBA username SYS. To see how many there are:

SELECT COUNT(*) FROM ALL_OBJECTS


WHERE OBJECT_TYPE = 'PACKAGE' AND OWNER = 'SYS';

The list of PL/SQL packages provided with an Oracle database grows with the release of new versions. It
would be impossible to cover the exhaustive set of packages and their functionality in this course. For more
information, refer to the PL/SQL Packages and Types Reference 10g manual (previously known as the
PL/SQL Supplied Packages Reference).

7
Some Oracle development tools, for example SQL*Plus and iSQL*Plus, will display the output only if the
command SET SERVEROUTPUT ON is executed before calling DBMS_OUTPUT. Application Express does not
require this.

8
The main purpose of DBMS_OUTPUT is for debugging, as it gives programmers an easy to use interface to
see, for instance, the current value of a loop counter or if a program makes it into a particular branch of an
IF statement.

9
10
11
12
13
14
If you code a subprogram to include a DBMS_OUTPUT (the first example above), the subprogram will need
to be modified and recompiled to omit the DBMS_OUTPUT in order to run the subprogram as part of a real
application.

15
Using this example above, the subprogram can be used "as is" without modification.

16
The UTL_FILE package is simply a set of PL/SQL procedures that allow you to read, write, and manipulate operating system files.

The UTL_FILE I/O capabilities are similar to standard operating system stream file I/O (OPEN, GET, PUT, CLOSE) capabilities.

The UTL_FILE package can be used only to manipulate text files, NOT binary files. To read binary files (BFILES) the DBMS_LOB
package is used.

The DBA can control access to a directory.

An Oracle DIRECTORY object is created by the DBA. Here is an example:

CREATE DIRECTORY my_dir AS '/temp/my_files';


-- the text files are stored in the O/S directory: /temp/myfiles

GRANT READ, WRITE ON my_dir TO public;


-- allows everyone to read and write these files, GRANT can be used to limit access to specific users.

The DBA can control access to text files by using the UTL_FILE_DIR database parameter, but this is less flexible and is not
recommended.

17
The next slide explains some of these procedures and functions.

18
You open files for reading or writing with the FOPEN function. You then either read, write, or append to the
file until processing is done. You then close the file by using the FCLOSE procedure.

19
The UTL_FILE package declares seven exceptions that indicate an error condition in the operating system
file processing. The UTL_FILE exceptions are:

INVALID_PATH - if the file location or file name was invalid


INVALID_MODE - if the OPEN_MODE parameter in FOPEN was invalid
INVALID_FILEHANDLE - if the file handle was invalid
INVALID_OPERATION - if the file could not be opened or operated on as requested
READ_ERROR - if an operating system error occurred during the read operation
WRITE_ERROR - if an operating system error occurred during the write operation
INTERNAL_ERROR - if an unspecified error occurred in PL/SQL

Note: These exceptions must be prefaced with the package name.

20
UTL_FILE procedures can raise predefined PL/SQL exceptions such as NO_DATA_FOUND or VALUE_ERROR.

The NO_DATA_FOUND exception is raised when reading past the end of a file by using UTL_FILE.GET_LINE
or UTL_FILE.GET_LINES.

21
The parameters include the following:
Location Parameter: specifies the name of a directory alias defined by a CREATE DIRECTORY statement, or
an operating system–specific path specified by using the UTL_FILE_DIR database parameter
Filename Parameter: specifies the name of the file, including the extension, without any path information
Open_mode String: specifies how the file is to be opened. Values are:
'r' for reading text (use GET_LINE)
'w' for writing text (PUT, PUT_LINE, NEW_LINE, PUTF, FFLUSH)
'a' for appending text (PUT, PUT_LINE, NEW_LINE, PUTF, FFLUSH)
The return value from FOPEN is a file handle whose type is UTL_FILE.FILE_TYPE. The handle must be used
on subsequent calls to routines that operate on the opened file.
The IS_OPEN function parameter is the file handle. The IS_OPEN function tests a file handle to see if it
identifies an opened file. It returns a Boolean value of TRUE if the file has been opened; otherwise it
returns a value of FALSE indicating that the file has not been opened.
The code above combines the use of the two subprograms.
Note: For the full syntax, refer to PL/SQL [version] Packages and Types Reference.

22
23
24
What happens in the example above:

-- 1 creates a new empty file and opens it for writing ('w'). For example, if the input parameters are
directory MY_DIR (an alias for /temp/myfiles) and filename salreport.txt, an operating system file
/temp/myfiles/salreport.txt will be created.

-- 2 the PUT_LINE call writes header text 'REPORT: GENERATED ON 29-MAY-15' to the newly opened file
(assuming today's date is 29 May 2015).

-- 3 the NEW_LINE call writes a blank line to the file.

Example continues on the next slide…

25
-- 4 writes a line to the file containing data from the most recently fetched cursor row.

-- 5 writes a footer line to the file.

-- 6 closes the file.

-- 7 an INVALID_FILEHANDLE exception will be raised if the file handle stored in v_file is invalid (for example
if the procedure has mistakenly modified its value).

-- 8 a WRITE_ERROR exception will be raised if the operating system cannot write to the file (for example if
no free space is available on the disk).

26
27
Oracle Academy users do not have access to the UTL_MAIL package.

28
Remember, Oracle Academy users do not have access to the UTL_MAIL package.

29
30
Remember, Oracle Academy users do not have access to the UTL_MAIL package.

31
32
33
34
DBMS_OUTPUT package – A package that sends text messages from any PL/SQL block into a private
memory area, from which the message can be displayed on the screen.

UTL_FILE package – A package that allows PL/SQL programs to read and write operating system text files.

UTL_MAIL package – A package that allows PL/SQL programs to manage components of an e-mail message.

35
36
Release Date: August, 2016
Updates:
2
3
4
SQL statements operate independently. When writing programs you must create a body of code that is
going to vary according to the data and the user input. PL/SQL is an application-development language that
is a superset of SQL, supplementing it with standard programming-language features and PL/SQL allows
you to store compiled code directly in the database.

5
6
7
The embedded SQL statements available in PL/SQL are limited to SELECT, INSERT, UPDATE, DELETE,
COMMIT, and ROLLBACK, all of which are parsed at compile time; that is, they have a fixed structure. You
need to use Dynamic SQL functionality if you require:

the structure of a SQL statement to be altered at execution time


or
access to DDL statements and other SQL functionality in PL/SQL

8
PL/SQL does not allow you to write DDL statements directly in the code, so for example the following
program would fail:

BEGIN
CREATE TABLE dual_dup AS SELECT * FROM DUAL;
END;

So, to handle this shortcoming in the language, Oracle has given us Native Dynamic SQL (NDS). In the old
days, PL/SQL developers were able to use the built-in DBMS_SQL package to execute dynamic SQL and
PL/SQL. For example, at runtime you can construct a query, a DELETE statement, a CREATE TABLE
statement, or even a PL/SQL block as a string--and then execute it. Dynamic SQL comes in extremely handy
when you need to execute DDL inside PL/SQL and just generally when you don't know in advance exactly
what you need to do or what the user will want to do.

In Oracle 8 and earlier releases, the only way to implement Dynamic SQL in a PL/SQL application was by
using the DBMS_SQL package. With Oracle 8i and later releases, the PL/SQL environment provides NDS as
an easier alternative.

9
10
Native Dynamic SQL has been integrated into the PL/SQL language by adding one new statement, EXECUTE
IMMEDIATE. Use EXECUTE IMMEDIATE to execute the specified SQL statement.

11
You can use numeric, character, and date literals as bind arguments, but you cannot use Boolean literals
(TRUE, FALSE, and NULL).

12
13
The two procedures in the slide are functionally identical. Note the first example, using EXECUTE
IMMEDIATE, is much simpler and easier to read.

This and the following examples show Dynamic SQL within standalone procedures and functions, but
Dynamic SQL can be used within packaged subprograms in the same way.

14
15
When this procedure runs with the actual parameters indicated in the example above, the EXECUTE
IMMEDIATE (and the escape single quotes) will result in this INSERT statement:

INSERT INTO employee_names VALUES(250, 'Chang')

The two uses of escape single quotes results in the single quote before and after Chang in the resulting
INSERT statement. A single quote followed immediately by another single quote, is an example of using an
escape character to indicate that the, in the case, single quote, should be treated as a string character
rather than as a syntactical token. The following, third single quote is unrelated to the two previous single
quotes, and it is the syntactical token that ends the string.

16
If you leave out the keyword SPECIFICATION or BODY with the ALTER PACKAGE statement, then the
specification and body are both compiled.

17
18
Before Oracle 8i, the EXECUTE IMMEDIATE statement did not exist in PL/SQL, and the presupplied
DBMS_SQL package was the only way to write Dynamic SQL.

The Native Dynamic SQL implementation will be able to handle about 80-90% of the Dynamic SQL
requirements needed and for the rest you will have to use DBMS_SQL.

The purpose of this and the examples in the next two slides is to show that DBMS_SQL has no advantages
over EXECUTE IMMEDIATE and is much more long-winded and difficult to use. Using EXECUTE IMMEDIATE
is therefore strongly recommended.

19
The calls to DBMS_SQL perform the following actions:

Use DBMS_SQL.OPEN_CURSOR to establish a cursor (area in memory) to process a SQL statement.


Use DBMS_SQL.PARSE to establish the validity of the SQL statement.
Use DBMS_SQL.EXECUTE function to run the SQL statement. This function returns the number of rows
processed.
Use DBMS_SQL.CLOSE_CURSOR to close the cursor.

20
You don't have to understand everything shown here to understand that using EXECUTE IMMEDIATE is
much simpler, and therefore recommended.

21
There are some problems with DBMS_SQL:

It is a very complicated package.


It has a number of restrictions.
It is slow.

So Oracle implemented Dynamic SQL directly in the PL/SQL language itself. The new solution was called
Native Dynamic SQL.

You write dramatically less code using NDS. And since the code you write relies less on built-in packaged
programs and more on native, standard elements of PL/SQL, that code is easier to write, read, and
maintain.

NDS will handle about 80-90% of the Dynamic SQL requirements needed and for the rest you will have to
use DBMS_SQL, even with its problems.

22
Native Dynamic SQL – some programs must build and process a variety of SQL statements at run time. Such
statements can, and probably will, change from execution to execution.
EXECUTE IMMEDIATE – A statement that prepares (parses) and immediately executes a dynamic SQL
statement or an anonymous PL/SQL block.

23
24
Release Date: August, 2016
Updates:
2
3
4
5
6
Only the largest ten or fifteen employers in the world exceed one million employees. Even smaller
companies could have other really large tables, for example, CUSTOMERS and TRANSACTIONS.

7
Only the largest ten or fifteen employers in the world exceed one million employees. Even smaller
companies could have other really large tables, for example, CUSTOMERS and TRANSACTIONS.

8
9
10
11
A deterministic system is a system in which the output can be predicted with 100 percent certainty. When an Oracle
Database encounters a deterministic function, it attempts to use previously calculated results when possible rather
than re-executing the function. Specify DETERMINISTIC for a user-defined function to indicate that the function
returns the same result value whenever it is invoked with the same values for its parameters. This helps the optimizer
avoid redundant function calls: if a stored function was invoked previously with the same arguments the optimizer
can elect to use the previous result. Using the built-in SQL function LOWER as an example, we might have the
following SELECT statement:

SELECT last_name
FROM employees
WHERE LOWER(last_name) = ‘king’

This SELECT statement may return hundreds of employees with the last name of “King" regardless what case was
originally used to enter the employee’s last name into the database. However, for the value “King," the function is
only being referred to once by the optimizer, not hundreds of times for every employee with the last name of “King."

Do not specify DETERMINISTIC for a function whose result depends on the value of session variables or the state of
schema objects, because results might vary across calls.

12
13
14
15
16
17
18
19
20
Oracle uses two engines to process PL/SQL code. All procedural code is handled by the PL/SQL engine while
all SQL is handled by the SQL engine. There is an overhead associated with each context switch between
the two engines. If PL/SQL code loops through a collection performing the same DML operation for each
item in the collection it is possible to reduce context switches by bulk binding the whole collection to the
DML statement in one operation.

21
22
ANSWER: One million rows means one million context switches.

23
24
25
ANSWER: one context switch

26
27
ANSWER: one million context switches

28
29
Since no columns are specified in the INSERT statement, the record structure of the collection must match
the table exactly.

Bulk binds can also improve the performance when loading collections from queries. The BULK COLLECT
INTO construct binds the output of the query to the collection. Populating two collections with 10,000 rows
using a FOR..LOOP takes approximately 0.05 seconds. Using the BULK COLLECT INTO construct reduces this
time to less than 0.01 seconds.

30
31
FORALL statement and SQL%BULK_ROWCOUNT attribute has the same number of elements or subscripts.
So if we are bulk collecting 100 records, FORALL will loop through 1 to 100 and so SQL%BULK_ROWCOUNT
attribute is 100 too. Note the || i || inserted into the DBMS_OUTPUT statement. The %BULK_ROWCOUNT
composite attribute acts like an associative array. The database deposits in the Nth element in this
collection the number of rows processed by the Nth execution of FORALL. If the || i || is not included in
the statement you will not see the row count increment.

32
FORALL statement and SQL%BULK_ROWCOUNT attribute has the same number of elements or subscripts.
So if we are bulk collecting 100 records, FORALL will loop through 1 to 100 and so SQL%BULK_ROWCOUNT
attribute is 100 too. Note the || i || inserted into the DBMS_OUTPUT statement. The %BULK_ROWCOUNT
composite attribute acts like an associative array. The database deposits in the Nth element in this
collection the number of rows processed by the Nth execution of FORALL. If the || i || is not included in
the statement you will not see the row count increment.

33
34
35
36
37
What if the goal is to proceed past any problem rows and continue processing? In order to achieve this, the
SAVE EXCEPTIONS clause of the FORALL statement must be used;

The FORALL statement includes an optional SAVE EXCEPTIONS clause that allows bulk operations to save
exception information and continue processing. Once the operation is complete, the exception information
can be retrieved using the SQL%BULK_EXCEPTIONS attribute. This is a collection of exceptions for the most
recently executed FORALL statement, with the following two fields for each exception:

SQL%BULK_EXCEPTIONS(i).ERROR_INDEX – Holds the iteration (not the subscript) of the original FORALL
statement that raised the exception. In sparsely populated collections, the exception row must be found by
looping through the original collection the correct number of times.

SQL%BULK_EXCEPTIONS(i).ERROR_CODE – Holds the exceptions error code. The total number of


exceptions can be returned using the collections COUNT method, which returns zero if no exceptions were
raised.

38
39
The Oracle RETURNING clause provides the PL/SQL developer with a lot of flexibility. The RETURNING
clause to INSERTs, UPDATEs, and DELETEs helps to retrieve data from a row or rows affected by the DML
statement. If the DML operation is affecting only one row then static SQL can be used. Using PL/SQL, the
RETURNING Clause can also be used in BULK DML to return values to a collection/array for later evaluation.
The RETURNING clause eliminates inefficient network round trips and server memory usage.

40
41
42
Bulk Binding – Fetches all the rows in a single call to the SQL Engine.
BULK COLLECT Clause – provides bulk processing for SELECT and FETCH statements
DETERMINISTIC Clause – Means that the same input value will always produce the same output value and
must be used to create a function-based index on your own functions.
FORALL – provides bulk processing for DML activity
NOCOPY hint – Passes arguments by reference rather than by value, and usually speeds up the execution of
SQL statements.
RETURNING Clause – allows the retrieval of data modified by a DML statement without triggering a
separate context switch

43
44
Release Date: August, 2016
Updates:
This lesson includes several examples of CREATE TRIGGER syntax. For this lesson, try not to focus on the
details of the syntax, as that will be covered in the following lessons.

2
3
4
5
6
As we continue to develop our knowledge of triggers, you will see that even more information can be
stored in the logging table. For instance, in addition to the USER_ID of the person who updated the salary
column and the date the salary column was updated, you might also store the employee id whose salary
was changed, as well as their old salary.

7
Triggers allow specified actions to be performed automatically in the database without having to write any
extra front-end application code. Triggers can greatly increase the functionality of the database and
therefore the functionality of your applications.

The key difference between procedures/functions and triggers is that procedures/functions have to be
invoked explicitly in order to execute them, while triggers are event-driven; we do not (and cannot) invoke
them explicitly. Also, since triggers are never explicitly invoked, they cannot receive parameters.

Triggers are blocks of code that are always "listening" for something to happen in the database. We
CANNOT write a PL/SQL block such as:

BEGIN
log_sal_change_trigg;
END;

8
A database trigger is executed automatically whenever the triggering event happens. A database triggering
event can be a data event such as an INSERT, DELETE, or UPDATE command, or it could be a database event
such as AFTER LOGON ON DATABASE.

Application triggers may already be familiar to you. For example, when you order a book through a website
such as www.amazon.com, you enter all the required details and click on a "SUBMIT" button to submit your
order. Clicking the "SUBMIT" button is a triggering event that results in your order being submitted for
processing and delivery. The website application was "listening" for the click on the "SUBMIT" button.

9
Triggering events modify the state of the database in some way. You cannot associate a trigger with a
SELECT statement or an explicit cursor FETCH statement.

Triggers can be either row-level or statement-level. A row-level trigger fires once for each row affected by
the triggering statement and a statement-level trigger fires once for the whole statement.

10
Do not use triggers to do things that can more easily be done in another way. For example, do not create a
trigger to enforce referential integrity; use a foreign key constraint instead.

11
“Derived column values” means that whenever certain data values are updated by the application code, we
want to automatically update another (related) data value.

“Synchronous table replication” means that for some reason we need to duplicate a data item in two
separate tables (although this is not compliant with third normal form, it is sometimes needed for
performance or security reasons). The application code would update the first table, while a suitable trigger
would automatically and immediately (i.e., synchronously) apply the same update to the second table.

12
Note that you cannot demonstrate the trigger in the slide without DBA privileges.

13
The trigger code in this example is more complicated, but don't worry about the syntax at this point (it will
be covered in the following lessons). The key here is this business rule cannot be enforced using a check
constraint because you cannot code subqueries in a constraint definition (see the code below). To enforce
this business rule requires a trigger to be used.

You cannot code subqueries in a constraint definition. The code below is NOT allowed.

ALTER TABLE employees ADD CONSTRAINT check_job_ck


CHECK (job_id NOT IN
(SELECT job_id FROM job_history WHERE employee_id ….));

14
Oracle automatically executes a trigger when a specified event occurs. Too many triggers can slow down
the processes, so don’t create more triggers than you really need. Consider the effect of triggers on other
triggers. If you accidentally create a recursive trigger (i.e., a trigger that ends up calling itself), Oracle will
give you an error when you try to compile that trigger.

Trigger code can execute less efficiently than stored procedure code. Therefore, instead of writing 100 lines
of PL/SQL code within a trigger, write the code in a separate procedure and invoke the procedure from the
trigger.

15
Here are the differences between triggers and procedures. Procedures and triggers are implemented in
Oracle to achieve different things, so use them for their intended purposes. The biggest and most
important difference is in how the code is executed: explicitly by you the programmer or implicitly by the
database.

Triggers are similar to stored procedures. A trigger stored in the database can declare its own local
variables, can include SQL and PL/SQL statements, and can invoke stored procedures. However, procedures
and triggers differ in the way they are invoked. A procedure is explicitly invoked by a call from an
application. Triggers are implicitly fired by the database when a triggering event occurs, no matter which
user is connected or which application is being used.

16
Application triggers – Execute automatically whenever a particular event occurs within an application.
Database triggers – Execute automatically whenever a data event (such as DML or DDL) or system event
(such as logon or shutdown) occurs on a schema or database.
Triggers – Programs to execute a specific action whenever a specific event occurs in an application or in the
database.

17
18
Release Date: August, 2016
Updates:
2
3
4
In this lesson, you learn about statement triggers. The next lesson will cover row triggers.

NOTE: You cannot explicitly create a trigger on a MERGE DML statement. However, since a MERGE is really
a mixture of INSERTs and UPDATEs, creating INSERT and/or UPDATE triggers will produce the same effect.

5
6
7
BEFORE triggers are often used to decide whether the triggering DML statement should be allowed to
complete.

AFTER triggers are frequently used to generate audit records and log records.

INSTEAD OF triggers are designed to be used with complex views, not directly with tables.

If a trigger throws an unhandled error, the trigger, plus its triggering SQL statement would be rolled back.
This would happen regardless of whether a BEFORE or AFTER trigger is used.

8
9
In the first example, the trigger will fire if the SALARY or COMMISSION_PCT (or both) columns are updated,
but not if other columns of EMPLOYEES are updated.

In the second example, the trigger will fire after any kind of DML statement is executed on EMPLOYEES. We
could create three separate triggers (one for INSERT, one for UPDATE, one for DELETE), but a single trigger
is neater.

10
11
ANSWER: In every case, the trigger fires exactly once. A statement trigger fires only once even if the
triggering DML statement affects many rows.

12
13
14
Why is the trigger created as an AFTER trigger, not a BEFORE trigger?

ANSWER: Because we want to log the INSERT only if it is successful. The INSERT into EMPLOYEES could fail
(for example because of a constraint violation), but a BEFORE trigger would already have logged the İNSERT
by that time.

NOTE: This is a statement trigger, not a row trigger, and will therefore insert only one row into the logging
table EVEN IF many employees are inserted, for example by INSERT….AS SELECT. In real life, a row trigger
would be better here. Row triggers will be discussed in the next lesson.

15
16
A DML trigger used to enforce business rules and prevent unauthorized operations is sometimes called a
Check Trigger.

17
Remember the RAISE_APPLICATION_ERROR is a server-side, built-in procedure that returns an unhandled
exception to the user and causes the PL/SQL block (in this case, the trigger) to fail.

When a database trigger fails, the triggering statement is automatically rolled back by the Oracle server. In
other words, the employee is not inserted.

18
Why is this a BEFORE trigger?

ANSWER: If it were an AFTER trigger, then by the time the trigger raised the error, it would be too late—the
employee would already have been inserted.

19
You can demonstrate this concept by modifying the IF statement in the trigger to correspond with the current time.
For example if you want to demonstrate this at 3:00 pm (15 on a 24 hour clock), recreate the trigger as:

CREATE OR REPLACE TRIGGER secure_emp


BEFORE INSERT ON employees
BEGIN
IF TO_CHAR(SYSDATE,‘HH24') BETWEEN 14 AND 16 THEN
RAISE_APPLICATION_ERROR(-20500,
'You may insert into EMPLOYEES table only during business hours');
END IF;
END;

Before doing this, remember that SYSDATE returns the database time, and the database may be in a different time
zone from you. Check the database time by:

SELECT TO_CHAR(SYSDATE, 'HH24:MI:SS') FROM DUAL;

20
NOTE: Transaction control statements (COMMIT, ROLLBACK, SAVEPOINT) are not allowed in a trigger body.

21
DML trigger – A trigger which is automatically fired (executed) whenever a SQL DML statement (INSERT,
UPDATE or DELETE) is executed.
Row trigger – fires once for each row affected by the triggering event.
Statement trigger – is fired once on behalf of the triggering event, regardless of how many rows, or if any,
are affected by the event.

22
23
Release Date: August, 2016
Updates:
2
3
4
5
The trigger keywords DELETING, INSERTING, and UPDATING are automatically declared Boolean variables
which are set to TRUE or FALSE by the Oracle server depending on which type of DML statement is being
executed.

6
7
This trigger will allow other columns of EMPLOYEES to be updated at any time.

8
9
10
11
12
13
14
ANSWER: It does not matter because the employee_id has not changed, the old and new values are the
same.

Using :OLD or :NEW would matter if the trigger is on an INSERT. In this case, :OLD.employee_id would be
NULL.

15
This trigger is similar to real world triggers in that every time any DML operation is performed on the
EMPLOYEES table, a row is automatically inserted into the AUDIT_EMP table. The AUDIT_EMP table will
include a row for each row changed in the EMPLOYEES table. The row in the AUDIT_EMP table will contain
the username of the person who made the change, the date the change was made, the employee_id
whose row was changed, and the pre-and post-update values of that employee’s last_name, job_id, and
salary.

16
QUESTION: When a row is INSERTED into EMPLOYEES, what are the values of :OLD.employee_id,
:OLD.last_name, etc.?
ANSWER: The values are NULL, because the row did not exist before the INSERT.

Similarly, when a row is DELETEd, the :NEW.column_name values are NULL.

17
Remember that when a BEFORE trigger executes RAISE_APPLICATION_ERROR, the triggering statement (in
this case, INSERT INTO employees or UPDATE EMPLOYEES) is not executed.

QUESTION: Since the job_id is not being updated, does it matter whether we test :NEW.job_id or
:OLD.job_id?

ANSWER: Yes, because the DML statement could be an INSERT, in which case the :OLD value would be
NULL.

18
King’s salary update (although allowed by the trigger) will be rolled back, because every SQL statement
must either complete 100% successfully or not at all. This rule is called “statement-level consistency” and is
a basic rule of the Oracle database (nothing to do with triggers).

The error message does not show which row(s) violated the check and were therefore not updated. But we
could easily show this by modifying the trigger code to:

… RAISE_APPLICATION_ERROR (-20202, 'Employee ' || :NEW.employee_id || ' cannot earn more than
$15,000.');

19
20
The trigger executes a SELECT on the required department row. If the department does not exist,
NO_DATA_FOUND is raised. The NO_DATA_FOUND exception handler INSERTS the required department
row.

"Check Triggers” MUST be a BEFORE trigger.

21
OLD (and/or NEW) would be very badly-chosen table names, but the point is they are possible names. In
real applications, the database table names are often determined by someone else (usually the DBA), and
cannot be changed later (without significant effort).

22
This code will still work because technically there is no ambiguity. The value qualifiers :OLD and :NEW are
prefixed with a colon (:) while the table name is not. But the code is certainly confusing to read.

23
Notice that in the REFERENCING clause, the value qualifiers must not be prefixed with a colon:
REFERENCING OLD AS former, not REFERENCING :OLD AS :former.
You can declare just one correlation name if you want. For example, the code in the slide could be written
as:
CREATE OR REPLACE TRIGGER log_emps
AFTER UPDATE OF salary ON old REFERENCING OLD AS former FOR EACH ROW
BEGIN
INSERT INTO log_emp_table
(who, when, which_employee, old_salary, new_salary)
VALUES (USER, SYSDATE, :former.employee_id,
:former.salary, :NEW.salary);
END;
But it is better (because it is clearer) to declare both correlation names.
The REFERENCING clause can be used only with row triggers because :OLD and :NEW can be used only with
row triggers.

24
A complex IF statement could be difficult to read. The WHEN clause can help make this logic easier to read,
and as a result, easier to maintain.

25
The WHEN clause condition must be enclosed in parentheses (), but can be as complex as needed. For
example:

WHEN (condition_1 AND NOT (condition_2 OR condition_3))

Correlation names (OLD and NEW) in a WHEN clause are not prefixed with a colon (just like in a
REFERENCING clause).

The WHEN clause can be used to test any conditions, but is normally used only to test OLD and NEW
column values. This is why it can be used only with row triggers. The WHEN condition(s) are evaluated FOR
EACH ROW, so a multiple-row UPDATE may execute the trigger body for some rows, but not for others.

26
Underlying tables cannot be updated through a Complex View.

We can overcome this by creating an INSTEAD OF trigger which will update the underlying tables directly
instead of trying to update through the view.

INSTEAD OF triggers are very simple. You write code that the Oracle server will execute when a program
performs a DML operation on a view. An INSTEAD OF trigger takes the place of, rather than supplements,
Oracle's usual DML behavior.

27
28
This example creates and uses two new tables, NEW_EMPS and NEW_DEPTS, with different columns from
the EMPLOYEES and DEPARTMENTS tables.

Instead of trying to insert a row into the Complex View, the following actions take place:

• The INSTEAD OF trigger fires.


• A row is inserted into the NEW_EMPS table.
• The DEPT_SAL column of the NEW_DEPTS table is updated.
• The salary value supplied for the new employee is added to the existing total salary of the department to
which the new employee has been assigned.

Note: The code for this scenario is shown in the next two slides.

29
INSTEAD OF triggers can be associated only with views, and the BEFORE and AFTER timing options are not
valid, since the triggering DML statement is not executed at all.

30
INSTEAD OF triggers are always row triggers, even if the clause FOR EACH ROW is omitted, as in this slide.
You can have fun with INSTEAD OF triggers. Try the following:
CREATE TABLE test_emps AS SELECT * FROM employees;
UPDATE test_emps SET salary = salary * 1.1;
The salary values are updated, but now try this:
RENAME test_emps TO newname_emps:
CREATE VIEW test_emps AS SELECT * FROM newname_emps;
-- in effect we have just converted TEST_EMPS from a table to a view.
CREATE TRIGGER do_nothing
INSTEAD OF UPDATE ON test_emps
BEGIN
NULL;
END;
Now execute the UPDATE statement again:
UPDATE test_emps SET salary = salary * 1.1;
What happens? Nothing! It’s as if the UPDATE statement did not exist.

31
32
33
34
35
36
37
38
39
40
This example is the same as the one on the previous slide, except here all of the code is included. When this
trigger executes, a row will be added to the log table that includes the EMPLOYEE_ID, the date the change
was made, and the new salary for each row updated in the EMPLOYEES table.

41
Conditional Predicate – predefined Boolean variables INSERTING, DELETING and UPDATING which can be
tested in a trigger body to take different code paths depending on which DML statement caused the trigger
to fire.

Compound Trigger - A single trigger that can include actions for each of the four possible timing points:
before the triggering statement, before each row, after each row, and after the triggering statement.

DML Row Trigger – a DML trigger which fires once for each row affected by the triggering DML statement.

INSTEAD OF trigger – A trigger which replaces a DML statement on a complex view with DML statements
on the tables on which the view is based.

:OLD and :NEW qualifiers – enables a row trigger to access column values in the table row currently being
modified by the triggering statement.

42
43
Release Date: August, 2016
Updates:
2
3
4
5
timing: BEFORE or AFTER (another timing option called INSTEAD OF is used when certain DML actions are
required on a database view)

NOTE: the timing INSTEAD OF cannot be used with DDL or Database Event triggers.

ddl_event: CREATE or ALTER or DROP

Only the DBA can create DDL triggers on other users’ schemas (either by ON DATABASE or by ON schema-
name.SCHEMA)

To create a trigger in your own schema on a table in your own schema, you must have the CREATE TRIGGER
system privilege.

To create a trigger in any schema on a table in any schema, you must have the CREATE ANY TRIGGER
system privilege.

6
DDL triggers can specify only ON SCHEMA or ON DATABASE. We cannot say (for example) AFTER CREATE
ON TABLE.

Also, these are not like DML row triggers. We cannot use qualifiers such as :OLD and :NEW. Unfortunately,
while we might want the log table to record which object was created, using something like the following
will NOT work:

INSERT INTO log_table VALUES (USER, SYSDATE, :NEW.object_type, :NEW.object_name);

7
This trigger will not function properly in the Application Express development environment.

It is possible to prevent a specific table from being dropped by: ALTER table-name DISABLE TABLE LOCK;
This prevents any exclusive locks being obtained on the table. Unfortunately this command also prevents
several ALTER statements (which also require an exclusive lock) on the table!

NOTE: This trigger will prevent dropping any schema objects, even the trigger itself. Dropping the trigger
involves two steps:

1. ALTER TRIGGER prevent_drop_trigg DISABLE;


2. DROP TRIGGER prevent_drop_trigg;

8
Remember, you cannot use INSTEAD OF with Database Event triggers.

You can define triggers to respond to such system events as LOGON, SHUTDOWN, and even SERVERERROR.

To create a trigger ON DATABASE, you must have the ADMINISTER DATABASE TRIGGER system privilege.
Typically, only the DBA can use ON DATABASE or ON other-username.SCHEMA.

If the trigger issues SQL statements or calls procedures or functions, then the owner of the trigger must
have the privileges necessary to perform these operations. These privileges must be granted directly to the
owner rather than acquired through roles.

Database Event triggers can be created ON DATABASE or ON SCHEMA, except that ON SCHEMA cannot be
used with SHUTDOWN and STARTUP events.

9
You can create these triggers to monitor how often you log on and off, or you may want to write a report
that monitors the length of time for which you are logged on. When you specify ON SCHEMA, the trigger
fires for the specific user. If the DBA specifies ON DATABASE, the trigger fires for all users.

The LOGOFF trigger will not fire if the user’s session disconnects abnomally.

10
If the IS_SERVERERROR … conditional test is omitted, the trigger will fire when any Oracle server error
occurs.

11
Trigger syntax also supports a CALL to a procedure as the trigger body. It can also be used to call programs
written in C or JAVA.

12
Sometimes you may find that Oracle reports a mutating table error when your trigger executes. This happens when
the trigger is modifying a mutating table. To avoid mutating table errors:
A row-level trigger must not query or modify a mutating table.
A statement-level trigger must not query or modify a mutating table if the trigger is fired as the result of a CASCADE
delete.
Reading and writing data using triggers is subject to certain rules. The restrictions apply only to row triggers, unless a
statement trigger is fired as a result of ON DELETE CASCADE.
Mutating table example:
CREATE OR REPLACE TRIGGER emp_trigg
AFTER INSERT OR UPDATE OR DELETE ON employees -- EMPLOYEES is the mutating table
FOR EACH ROW
BEGIN
SELECT … FROM employees … -- is not allowed
SELECT … FROM departments … -- is allowed

END;

13
The CHECK_SALARY trigger in the example attempts to guarantee that whenever a new employee is added
to the EMPLOYEES table or whenever an existing employee’s salary or job ID is changed, the employee’s
salary falls within the established salary range for the employee’s job.

When an employee record is updated, the CHECK_SALARY trigger is fired for each row that is updated. The
trigger code queries the same table that is being updated. Therefore, it is said that the EMPLOYEES table is
a mutating table.

A trigger (such as check_salary in the slide) which violates the mutating table restriction can still be
CREATEd, i.e. it will compile successfully. But an exception will be raised when the triggering DML
statement is executed, as shown in the next slide.

14
Possible solutions to this mutating table problem include the following:

Store the summary data (the minimum salaries and the maximum salaries) in another summary table,
which is kept up-to-date with other DML triggers.

Store the summary data in a PL/SQL package, and access the data from the package. This can be done in a
BEFORE statement trigger.

Implement the rules in the application code instead of in the database.

15
16
The trigger code shown in the slide prevents anyone (not only SCOTT) from updating salaries on Saturday
or Sunday. If you wanted this restriction to apply only to SCOTT, you could code:

CREATE OR REPLACE TRIGGER weekdays_emp


BEFORE UPDATE ON employees
BEGIN
IF USER = 'SCOTT'
AND (TO_CHAR (SYSDATE, 'DY') IN ('SAT','SUN')) THEN
RAISE_APPLICATION_ERROR(-20506,'You may only
change data during normal business hours.');
END IF;
END;

17
18
Taking this example further, what if the minimum salary changes from time to time? Next year it may be $550, not $500. We don't want to drop
and recreate the constraint every time.
We would create a single-row, single-column table which stores the minimum salary:
CREATE TABLE minsal (min_salary NUMBER(8,2));
INSERT INTO minsal (min_salary) VALUES (500);
And later, if the minimum salary changes to $550, we simply:
UPDATE minsal SET min_salary = 550;
Our trigger would be coded:
CREATE OR REPLACE TRIGGER check_salary
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
DECLARE
v_min_sal minsal%min_salary%TYPE;
BEGIN
SELECT min_salary INTO v_min_sal
FROM minsal;
IF :NEW.salary < v_min_sal
OR :NEW.salary < :OLD.salary THEN
RAISE_APPLICATION_ERROR (-20508,
'Do not decrease salary.');
END IF;
END;

19
Real-life tables in large organizations can have billions of rows. A mobile phone company needs to store
data about every phone call and every text message sent using its network. With millions of phone users, it
would be billions of rows.

20
21
The departments.total_salary column is an example of derived data. Although it violates the data modeling
rules of normalization, sometimes this has to be done to improve performance.

22
The slide shows a procedure and a trigger which invokes the procedure three times. This avoids having to
code three separate UPDATE DEPARTMENTS ... statements within the trigger body.

23
CALL statement – enables you to call a stored procedure, rather than code the PL/SQL body in the trigger
itself.
Database Event triggers – are fired by non-SQL events in the database.
DDL Triggers – are fired by DDL statements: CREATE, ALTER or DROP.
Mutating table – A table that is currently being modified by an UPDATE, DELETE, or INSERT statement, or a
table that might need to be updated by the effects of a declarative DELETE CASCADE referential integrity
action.

24
25
Release Date: August, 2016
Updates:
2
3
4
5
6
Monica does not need UPDATE privilege on TOM.EMPLOYEES, only the ALTER privilege. The user who fires
the trigger by executing code that contains "UPDATE tom.employees SET…" will need the UPDATE privilege,
but Monica does not.

7
USER_ERRORS contains the details of any compilation errors that occurred while a trigger was compiling.
The contents of these views are similar to those for subprograms.

8
If the trigger source file is unavailable, you can recreate it from the TRIGGER_BODY column in
USER_TRIGGERS. You can also examine the ALL_TRIGGERS view, which contains the additional column
OWNER, for the owner of the trigger.

Run the following code to see what information is available to you regarding triggers.

SELECT * FROM USER_TRIGGERS

SELECT * FROM ALL_TRIGGERS

DESC USER_TRIGGERS

9
Unlike USER_SOURCE, which contains one row for each line of subprogram code, USER_TRIGGERS contains
only one row per trigger.

No data is returned by this SELECT statement until a RESTRICT_SALARY trigger is created.

10
When a trigger is first created, it is enabled by default.

Why would we disable a trigger? Answer:

1. To improve performance when loading very large amounts of data into the database. For example,
imagine a trigger defined as …AFTER INSERT ON bigtable FOR EACH ROW…. Now someone (maybe the
DBA) inserts 10 million rows into BIGTABLE. This row trigger will fire 10 million times, slowing down the
data load considerably.

2. We may disable a trigger when it references a database object that is currently unavailable due to a
failed network connection, disk crash, offline data file, or offline table space.

If you need a trigger turned off temporarily, don't drop it and then recreate it, just disable it for a little
while by using the ALTER TRIGGER statement. Don't forget to re-enable it to return to normal processing—
the trigger was there for a reason.

11
When a table is dropped, other object types (procedures, functions, complex views, etc.) which reference
the table are NOT dropped. So why are triggers?

Answer: Unlike the other object types, a trigger can be associated with only one table, so if that table is
dropped, the trigger is no longer needed.

12
ALL_TRIGGERS – detailed code and status of all triggers on tables accessible to the current user.
USER_TRIGGERS – detailed code and status of triggers owned by the current user.

13
14
Release Date: August, 2016
Updates:
2
3
4
5
A procedure or function can directly or indirectly (through an intermediate view, procedure, function, or
packaged procedure or function) reference the following objects:

– Tables
– Views
– Sequences
– Procedures
– Functions
– Packaged procedures or functions

6
7
Some object types (sometimes the same object) can be both dependent and referenced.

8
Local vs. Remote Dependencies

If the referenced object is in a different database, the dependency is called a remote dependency. Because
the two databases have separate data dictionaries, some of the features described in this lesson work
differently for remote dependencies.

9
Assume that the structure of the table on which a view is based is modified. When you describe the view by
using the DESCRIBE command, you get an error message that states that the object is invalid to describe.
This is because DESCRIBE is not a SQL command and, at this stage, the view is invalid because the structure
of its base table is changed. If you query the view now, the view is recompiled automatically and you can
see the result (if it is successfully recompiled).

Although this example discusses automatic recompilation of a view, the same mechanisms apply to other
dependent objects such as subprograms.

Oracle will also handle remote dependencies, which is what we call dependencies that span different
databases. So a procedure stored in one database located in Paris, France, could be selecting from a table
stored in a database located in Copenhagen, Denmark. If the table is changed in the Danish system, this
does not ripple straight through to the procedure in the French system, but will be picked up the next time
the procedure is executed. Oracle normally handles this type of dependency by comparing the timestamps
on the last compilation of the tables and procedures on the different databases. If the compile dates and
times are the same, the status of the procedure is left at VALID, and if they differ, the status is changed to
INVALID, and an automatic recompile is attempted by Oracle.

10
11
The QUERY_EMP procedure directly references the EMPLOYEES table. The ADD_EMP procedure updates
the EMPLOYEES table indirectly by using the EMP_VW simple view.

In each of the following cases, will the ADD_EMP procedure be invalidated, and will it successfully
recompile when next invoked?

1. The internal logic of the QUERY_EMP procedure is modified.


2. A new column is added to the EMPLOYEES table.
3. The EMP_VW view is dropped.

Answers:
1. ADD_EMP will NOT be invalidated because it is not directly or indirectly dependent on QUERY_EMP.
2. ADD_EMP will be invalidated because it is indirectly dependent on EMPLOYEES. When ADD_EMP is next
invoked, it will recompile successfully (and so will EMP_VW).
3. ADD_EMP will be invalidated because it is directly dependent on EMP_VW. When next invoked, it will
not recompile successfully because its referenced object (EMP_VW) no longer exists.

12
Determine which database objects to recompile manually by displaying direct dependencies from the
USER_DEPENDENCIES data dictionary view.

Examine the ALL_DEPENDENCIES view, which contains the additional column OWNER, which references the
owner of the object.

Note: the *_DEPENDENCIES views do not show indirect dependencies. For these we need to run the
utldtreel.sql script as shown in the next slide.

13
Display direct and indirect dependencies from additional user views called DEPTREE and IDEPTREE.

See the APEX_Student_Guide in Section 0 if you need assistance with running the utldtree.sql script.

14
The depttree_fill procedure has 3 parameters; the object type, schema name of the object owner, and
object name.
Example:
1. You can verify that the utldtree.sql script ran if you DESCRIBE its structure:
DESCRIBE deptree_temptab
2. Populate the DEPTREE_TEMPTAB table with information for a particular referenced object by invoking
the DEPTREE_FILL procedure (shown in the slide above). There are three parameters for this procedure:
object_type: Type of the referenced object
object_owner: Schema of the referenced object
object_name: Name of the referenced object

15
Display a tabular representation of all dependent objects by querying the DEPTREE view.

Display an indented representation of the same information by querying the IDEPTREE view, which consists
of a single column named DEPENDENCIES.

For example:

SELECT * FROM ideptree;

provides a single column of indented output of the dependencies in a hierarchical structure.

16
Predict the effect that a change in the definition of a procedure has on the recompilation of a dependent
procedure.

Suppose that the RAISE_SAL procedure updates the EMPLOYEES table directly, and that the REDUCE_SAL
procedure updates the EMPLOYEES table indirectly by way of RAISE_SAL.

In each of the following cases, will the REDUCE_SAL procedure successfully recompile?

1. The internal logic of the RAISE_SAL procedure is modified.


2. One of the formal parameters to the RAISE_SAL procedure is eliminated.

Answers:
1. REDUCE_SAL will successfully recompile because its actual parameters have not changed, therefore its
invocation from REDUCE_SAL is still valid.
2. REDUCE_SAL will not successfully recompile because one of its actual parameters in its call to RAISE_SAL
no longer exists.

17
Be aware of the subtle case in which the creation of a table, view, or synonym may unexpectedly invalidate
a dependent object because it interferes with the Oracle server hierarchy for resolving name references.
Predict the effect that the name of a new object has upon a dependent procedure.
Suppose that your QUERY_EMP procedure originally referenced a public synonym called EMPLOYEES.
However, you have just created a new table called EMPLOYEES within your own schema.
Questions:
Does this change invalidate the procedure?
Answer: Yes
Which of the two EMPLOYEES objects does QUERY_EMP reference when the procedure recompiles?
Answer: your own EMPLOYEES table.
Now suppose that you drop your private EMPLOYEES table. Does this invalidate the procedure?
Answer: Yes.
Now what happens when the procedure recompiles?
Answer: It will recompile successfully and reference the public synonym.
You can track security dependencies in the USER_TAB_PRIVS data dictionary view.

18
If the recompilation is successful, the object becomes valid. If not, the Oracle server returns an error and
the object remains invalid. When you recompile a PL/SQL object, the Oracle server first recompiles any
invalid object on which it depends.
Procedure: Any local objects that depend on a procedure (such as procedures that call the recompiled
procedure or package bodies that define the procedures that call the recompiled procedure) are also
invalidated, even if they were previously valid. This is because the recompiled procedure could have been
edited before recompilation.
Packages: The COMPILE PACKAGE option recompiles both the package specification and the body,
regardless of whether it is invalid. The COMPILE SPECIFICATION option recompiles the package
specification. Recompiling a package specification invalidates any local objects that depend on the
specification, such as subprograms that use the package. Note that the body of a package also depends on
its specification. The COMPILE BODY option recompiles only the package body, and does not invalidate
objects dependent on the specification.
Triggers: Explicit recompilation eliminates the need for implicit run-time recompilation and prevents
associated run-time compilation errors and performance overhead.
The DEBUG option instructs the PL/SQL compiler to generate and store the code for use by the PL/SQL
debugger.

19
Sometimes a recompilation of dependent procedures is unsuccessful (for example, when a referenced
table is dropped or renamed).

The success of any recompilation is based on the exact dependency. If a referenced view is re-created, any
object that is dependent on the view needs to be recompiled. The success of the recompilation depends on
the columns that the view now contains, as well as the columns that the dependent objects require for
their execution. If the required columns are not part of the new view, then the object remains invalid.

20
The recompilation of dependent objects is successful if:

New columns are added to a referenced table


All INSERT statements include a column list
No new column is defined as NOT NULL

When a private table is referenced by a dependent procedure and the private table is dropped, the status
of the dependent procedure becomes invalid. When the procedure is recompiled (either explicitly or
implicitly) and a public table exists, the procedure can recompile successfully but is now dependent on the
public table. The recompilation is successful only if the public table contains the columns that the
procedure requires; otherwise, the status of the procedure remains invalid.

21
22
You can simplify dependency management and avoid unnecessary invalidations with packages when
referencing a package procedure or function from a stand-alone procedure or function.

– If the package body changes and the package specification does not change, then the stand-alone procedure that
references a package construct remains valid.
– If the package specification changes, then the outside procedure referencing a package construct is invalidated, as is the
package body.

23
If a stand-alone procedure that is referenced within the package changes, then the entire package body is
invalidated, but the package specification remains valid. Therefore, it is recommended that you bring the
procedure into the package.

24
25
Release Date: August, 2016
Updates:
2
You CANNOT create a remote dependency in the Academy Application Express environment because there
is only one database. In real life, you (or the DBA) would first create a database link, which is a pointer to a
remote database, and then reference the database link within a local procedure.

3
4
When the referenced and dependent objects are in two different databases, the dependency is called a remote
dependency.
The Oracle server does not automatically track relationships (such as dependencies) between objects in two different
databases, even when the two databases are on the same server machine. This is because each database has its own
separate and independent data dictionary.
In this and the following slides explaining remote dependencies, the examples used are procedures. But they are true
for any PL/SQL subprogram: procedure, function, package specification, or trigger.
You CANNOT create a remote dependency in the Academy Application Express environment because there is only one
database. In real life, you (or the DBA) would first create a database link, which is a pointer to a remote database, and
then reference the database link within a local procedure. For example:
CREATE DATABASE LINK my_db_link
CONNECT TO remote_username IDENTIFIED BY remote_password
USING 'remote_database_name';

CREATE OR REPLACE procedureA ...


IS BEGIN
… procedureB@my_db_link (parameters…)
...
END;

5
If the remote procedure is (directly or indirectly) invalidated, the server cannot automatically invalidate the
local procedure because there is no reference to the local procedure within the remote data dictionary.

The slide shows what happens when a table in the remote database is modified. The view and procedure in
the remote database are automatically invalidated because they are in the same database as the table, but
the local procedure is not invalidated because it is in a different database.

However, the local procedure can (and will) be invalidated when it invokes (calls) the remote procedure; in
other words, at execution time.

6
The REMOTE_DEPENDENCIES_MODE parameter must be set in the local database, not the remote
database. For example:

ALTER SESSION SET REMOTE_DEPENDENCIES_MODE = SIGNATURE;

To change back to default timestamp mode:

ALTER SESSION SET REMOTE_DEPENDENCIES_MODE = TIMESTAMP;

7
8
Timestamps (and signatures) are actually stored within the compiled code (P-code) of the PL/SQL subprogram itself,
not in the data dictionary. But the local timestamp can be seen by selecting from USER_OBJECTS, which is a data
dictionary table.

These automatic timestamps are stored for all object types (table, view, index, synonym, and so on), not only for
PL/SQL subprograms. Try this:

CREATE TABLE timetab (firstcol NUMBER);

SELECT timestamp "Created at" FROM USER_OBJECTS


WHERE object_type = 'TABLE' and object_name = 'TIMETAB';

ALTER TABLE timetab ADD (secondcol NUMBER);

SELECT timestamp "Altered at" FROM USER_OBJECTS


WHERE object_type = 'TABLE' and object_name = 'TIMETAB';

Remember that these timestamps show database server time; the server may not be in your time zone.

9
Whenever a PL/SQL subprogram is compiled (successfully or unsuccessfully), the timestamp of the
compilation is stored within the subprogram.

When local procedure A is compiled, and it references remote procedure B, the remote procedure's
timestamp is read and stored within the local procedure, as well as the local procedure's timestamp.

10
It does not matter when the two subprograms were originally compiled, as long as they are both valid at
the start of this example.

11
When procedure A was compiled (at 7:00 a.m.) the compiler checked the validity and timestamp of remote
procedure B by a call across the network, and stored B's timestamp within A’s dictionary, as well as A's
timestamp.

You cannot SELECT the timestamps of remote subprograms in USER_OBJECTS.

12
Remember that procedure A calls procedure B, but not vice-versa. So there is no reference to A in the code
of B. Therefore, (re)compiling B stores B's new timestamp only.

13
The code of procedure A references procedure B. Therefore, when A is (re)compiled, the validity of B is
checked, just as with local dependencies. The timestamp of B is stored within procedure A.

14
When procedure A is executed, the validity and timestamp of B are checked. Because B is valid and its
timestamp is still 8:00 a.m., the local Oracle server knows that B cannot possibly have been recompiled
(therefore cannot have been altered) since 8:00 a.m.

Procedure A therefore remains valid and executes successfully.

15
This time, when procedure A is executed, the two timestamps of B are not equal. So the local Oracle server
knows that B must have been recompiled since it was last invoked from A.

The key point here is that A is not automatically recompiled, because it was not invalid at the start of its
execution. Instead, the execution fails and returns an unhandled exception. This is true even when B's
formal parameters were not changed by the recompilation at 11:00 a.m.

If the relationship had been a LOCAL dependency, and B's formal parameters had not changed, this step
would have executed successfully and A would have remained valid.

16
The second execution of procedure A forces a recompilation because its status was invalid. As always, the
actual parameters in A are compared with the formal parameters of B. Since they still match, A recompiles
and executes successfully and the remote timestamp is updated.

17
B's new timestamp is stored within B.

18
19
A subprogram's timestamp changes every time the subprogram is recompiled, while its signature changes
only if the formal parameters have changed.

You cannot SELECT signatures from the data dictionary.

20
21
22
23
24
Since the recompilation of procedure B at 11:00 a.m. did not change its formal parameters (and therefore
they still match the actual parameters within procedure A), B's signature was not changed by its
recompilation. Therefore, when A is executed, the local and remote signatures are still equal and the
execution is successful.

25
Remote Dependencies are when the Oracle database manages dependencies in a distributed environment
across a network.
Signature Mode is the setting to check if a local subprogram is still valid, or must be invalidated by checking
the value a unique number calculated and stored each time a procedure is recompiled.
Timestamp Mode is the setting to check if a local subprogram is still valid, or must be invalidated by
checking the value in the USER_OBJECTS dictionary view.

26
27
Release Date: August, 2016
Updates:
2
3
4
Oracle designed its database products to be flexible and configurable so they would operate on more than
seventy computer platforms, from mainframes to PC networks to tablets and phones. The secret to this
flexibility lies in the software's initialization parameters, whose numerous settings can be configured for
top performance in countless environments. On the downside, however, improper settings can slow a
system down, even grind it to a halt.

Oracle administrators need to keep in mind the characteristics and optimal settings for each parameter to
make key adjustments to an Oracle database. Most initialization parameters can be altered dynamically by
using the ALTER SESSION or ALTER SYSTEM command. Initialization parameters can be set in the init.ora
file.

5
6
Although your Oracle Application Express (APEX) environment automatically commits changes, the
following slides will be presented as if you were issuing the commands in an installed/local environment
with the ability to use COMMIT and ROLLBACK.

In your APEX configuration (with AUTOCOMMIT enabled), the optimization options presented here may
produce unpredictable results depending on the code being compiled.

7
PLSQL_CODE_TYPE specifies the compilation mode (with or without native compilation) for PL/SQL library
units (subprograms).
Values:
INTERPRETED - PL/SQL library units will be compiled to PL/SQL bytecode format. Such modules are
executed by the PL/SQL interpreter engine.
NATIVE - PL/SQL library units (with the possible exception of top-level anonymous PL/SQL blocks) will be
compiled to native machine code. Such modules will be executed natively without incurring any interpreter
overhead.
When the value of this parameter is changed, it has no effect on PL/SQL library units that have already
been compiled. The value of this parameter is stored persistently with each library unit.
If a PL/SQL library unit is compiled native, all subsequent automatic recompilations of that library unit will
use native compilation.

8
9
10
11
12
13
14
The native code need not be interpreted at run time, so it runs faster. Because native compilation applies
only to PL/SQL statements, a PL/SQL unit that only calls SQL statements might not run faster when natively
compiled, but it does run at least as fast as the corresponding interpreted code. The compiled code and the
interpreted code make the same library calls, so their action is the same.

15
16
17
18
Runtime performance can be improved dramatically, with only a slight increase (typically) in compile time.
The benefits of optimization apply to both interpreted and natively compiled PL/SQL because optimizations
are applied by analyzing patterns in source code.

19
Additional Information:

PLSQL_OPTIMIZE_LEVEL = 0: This setting essentially turns off compiler optimization. The PL/SQL compiler
maintains the original evaluation order of statement processing of the Oracle9i Database and earlier
releases. Although code will run somewhat faster than it did in Oracle9i, use of level 0 will forfeit most of
the performance gains of PL/SQL in Oracle Database 10g and later releases.

20
Additional Information:

PLSQL_OPTIMIZE_LEVEL = 2: (default value) Compiler will apply many modern optimization techniques
beyond level 1, and some of those changes may result in moving source code relatively far from its original
location. Level 2 optimization may cause the compilation time in some of your programs to increase
substantially. If you encounter this situation (or, alternatively, if you are developing your code and want to
minimize compile time, knowing that when you move to production, you will apply the highest optimization
level), try cutting back the optimization level to 1.

21
22
The optimizer settings are defined through the PLSQL_OPTIMIZE_LEVEL initialization parameter (and
related ALTER DDL statements), which can be set to 0, 1, 2, or 3. The higher the number, the more
aggressive the optimization, meaning that the compiler will make a greater effort, and possibly restructure
more of your code, to optimize performance.

23
This data dictionary view displays information about the compiler settings for the stored objects owned by
the current user. Its columns (except for OWNER) are the same as those in ALL_PLSQL_OBJECT_SETTINGS.

24
25
PLSQL_CODE_TYPE - improve execution speed of compiled PL/SQL code.

PLSQL_OPTIMIZE_LEVEL - used to control what the PL/SQL Compiler does with useless code, as well as
giving other performance benefits.

PLSQL INITIALIZATION PARAMETER - used to change the way a user’s database session interacts with the
Oracle server.

USER_PLSQL_OBJECT_SETTINGS - data dictionary view to see how a PL/SQL program was compiled.

26
27
Release Date: August, 2016
Updates:
2
3
4
5
6
7
8
To make your programs more robust and avoid problems at run time, you can enable checking for certain
warning conditions. These conditions are not serious enough to produce an error and keep you from
compiling a subprogram. They might point out something in the subprogram that produces an undefined
result or might create a performance problem. For example, when this procedure is created (or replaced)
after the ALTER SESSION command enables all PL/SQL warning messages, you see this procedure
UNREACHABLE has a line of code identified that would never execute.

9
Use the ALTER SESSION command to enable PL/SQL warning messages.

10
USER_ERRORS describes current errors on all stored objects (views, procedures, functions, packages, and
package bodies) owned by the current user. You can also treat particular messages as errors instead of
warnings. For example, if you know that the warning message PLW-05003 represents a serious problem in
your code, including ERROR:05003' in the PLSQL_WARNINGS setting makes that condition trigger an error
message (PLS_05003) instead of a warning message. You would do this when you want the result to be a
failed compilation rather than simply a warning message.

11
To work with PL/SQL warning messages, you use the PLSQL_WARNINGS initialization parameter. PL/SQL
warning messages are divided into categories so that you can suppress or display groups of similar warnings
during compilation. The categories are:

· SEVERE: Messages for conditions that might cause unexpected behavior or wrong results, such as aliasing
problems with parameters.

· PERFORMANCE: Messages for conditions that might cause performance problems, such as passing a
VARCHAR2 value to a NUMBER column in an INSERT statement.

· INFORMATIONAL: Messages for conditions that do not have an effect on performance or correctness, but
that you might want to change to make the code more maintainable, such as the example for unreachable
code that can never be executed.

· ALL: is a shorthand way to refer to all warning messages.

12
Oracle can issue warnings when you compile subprograms that produce ambiguous results or use
inefficient constructs. To work with PL/SQL warning messages, you can use the PLSQL_WARNINGS
initialization parameter or the DBMS_WARNING package. Let’s look at some examples of the
PLSQL_WARNINGS initialization parameter first.

13
14
15
ALTER SESSION SET PLSQL_WARNINGS = 'DISABLE:ALL';
--all warnings are disabled.
ALTER SESSION SET PLSQL_WARNINGS = 'ENABLE:PERFORMANCE';
--only performance warning level is enabled. Other categories are unchanged.
ALTER SESSION SET PLSQL_WARNINGS = 'ENABLE:SEVERE';
--like the previous example, this only enables severe warning level and other categories are unchanged.
ALTER SESSION SET PLSQL_WARNINGS = 'ENABLE:ALL', 'DISABLE:SEVERE';
--This first enables all three categories, then disables the SEVERE category, so that PERFORMANCE and
INFORMATIONAL are still enabled.
ALTER SESSION SET PLSQL_WARNINGS = 'DISABLE:SEVERE', 'ENABLE:ALL';
--This first disables the severe performance warning level and then enables all warning levels overriding the
first parameter setting.

16
17
Warning messages are prefixed with PLW and error messages are prefixed with PLS. Query the
USER_ERRORS table in the data dictionary to obtain warning and error messages on stored objects.
The USER_ERRORS table includes the following columns:
NAME (name of the object)
TYPE (type of object VIEW, PROCEDURE, etc.)
SEQUENCE (sequence number for ordering purposes)
LINE (line number at which the error occurred)
POSITION (position in the line at which the error occurred)
TEXT (text of the error)
ATTRIBUTE (indicates ERROR or WARNING)
MESSAGE_NUMBER (error number without the prefix)

18
19
You can adjust your settings with a very high level of granularity by combining different options. For
example, suppose you want to see all severe issues and you want the compiler to treat PLW-05005:
function exited without a RETURN as a compile error.
If you leave PLW-05005 simply as a warning and compile the no_return function, the program does compile
and you can use it in an application. If you alter the treatment of that warning with the ALTER SESSION
command and then recompile no_return, the compiler fails with an error.
You can also specify ALL as a quick and easy way to refer to all compile-time warnings categories, as in:
ALTER SESSION SET PLSQL_WARNINGS = 'ENABLE:ALL';

20
Oracle's DBMS_WARNING allows the PL/SQL programmer to selectively control which categories of
warning and which individual warnings to disable, enable, or treat as errors. If you are writing in a
development environment that compiles PL/SQL subprograms, you can control PL/SQL warning messages
by calling subprograms in the DBMS_WARNING package. You might also use this package when compiling a
complex application, made up of several nested SQL*Plus scripts, where different warning settings apply to
different subprograms. You can save the current state of the PLSQL_WARNINGS parameter with one call to
the package, change the parameter to compile a particular set of subprograms, then restore the original
parameter value.

21
The DBMS_WARNING package provides a way to manipulate the behavior of PL/SQL warning messages, in
particular by reading and changing the setting of the PLSQL_WARNINGS initialization parameter to control
what kinds of warnings are suppressed, displayed, or treated as errors. This package provides the interface
to modify, create, or query current system or session settings.

22
You can modify the current session's or system's warning settings with the value supplied. The value will be
added to the existing parameter setting if the value for the warning category or warning value has not been
set, or override the existing value. The effect of calling this function is the same as adding the qualifier
(ENABLE/DISABLE/ERROR) on the category specified to the end of the current session or system setting.

23
This procedure replaces previous settings with the new value of ‘SEVERE’. This will have the same effect as
the example using the subsequent ALTER SESSION (OR ALTER SYSTEM) command.
Syntax:
DBMS_WARNING.SET_WARNING_SETTING_STRING (warning_value IN VARCHAR2, scope IN VARCHAR2);
warning_value – the new string that will constitute the new value (in the example above this is
‘ENABLE:SEVERE’)
scope – specifies if the changes are being done in the session context or system context. Allowed values are
SESSION or SYSTEM (in this example, we are activating this for just this user’s session)

24
This function returns the entire warning string for the current session. Use this function when you want to
parse the warning string yourself and then modify and set the new value using
SET_WARNING_SETTING_STRING.

25
This function returns the category name, given the message number.

26
27
28
29
DBMS_WARNING - Server-supplied package that allows you to set the same warning categories as the
PLSQL_WARNINGS parameter, but also allows you to save your previous warning settings in a PL/SQL
variable so you can easily return to your original settings.

PL/SQL Compiler Errors - Fatal situations identified during compilation that must be corrected prior to
successful compilation.

PL/SQL Compiler Warnings - Non-fatal situations that can be identified during compilation by setting
PLSQL_WARNINGS. Using PLSQL_WARNINGS, you can selectively control which warning categories and
individual warnings to disable, enable, or treat as errors.

30
31
Release Date: August, 2016
Updates:
2
3
4
5
6
This means you can include new features in your application when it runs in the latest database
environment and automatically disable the new features when running the application in an older database
environment. You also can activate debugging or tracing statements to run in the development
environment and automatically ignore them when running the application at a production site.

7
Conditional compilation uses selection directives, inquiry directives, and error directives to specify source
text for compilation.
The selection directive evaluates static expressions to determine which text should be included in the
compilation. This procedure example called LETS_PRETEND uses a selection directive.
The selection directive is of the form:
$IF boolean_static_expression $THEN text
[ $ELSIF boolean_static_expression $THEN text ]
[ $ELSE text ]
$END
The error directive $ERROR raises a user-defined error and is of the form:
$ERROR varchar2_static_expression $END
The inquiry directive is used to check the compilation environment. An inquiry directive can be predefined
or be user-defined.
The inquiry directive is of the form:
inquiry_directive ::= $$id

8
Generally, conditional compilation is helpful when you are trying to write a portable program, but the way
you do something is different depending on what compiler, operating system, or computer you're using.
You could use conditional compilation if you want to compile different versions of your program with
different features present in the different versions.

Although the example is a "real" function and you can run this code, it is a very simple function. It receives
no parameters and always returns the value 17 as a NUMBER datatype.

9
To learn more about the DETERMINISTIC option, you can explore what it does and when to use it at
http://docs.oracle.com.

Basically, the DETERMINISTIC option speeds up the execution of any code calling this function and passing it
the same parameter values as were passed to it in a previous call to this function.

10
USER_SOURCE describes the text source of the stored objects owned by the current user. There are four
columns available to query of this view stored in the Data Dictionary. They are:

NAME - VARCHAR2(30) NOT NULL Name of the object


TYPE - VARCHAR2(12) Type of object: FUNCTION, JAVA SOURCE, PACKAGE, PACKAGE BODY, PROCEDURE,
TRIGGER, TYPE, TYPE BODY
LINE - NUMBER NOT NULL Line number of this line of source
TEXT - VARCHAR2(4000) Text source of the stored object

To see the name and type of your programs, run the following:

SELECT DISTINCT(name), type FROM USER_SOURCE;

11
The PRINT_POST_PROCESSED_SOURCE procedure returns the source code text of a stored PL/SQL unit that
resulted from the most recent successful compilation of its actual source code.

The basic parameters for PRINT_POST_PROCESSED_SOURCE are:

object_type - Must be PACKAGE, PACKAGE BODY, PROCEDURE, FUNCTION, or TRIGGER.


schema_name - Enter your user name.
object_name - Enter the name of the object.

The DBMS_PREPROCESSOR package has other capabilities you can explore at http://docs.oracle.com.

12
13
14
15
16
17
Oracle recommends that this parameter be used for controlling the conditional compilation of debugging or
tracing code. This initialization parameter provides a mechanism that allows PL/SQL programmers to
control conditional compilation of each PL/SQL library unit independently.

18
Each PLSQL_CCFLAGS variable must be either a BOOLEAN literal (TRUE, FALSE, or NULL) or a PLS_INTEGER
literal.

19
20
Example:

ALTER SESSION SET PLSQL_CCFLAGS = 'DeBug:TruE';


ALTER SESSION SET PLSQL_CCFLAGS = 'debug:TRUE';
ALTER SESSION SET PLSQL_CCFLAGS = ‘testflag:1';
ALTER SESSION SET PLSQL_CCFLAGS = ‘TeStFlAg:1’;

21
22
23
This table displays information about the compiler settings for the stored objects owned by the current
user.

NAME - VARCHAR2(30) NOT NULL Name of the object


TYPE - VARCHAR2(12) Type of the object: PROCEDURE, FUNCTION, PACKAGE, PACKAGE BODY, TRIGGER,
TYPE, TYPE BODY
PLSQL_OPTIMIZE_LEVEL - NUMBER Optimization level that was used to compile the object
PLSQL_CODE_TYPE - VARCHAR2(4000) Compilation mode for the object
PLSQL_DEBUG - VARCHAR2(4000) Indicates whether the object was compiled with debug information or
not
PLSQL_WARNINGS - VARCHAR2(4000) Compiler warning settings that were used to compile the object
NLS_LENGTH_SEMANTICS - VARCHAR2(4000) NLS length semantics that were used to compile the object
PLSQL_CCFLAGS - VARCHAR2(4000) Conditional compilation flag settings that were used to compile the
object
PLSCOPE_SETTINGS - VARCHAR2(4000) Settings for using PL/Scope

24
25
The DBMS_DB_VERSION package specifies the Oracle version numbers and other information useful for
simple conditional compilation selections based on Oracle versions. The DBMS_DB_VERSION package
contains different constants for different Oracle Database versions and releases.

VERSION - PLS_INTEGER with a value of 11: Current version


RELEASE - PLS_INTEGER with a value of 1: Current release
VER_LE_9 – BOOLEAN with a value of FALSE: Version <= 9
VER_LE_9_1 – BOOLEAN with a value of FALSE: Version <= 9 and release <= 1
VER_LE_9_2 – BOOLEAN with a value of FALSE: Version <= 9 and release <= 2 …

26
Conditional Compilation - allows you to include some source code in your PL/SQL program that may be
compiled or ignored by the compiler depending on a value checked at compilation.

DBMS_DB_VERSION - package specifies the Oracle version numbers and other information useful for
simple conditional compilation selections based on Oracle versions.

DBMS_PREPROCESSOR - an Oracle-supplied package that can return or display the post-processed source
text of a stored PL/SQL unit

Inquiry and Selection Directives - used in conditional compilation

PLSQL_CCFLAGS - mechanism that allows PL/SQL programmers to control conditional compilation of each
PL/SQL library unit independently.

USER_SOURCE - data dictionary view to see the complete source code, including the compiler directives,
for a stored PL/SQL unit

27
28
Release Date: August, 2016
Updates:
2
3
4
5
6
7
Obfuscated code is source or machine code that has been made difficult to understand. Programmers may
deliberately obfuscate code to conceal its purpose (a form of security through obscurity), to deter reverse
engineering, or as a puzzle or recreational challenge for readers. Programs known as obfuscators transform
human-readable code into obfuscated code using various techniques. Obfuscating code is typically done to
manage risks that stem from unauthorized access to source code. These risks include loss of intellectual
property, ease of probing for application vulnerabilities, and loss of revenue that can result when
applications are reverse engineered, modified to circumvent metering or usage control, and then
recompiled. Obfuscating code is, therefore, also a compensating control to manage these risks.

8
9
The DBMS_DDL package contains procedures for obfuscating a single PL/SQL unit, such as a package
specification, package body, function, procedure, type specification, or type body. These overloaded
subprograms provide a mechanism for obfuscating dynamically generated PL/SQL program units that are
created in a database.

The DBMS_DDL package contains the WRAP function and the CREATE_WRAPPED procedure. The
CREATE_WRAPPED both wraps the text and creates the PL/SQL unit.

10
11
12
13
14
ANSWER: Other developers need to see information in the specification in order to use the package.

15
This utility is especially handy for customers who have users that may not necessarily be under their
administrative control. For example, for users who run your application from the Internet.

16
17
18
For this course, we must use DBMS_DDL.CREATE_WRAPPED.

19
DBMS_DDL.CREATE_WRAPPED - procedure for obfuscating a single PL/SQL unit which both wraps the text
and creates the PL/SQL unit.

Obfuscation - process of turning code into source or machine code to make it difficult to understand.

Wrapper Utility - processes an input SQL file and obfuscates only the PL/SQL units in the file.

Wrapping PL/SQL Source Code - process of hiding the PL/SQL source code using the wrap utility or
DBMS_DDL subprograms.

20
21

You might also like