PLSQL notes
PLSQL notes
SQL PL/SQL
Advantages of PL/SQL
Block Structures: PL SQL consists of blocks of code, which can be nested within each
other. Each block forms a unit of a task or a logical module. PL/SQL Blocks can be
stored in the database and reused.
Procedural Language Capability: PL SQL consists of procedural language constructs
such as conditional statements (if else statements) and loops like (FOR loops).
Error Handling: PL/SQL handles errors or exceptions effectively during the execution of
a PL/SQL program. Once an exception is caught, specific actions can be taken depending
upon the type of the exception or it can be displayed to the user with a message.
Block Structure
PL/SQL blocks have a pre-defined structure in which the code is to be grouped. Below are
different sections of PL/SQL blocks.
1. Declaration section
2. Execution section
3. Exception-Handling section
PL/SQL Block Syntax. Below is the syntax of the PL/SQL block structure.
Anonymous blocks:
Anonymous blocks are PL/SQL blocks which do not have any names assigned to them.
They need to be created and used in the same session because they will not be stored in the
server as database objects.
Since they need not store in the database, they need no compilation steps. They are written
and executed directly, and compilation and execution happen in a single process.
These blocks don't have any reference name specified for them.
These blocks start with the keyword 'DECLARE' or 'BEGIN'.
Since these blocks do not have any reference name, these cannot be stored for later
purpose. They shall be created and executed in the same session.
They can call the other named blocks, but call to anonymous block is not possible as
it is not having any reference.
It can have nested block in it which can be named or anonymous. It can also be
nested in any blocks.
These blocks can have all three sections of the block, in which execution section is
mandatory, the other two sections are optional.
Named blocks:
Named blocks have a specific and unique name for them. They are stored as the database
objects in the server. Since they are available as database objects, they can be referred to or
used as long as it is present on the server. The compilation process for named blocks
happens separately while creating them as a database objects.
1. Procedure
2. Function
We need to execute "set serveroutput on" if we need to see the output of the code.
Sql>ed
BEGIN
dbms_output.put_line (‘Hello World..');
END:
/
Sql>/
Output:
Hello World...
DECLARE
text VARCHAR2(25);
BEGIN
text:= ‘Hello World’;
dbms_output.put_line (text);
END:
/
Output:
Hello World
Comments in PL/SQL
Comment can be used in the program to increase the readability of the program. In
PL/SQL codes can be commented in two ways.
Using '--' in the beginning of the line to comment that particular line.
Using '/*…….*/' we can use multiple lines. The symbol '/*' marks the starting of the
comment and the symbol '*/' marks the end of the comment. The code between these
two symbols will be treated as comments by the compiler
BEGIN
--single line comment
dbms output.put line (' Hello World ’);
/*Multi line commenting begins
Multi line commenting ends */
END;
/
Output:
Hello World
PL/SQL Placeholders
Placeholders are temporary storage area. PL/SQL Placeholders can be any of Variables,
Constants and Records. Oracle defines placeholders to store data temporarily, which are
used to manipulate data during the execution of a PL SQL block.
Depending on the kind of data you want to store, you can define placeholders with a name
and a datatype. Few of the datatypes used to define placeholders are as given below.
Number (n,m) , Char (n) , Varchar2 (n) , Date , Long , Long raw, Raw, Blob, Clob, Nclob,
Bfile
Properties of Identifiers
PL/SQL Variables
General Syntax to declare a variable is
variable_name datatype [NOT NULL := value ];
For example, if you want to store the current salary of an employee, you can use a
variable.
DECLARE
salary number (6);
When a variable is specified as NOT NULL, you must initialize the variable when it
is declared.
For example: The below example declares two variables, one of which is a not null.
DECLARE
salary number(4);
dept varchar2(10) NOT NULL := “HR Dept”;
The value of a variable can change in the execution or exception section of the PL/SQL
Block. We can assign values to variables in the two ways given below.
variable_name:= value;
<variable_name> <datatype> := <value>;
2) We can assign values to variables directly from the database columns by using a
SELECT.. INTO statement. The General Syntax is:
Example: The below program will get the salary of an employee with id '1116' and display
it on the screen.
DECLARE
var_salary number(6);
var_emp_id number(6) = 1116;
BEGIN
SELECT salary
INTO var_salary
FROM employee
WHERE emp_id = var_emp_id;
dbms_output.put_line(var_salary);
dbms_output.put_line('The employee '
|| var_emp_id || ' has salary ' || var_salary);
END;
/
PL/SQL Constants
As the name implies a constant is a value used in a PL/SQL Block that remains
unchanged throughout the program.
DECLARE
salary_increase CONSTANT number (3) := 10;
You must assign a value to a constant at the time you declare it. If you do not assign a
value to a constant while declaring it and try to assign a value in the execution section,
you will get a error. If you execute the below Pl/SQL block you will get error.
DECLARE
salary_increase CONSTANT number(3);
BEGIN
salary_increase := 100;
dbms_output.put_line (salary_increase);
END;
PL/SQL Records
Declaring a record:
To declare a record, you must first define a composite datatype; then declare a record
for that type.
The following table consolidates the different ways in which you can define and
declare a pl/sql record.
Usage
Syntax
Example:
1.
DECLARE
TYPE employee_type IS RECORD
(employee_id number(5),
employee_first_name varchar2(25),
employee_last_name employee.last_name%type,
employee_dept employee.dept%type);
employee_salary employee.salary%type;
employee_rec employee_type;
2.
DECLARE
employee_rec employee%ROWTYPE;
The advantages of declaring the record as a ROWTYPE are:
1) You do not need to explicitly declare variables for all the columns in a table.
2) If you alter the column specification in the database table, you do not need to update the
code.
The following table consolidates the different ways you can assign values to and from
a record:
Usage
Syntax
record_name.col_name := value; To directly assign a value to a
specific column of a record.
record_name.column_name := value; To directly assign a value to a
specific column of a record, if
the record is declared using
%ROWTYPE.
SELECT col1, col2 INTO To assign values to each field of
record_name.col_name1, a record from the database table.
record_name.col_name2 FROM table_name
[WHERE clause];
SELECT * INTO record_name FROM To assign a value to all fields in
table_name [WHERE clause]; the record from a database table.
variable_name := record_name.col_name; To get a value from a record
column and assigning it to a
variable.
DECLARE
no1 number(5);
name1 employee5.name%type;
salary1 number(5);
deptno1 employee.deptno%type;
commission1 employee5.comm%type;
emp1 emp_rec;
BEGIN
select empno,name,salary,deptno into
no1,name1,salary1,deptno1 from
employee5 where empno=1;
dbms_output.put_line('employee no is '||no1);
dbms_output.put_line('employee name is '||
name1);
dbms_output.put_line('employee slary is '||
salary1);
dbms_output.put_line('employee department
no is '||deptno1);
END;
/
Output:
SQL> @ five.sql
employee no is 1
employee name is aaa
employee slary is 10000
employee department no is 10
employee no is 2
employee name is bbb
employee slary is 20000
employee department no is 30
syntax
There are different syntaxes for the IF-THEN-ELSE statement.
Syntax (IF-THEN)
IF condition THEN
{...statements to execute when condition is TRUE...}
END IF;
You use the the IF-THEN syntax, when you want to execute statements only
when condition is TRUE.
Syntax (IF-THEN-ELSE)
IF condition THEN
{...statements to execute when condition is TRUE...}
ELSE
{...statements to execute when condition is FALSE...}
END IF;
You use the IF-THEN-ELSE syntax, when you want to execute one set
of statements when condition is TRUE or a different set of statements when condition is
FALSE.
Syntax (IF-THEN-ELSIF)
IF condition1 THEN
{...statements to execute when condition1 is TRUE...}
ELSIF condition2 THEN
{...statements to execute when condition2 is TRUE...}
END IF;
You use the IF-THEN-ELSIF syntax, when you want to execute one set
of statements when condition1 is TRUE or a different set of statements when condition2 is
TRUE.
Syntax (IF-THEN-ELSIF-ELSE)
IF condition1 THEN
{...statements to execute when condition1 is TRUE...}
ELSE
{...statements to execute when both condition1 and condition2 are
FALSE...}
END IF;
You use the IF-THEN-ELSIF-ELSE syntax, when you want to execute one set
of statements when condition1 is TRUE, a different set of statements when condition2 is
TRUE, or a different set of statements when all previous conditions
(ie: condition1 and condition2) are FALSE
• Simple Loop
• While Loop
• For Loop
1) Simple Loop
A Simple Loop is used when a set of statements is to be executed
at least once before the loop terminates. An EXIT condition must
be specified in the loop, otherwise the loop will get into an
infinite number of iterations. When the EXIT condition is satisfied
the process exits from the loop.
2) While Loop
WHILE <condition>
LOOP statements;
END LOOP;
Important steps to follow when executing a while loop:
3) FOR Loop
A FOR LOOP is used to execute a set of statements for a predetermined number of
times. Iteration occurs between the start and end integer values given. The counter
is always incremented by 1. The loop exits when the counter reachs the value of the
end integer.
1) The counter variable is implicitly declared in the declaration section, so it's not
necessary to declare it explicity.
2) The counter variable is incremented by 1 and does not need to be incremented
explicitly.
3) EXIT WHEN statement and EXIT statements can be used in FOR loops but it's not
done oftenly.
CASE Statement
A CASE statement is similar to IF-THEN-ELSIF statement that selects one alternative
based on the condition from the available options.
Unlike IF-THEN-ELSIF, the CASE statement can also be used in SQL statements.
ELSE block in CASE statement holds the sequence that needs to be executed when
none of the alternatives got selected.
Syntax:
CASE (expression)
WHEN <valuel> THEN action_blockl;
WHEN <value2> THEN action_block2;
WHEN <value3> THEN action_block3;
ELSE action_block_default;
END CASE;
Example:
DECLARE
a NUMBER :=55;
b NUMBER :=5;
arth_operation VARCHAR2(20) :='MULTIPLY';
BEGIN
dbms_output.put_line('Program started.' );
CASE (arth_operation)
WHEN 'ADD' THEN dbms_output.put_line('Addition of the numbers are: '|| a+b );
WHEN 'SUBTRACT' THEN dbms_output.put_line('Subtraction of the numbers are: '||a-
b );
WHEN 'MULTIPLY' THEN dbms_output.put_line('Multiplication of the numbers are: '||
a*b );
WHEN 'DIVIDE' THEN dbms_output.put_line('Division of the numbers are:'|| a/b);
ELSE dbms_output.put_line('No operation action defined. Invalid operation');
END case;
dbms_output.put_line('Program completed.' );
END;
/
SET SERVEROUTPUT ON
DECLARE
l_day VARCHAR2(10);
BEGIN
l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));
CASE l_day
WHEN 'SATURDAY' THEN
DBMS_OUTPUT.put_line('The weekend has just started!');
WHEN 'SUNDAY' THEN
DBMS_OUTPUT.put_line('The weekend is nearly over!');
ELSE
DBMS_OUTPUT.put_line('It''s not the weekend yet!');
END CASE;
END;
/
The first WHEN clause that satisfies the condition will be executed, and the
controller will skip the remaining alternatives.
Syntax:
CASE
WHEN <expression1> THEN action_blockl;
WHEN <expression2> THEN action_block2;
WHEN <expression3> THEN action_block3;
ELSE action_block_default;
END CASE;
Example:
DECLARE
a NUMBER :=55;
b NUMBER :=5;
arth_operation VARCHAR2(20) :='MULTIPLY';
BEGIN
dbms_output.put_line('Program started.' );
CASE
WHEN arth_operation = 'ADD' THEN dbms_output.put_line('Addition of the numbers
are: '|| a+b );
WHEN arth_operation = 'SUBTRACT' THEN dbms_output.put_line('Subtraction of the
numbers are: '||a-b );
WHEN arth_operation = 'MULTIPLY' THEN dbms_output.put_line('Multiplication of the
numbers are: '|| a*b );
WHEN arth_operation = 'DIVIDE' THEN dbms_output.put_line('Division of the
numbers are:'|| a/b);
ELSE dbms_output.put_line('No operation action defined. Invalid operation');
END case;
dbms_output.put_line('Program completed.' );
END;
/
Declare
Var1 integer;
Var2 integer;
Var3 integer;
Begin
Var1:=&var1;
Var2:=&var2;
Var3:=var1+var2;
Dbms_output.put_line(var3);
End;
/
PL/SQL Program to Find Factorial of a Number
declare
n number;
fac number:=1;
i number;
begin
n:=&n;
for i in 1..n
loop
fac:=fac*i;
end loop;
dbms_output.put_line('factorial='||fac);
end;
/
declare
n number;
i number;
begin
n:=&n;
for i in 1..10
loop
dbms_output.put_line(n||' x '||i||' = '||n*i);
end loop;
end;
/
PL/SQL Program to Check Number is Odd or Even
declare
n number:=&n;
begin
if mod(n,2)=0
then
dbms_output.put_line('number is even');
else
dbms_output.put_line('number is odd');
end if;
end;
/
PL/SQL Program to Swap two Numbers
declare
a number;
b number;
temp number;
begin
a:=5;
b:=10;
dbms_output.put_line('before swapping:');
dbms_output.put_line('a='||a||' b='||b);
temp:=a;
a:=b;
b:=temp;
dbms_output.put_line('after swapping:');
dbms_output.put_line('a='||a||' b='||b);
end;
/
declare
n number;
m number;
rev number:=0;
r number;
begin
n:=12321;
m:=n;
while n>0
loop
r:=mod(n,10);
rev:=(rev*10)+r;
n:=trunc(n/10);
end loop;
if m=rev
then
dbms_output.put_line('number is palindrome');
else
dbms_output.put_line('number is not palindrome');
end if;
end;
/
PL/SQL Program to Reverse a String
declare
str1 varchar2(50):='&str';
str2 varchar2(50);
len number;
i number;
begin
len:=length(str1);
SET SERVEROUTPUT ON
EXECUTE display_numbers(2, 6);
2
3
4
5
6
Proc1.sql
create or replace procedure add(n1 in int,n2 in int,result out int)
as
begin
result :=n1+n2;
end;
sql>@proc1.sql
sql>edit proc2.sql
declare
result int;
begin
add(5,5,result);
dbms_output.put_line(result);
end;
sql>@proc2.sql
Functions:
PRINT l_result
L_RESULT
----------
4
Example:
Sql>ed funtest.sql
RETURN NUMBER AS
BEGIN
RETURN X * 2;
END;
SQL> @funtest
Function created.
GET_DOUBLE(2)
-------------
Packages:
Packages allow related code, along with supporting types, variables and cursors, to be grouped together.
The package is made up of a specification that defines the external interface of the package, and a body
that contains all the implementation code. The following code shows how the previous procedure and
function could be grouped into a package.
CREATE OR REPLACE PACKAGE my_package AS
PROCEDURE display_numbers (
p_lower IN NUMBER,
p_upper IN NUMBER);
FUNCTION difference (
p_lower IN NUMBER,
p_upper IN NUMBER)
RETURN NUMBER;
END;
/
PROCEDURE display_numbers (
p_lower IN NUMBER,
p_upper IN NUMBER)
AS
BEGIN
FOR i IN p_lower .. p_upper LOOP
DBMS_OUTPUT.put_line(i);
END LOOP;
END;
FUNCTION difference (
p_lower IN NUMBER,
p_upper IN NUMBER)
RETURN NUMBER
AS
BEGIN
RETURN p_upper - p_lower;
END;
END;
/
Once the package specification and body are compiled they can be executed as before, provided the
procedure and function names are prefixed with the package name.
SET SERVEROUTPUT ON
EXECUTE my_package.display_numbers(2, 6);
2
3
4
5
6
PRINT l_result
L_RESULT
----------
4
Method 3
RETURN total;
END;
/
Proc2.sql
Proc1.sql
create or replace procedure proc1 as
empid emp.empno%TYPE; -- employee_id datatype is NUMBER(6)
emplname emp.ename%TYPE; -- last_name datatype is VARCHAR2(25)
BEGIN
empid:= 7900; -- this is OK because it fits in NUMBER(6)
-- empid := 3018907; -- this is too large and will cause an overflow
emplname:= 'Patel'; -- this is OK because it fits in VARCHAR2(25)
DBMS_OUTPUT.PUT_LINE('Employee ID: ' || empid); -- display data
DBMS_OUTPUT.PUT_LINE('Employee name: ' || emplname); -- display dataet
update emp set ename=emplname where empno=empid;
END;
/
CURSORS
A cursor is a pointer to a private SQL area that stores information about the processing of a
SELECT or data manipulation language (DML) statement (INSERT, UPDATE, DELETE,
or MERGE). Cursor management of DML statements is handled by Oracle Database, but
PL/SQL offers several ways to define and manipulate cursors to execute SELECT
statements.
%FOUND
%ISOPEN
3 Always returns FALSE for implicit cursors, because Oracle closes the SQL
cursor automatically after executing its associated SQL statement.
%ROWCOUNT
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
+----+----------+-----+-----------+----------+
DECLARE
total_rows number(2);
BEGIN
UPDATE customers
IF sql%notfound THEN
total_rows := sql%rowcount;
END IF;
END;
When the above code is executed at the SQL prompt, it produces the following
result −
6 customers selected
PL/SQL procedure successfully completed.
If you check the records in customers table, you will find that the rows have been
updated –
Select * from customers;
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2500.00 |
| 2 | Khilan | 25 | Delhi | 2000.00 |
| 3 | kaushik | 23 | Kota | 2500.00 |
| 4 | Chaitali | 25 | Mumbai | 7000.00 |
| 5 | Hardik | 27 | Bhopal | 9000.00 |
| 6 | Komal | 22 | MP | 5000.00 |
+----+----------+-----+-----------+----------+
In the following PL/SQL code block, the select statement makes use of an implicit cursor:
Begin
Update emp Where 1=2;
Dbms_output.put_line (sql%rowcount ||’ ‘|| ‘ rows are affected by the update statement’);
End;
The following single-row query calculates and returns the total salary for a department.
PL/SQL creates an implicit cursor for this statement:
DECLARE
rows_deleted NUMBER;
BEGIN
DELETE * FROM emp;
rows_deleted := SQL%ROWCOUNT;
END;
Explicit Cursors
Explicit cursors are programmer-defined cursors for gaining more control over
the context area. An explicit cursor should be defined in the declaration section of
the PL/SQL Block. It is created on a SELECT Statement which returns more than one
row.
CURSOR c_customers IS
OPEN c_customers;
CLOSE c_customers;
Example
Following is a complete example to illustrate the concepts of explicit cursors
DECLARE
c_id customers.id%type;
c_name customerS.No.ame%type;
c_addr customers.address%type;
CURSOR c_customers is
BEGIN
OPEN c_customers;
LOOP
END LOOP;
CLOSE c_customers;
END;
When the above code is executed at the SQL prompt, it produces the following
result −
1 Ramesh Ahmedabad
2 Khilan Delhi
3 kaushik Kota
4 Chaitali Mumbai
5 Hardik Bhopal
6 Komal MP
declare
cursor emp_cursor
is
select id,name,salary,dept_id
from employees;
v_id employees.id%type;
v_name employees.name%type;
v_salary employees.salary%type;
v_dept_id employees.dept_id%type;
begin
open emp_cursor;
loop
fetch emp_cursor into v_id,v_name,v_salary,v_dept_id;
exit when emp_cursor%notfound;
dbms_output.put_line(v_id||', '||v_name||', '||v_salary||','||v_dept_id);
end loop;
close emp_cursor;
end;
Embedded SQL
There are, however, two complications to bear in mind. First, the data types recognized by
SQL may not be recognized by the host language and vice versa. This mismatch is
typically addressed by casting data values appropriately before passing them to or from
SQL commands. The second complication has to do with SQL being set-oriented, and is
addressed using cursors. Commands operate on and produce tables, which are sets.
For example. we can declare variables c-sname, c_sid, c_rating, and c_age (with the
initial c used as a naming convention to emphasize that these are host language
variables) as follows:
We also need some way for SQL to report what went wrong if an error condition
arises when executing an SQL statement. The SQL-92 standard recognizes two special
variables for reporting errors, SQLCODE and SQLSTATE. SQLCODE is defined to return
some negative value when an error condition arises, SQLSTATE associates predefined
values with several common error conditions, thereby introducing some uniformity to how
errors are reported. The appropriate C type for SQLCODE is long and the appropriate C
type for SQLSTATE is char [6] , that is, a character string five characters long.
As a simple example, the following EmbeddedSQL statement inserts a row, whose column
values me based on the values of the host language variables contained in it, into the
Sailors relation:
EXEC SQL
INSERT INTO Sailors VALUES (:c_sname, :csid, :crating, :cage);
The SQLSTATE variable should be checked for errors and exceptions after each
Embedded SQL statement. SQL provides the WHENEVER command to simplify
this tedious task:
The intent is that the value of SQLSTATE should be checked after each Embedded
SQL statement is executed. If SQLERROR is specified and the value of SQLSTATE
indicates an exception, control is transferred to stmt, which is presumably responsible
for error and exception handling. Control is also transferred to stmt.if NOT FOUND is
specified and the value of SQLSTATE is 02000, which denotes NO DATA.
SQLCA (SQL communication area), the definition of SQLCA must be included in the C
program by including the following line:
int main() {
EXEC SQL INCLUDE SQLCA;
EXEC SQL BEGIN DECLARE SECTION;
int OrderID; /* Employee ID (from user) */
int CustID; /* Retrieved customer ID */
char SalesPerson[10] /* Retrieved salesperson name */
char Status[6] /* Retrieved order status */
EXEC SQL END DECLARE SECTION;
query_error:
printf ("SQL error: %ld\n", sqlca->sqlcode);
exit();
bad_number:
printf ("Invalid order number.\n");
exit();
}
2. Cursors
Cursors enable us to examine, in the host language program, a collection of
rows computed by an Embedded SQL statement.
When a query returns multiple rows, you can explicitly define a cursor to
Process beyond the first row returned by the query
Keep track of which row is currently being processed
A major problem in embedding SQL statements in a host language like C is that an
impedance mismatch occurs because SQL operates on set of records, whereas languages
like C do not cleanly support a set-of-records abstraction. The solution is to essentially
provide a mechanism that allows us to retrieve rows one at a time from a relation. This
mechanism is called a cursor.
We can declare a cursor on any relation or on any SQL query (because every query returns
a set of rows). Once a cursor is declared, we can open it (which positions the cursor just
before the first row); fetch the next row; move the cursor (to the next row, to the row after
the next n, to the first row, or to the previous row, etc., by specifying additional parameters
for the FETCH command); or close the cursor. Thus, a cursor essentially allows us to
retrieve the rows in a table by positioning the cursor at a particular row and reading its
contents.
General Options for a Cursor Declaration. Several options can be specified when
declaring a cursor. The general form of a cursor declaration is as follows:
The default is that the query is for retrieval purposes (FOR READ ONLY). If some of the
tuples in the query result are to be updated, we need to specify FOR UPDATE OF
<attribute list> and list the attributes that may be updated. If some tuples are to be deleted,
we need to specify FOR UPDATE without any attributes listed.
The ORDER BY clause orders the tuples so that the FETCH command will fetch
them in the specified order.
You use the CURRENT OF cursor_name clause in a DELETE or UPDATE statement to refer
to the latest row fetched from the named cursor. The cursor must be open and positioned on a
row. If no fetch has been done or if the cursor is not open, the CURRENT OF clause results in
an error and processes no rows.
The FOR UPDATE OF clause is optional when you declare a cursor that is referenced in the
CURRENT OF clause of an UPDATE or DELETE statement. The CURRENT OF clause
signals the precompiler to add a FOR UPDATE clause if necessary
If the keyword INSENSITIVE is specified, the cursor behaves as if it is ranging over a private
copy of the collection of answer rows. Otherwise, and by default, other actions of some
transaction could modify these rows, creating unpredictable behavior. If INSENSITIVE is not
specified, the behavior is implementation dependent in this situation.
A holdable cursor is specified using the WITH HOLD clause, and is not closed when the
transaction is continued.Cursors are usually closed automatically at the end of a transaction,
i.e. when a COMMIT or ROLLBACK (or an implicit termination of the transaction)
occurs. That behavior can be changed if the cursor is declared using the WITH HOLD
clause.
#include <stdio.h>
EXEC SQL
BEGIN DECLARE SECTION;
char deptname[26];
char lname[16];
char fname[11];
EXEC SQL
END DECLARE SECTION;
main ()
{
EXEC SQL
WHENEVER SQLERROR GO TO abend;
EXEC SQL
DECLARE DEPT_EMP CURSOR FOR
SELECT DEPARTMENT, LAST_NAME, FIRST_NAME
FROM DEPARTMENT D, EMPLOYEE E
WHERE D.DEPT_NO = E.DEPT_NO
ORDER BY DEPARTMENT, LAST_NAME, FIRST_NAME;
while (!SQLCODE)
{
printf("%s %s works in the %s department.\n",fname,
lname, deptname);
EXEC SQL
FETCH DEPT_EMP
INTO :deptname, :lname, :fname;
}
EXEC SQL
CLOSE DEPT_EMP;
exit();
abend:
if (SQLCODE)
{
isc_print_sqlerror();
EXEC SQL
ROLLBACK;
EXEC SQL
CLOSE_DEPT_EMP;
EXEC SQL
DISCONNECT ALL;
exit(1)
}
else
{
EXEC SQL
COMMIT;
EXEC SQL
DISCONNECT ALL;
exit()
}
}
Triggers
What are triggers?
Triggers are named PL/SQL blocks which are stored in the database or we can also say that
they are specialized stored programs which execute implicitly when a triggering event occurs
which means we cannot call and execute them directly instead they only get triggered by
events in the database.
1. A DML Statement. For example Update, Insert or Delete, executing on any table of
your database. You can program your trigger to execute either BEFORE or AFTER
executing your DML statement. For example you can create a trigger which will get
fired Before the Update statement. Or you can create a trigger which will get triggered
after the execution of your INSERT DML statement.
2. Next type of triggering statement can be a DDL Statement such as CREATE or
ALTER. These triggers can also be executed either BEFORE or AFTER the execution
of your DDL statement. These triggers are generally used by DBAs for auditing
purposes and they really come in handy when you want to keep an eye on the various
changes on your schema such as who created the object or which user. Just like some
cool spy tricks.
3. A system event. Yes, you can create a trigger on a system event and by system event I
mean shut down or startup of your database.
4. Another type of triggering event can be User Events such as log off or log on onto your
database. You can create a trigger which will either execute before or after the event
and record the information such as time of event occur, the username who created it.
A procedure is executed explicitly from another block via a procedure call with passing
arguments, while a trigger is executed (or fired) implicitly whenever the triggering
event (DML: INSERT, UPDATE, or DELETE) happens, and a trigger doesn't accept
arguments.
Trigger names
Triggers exist in a separate namespace from procedure, package, tables (that share the same
namespace), which means that a trigger can have the same name as a table or procedure.
A triggering event or statement is the SQL statement that causes a trigger to be fired. A
triggering event can be an INSERT, UPDATE, or DELETE statement on a table, a DML event
or a DDL event or system event or a user event
A trigger restriction specifies a Boolean (logical) expression that must be TRUE for the trigger
to fire. The trigger action is not executed if the trigger restriction evaluates to FALSE or
UNKNOWN.
A trigger restriction is an option available for triggers that are fired for each row. Its function
is to control the execution of a trigger conditionally. You specify a trigger restriction using a
WHEN clause.
Trigger Action
A trigger action is the procedure (PL/SQL block) that contains the SQL statements and
PL/SQL code to be executed when a triggering statement is issued and the trigger restriction
evaluates to TRUE.
Similar to stored procedures, a trigger action can contain SQL and PL/SQL statements, define
PL/SQL language constructs (variables, constants, cursors, exceptions, and so on), and call
stored procedures. Additionally, for row trigger, the statements in a trigger action have access
to column values (new and old) of the current row being processed by the trigger. Two
correlation names provide access to the old and new values for each column.
Types of Triggers
There are 5 types of triggers in oracle database in which 3 of them are based on the triggering event which
are discussed in the previous section.
4. Instead-of Trigger
This is a type of trigger which enables you to stop and redirect the performance of a DML statement.
Often this type of trigger helps you in managing the way you write to non-updatable views. You can also
see the application of business rules by INSTEAD OF triggers where they insert, update or delete rows
directly in tables that are defining updatable views. Alternatively, sometimes the INSTEAD OF triggers
are also seen inserting, updating or deleting rows in designated tables that are otherwise unrelated to the
view.
5. Compound triggers
These are multi-tasking triggers that act as both statement as well as row-level triggers when the data is
inserted, updated or deleted from a table. You can capture information at four timing points using this
trigger:
(a) before the firing statement;
(b) prior to change of each row from the firing statement;
(c) post each row changes from the firing statement;
(d) after the firing statement.
All these types of triggers can be used to audit, check, save and replace the values even before they are
changed right when there is a need to take action at the statement as well as row event levels.
Types of triggers
There are two types of triggers in Oracle including row-level triggers and statement-level
triggers
• Statement-level triggers execute once for each transaction. For example, if a single
transaction inserted 500 rows into the Customer table, then a statement-level trigger on that
table would only be executed once.
• Statement-level triggers therefore are not often used for data-related activities; they are
normally used to enforce additional security measures on the types of transactions that may
be performed on a table.
• Statement-level triggers are the default type of triggers created and are identified
by omitting the FOR EACH ROW clause in the CREATE TRIGGER command.
Before and After Triggers
• Since triggers occur because of events, they may be set to occur immediately before or after
those events. The events that execute triggers are database transactions, triggers can be
executed immediately BEFORE or AFTER the statements INSERTs, UPDATEs, DELETEs.
• AFTER row-level triggers are frequently used in auditing applications, since they do not fire
until the row has been modified.
Clearly, there is a great deal of flexibility in the design of a trigger.
• Triggers for multiple INSERT, UPDATE, DELETE commands on a table can be combined
into a single trigger (using OR), provided they are all at the same level (row-level or
statement-level), e.g., INSERT OR UPDATE OR DELETE.
• However, you can not combine BEFORE or AFTER, e.g., BEFORE OR AFTER is illegal.
In a row level trigger, the trigger fires for each related row. And sometimes it is required to know the value
before and after the DML statement.
Oracle has provided two clauses in the RECORD-level trigger to hold these values. We can use these
clauses to refer to the old and new values inside the trigger body.
:NEW – It holds a new value for the columns of the base table/view during the trigger execution
:OLD – It holds old value of the columns of the base table/view during the trigger execution
This clause should be used based on the DML event. Below table will specify which clause is valid for
which DML statement (INSERT/UPDATE/DELETE).
aOn successfully compiling, this trigger will show you a string along with the user name who performed the
“Insert” DML on superheroes table. Thus you check this trigger by Inserting a row in Superheroes table.
On successfully compiling, this trigger will print a user defined string with the username of the user who
updated the row. You can check this trigger by writing an update DML on the superheroes table.
UPDATE superheroes SET SH_NAME = ‘Superman’ WHERE SH_NAME='Ironman';
You can check the working of this trigger by executing a DELETE DML on underlying table which is
superheroes.
RAISE_APPLICATION_ERROR(-2001,’INVALID TIME’);
END IF;
END;
Use an error number between -20,000 and -20,999. Specify a character string up to 2,048 bytes for
your message.
CREATE OR REPLACE TRIGGER chkemp
BEFORE INSERT OR DELETE OR UPDATE ON emp
declare
INVALID_TIME exception;
BEGIN
IF TO_NUMBER(TO_CHAR(SYSDATE,'HH24')) NOT BETWEEN 10 AND 16 THEN
RAISE INVALID_TIME;
END IF;
rollback;
EXCEPTION
WHEN INVALID_TIME THEN
DBMS_OUTPUT.PUT_LINE ('Not correct time for modification of emp');
DBMS_OUTPUT.PUT_LINE (SQLERRM);
DBMS_OUTPUT.PUT_LINE (SQLCODE);
END;
/
A TRIGGER doesn't scale in a cost effective manner .
Data manipulation (INSERT, UPDATE, DELETE) often requires locks on tables, and even on
indexes. That impedes other users access to data. The more code that must execute in the
TRIGGER, the longer the locks are being held, the longer the disruption to other users, the higher
the block/deadlock frequency.
Table Auditing
Table auditing means keeping a track of all the dml activities performed on a specific table of the database for
example which user Inserted, updated or deleted a row from the table and when. It is like spying on the users
who are messing your table’s data.
Example
For the demonstration we will use the table ‘Superheroes’ which we created in the previous tutorial.
Suppose you want to keep an eye on the users who are inserting, updating or deleting data from the
‘Superheroes’ table. Let’s see how we can achieve this. To do so we will need another table in which we can
journal the auditing data entries.
new_name varchar2(30),
old_name varchar2(30),
user_name varchar2(30),
entry_date varchar2(30),
operation varchar2(30)
);
This table sh_audit has 5 columns which will store the auditing information such as the new data inserted or
updated, old data which is updated or deleted from the table, name of the user who did it along with the date
and time, also the type of DML operation performed.
IF INSERTING THEN
INSERT INTO sh_audit (new_name,old_name, user_name, entry_date, operation)
VALUES(:NEW.SH_NAME, Null , v_user, v_date, 'Insert');
Example2:
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
+----+----------+-----+-----------+----------+
DECLARE
sal_diff number;
BEGIN
END;
Triggering a Trigger
Let us perform some DML operations on the CUSTOMERS table. Here is one INSERT
statement, which will create a new record in the table −
Because this is a new record, old salary is not available and the above result comes
as null. Let us now perform one more DML operation on the CUSTOMERS table. The
UPDATE statement will update an existing record in the table −
UPDATE customers
WHERE id = 2;
JDBC Driver is a software component that enables java application to interact with the
database. There are 4 types of JDBC drivers:
The JDBC-ODBC bridge driver uses ODBC driver to connect to the database. The JDBC-
ODBC bridge driver converts JDBC method calls into the ODBC function calls. This is
now discouraged because of thin driver.
Functions:
1. Translates query obtained by JDBC into corresponding ODBC query, which is then
handled by the ODBC driver.
2. Sun provides a JDBC-ODBC Bridge driver. sun.jdbc.odbc.JdbcOdbcDriver. This
driver is native code and not Java, and is closed
source.
3. Client -> JDBC Driver -> ODBC Driver -> Database
4. There is some overhead associated with the translation work to go from JDBC to
ODBC.
Advantages:
o easy to use.
o can be easily connected to any database.
Disadvantages:
o Performance degraded because JDBC method call is converted into the ODBC
function calls.
o The ODBC driver needs to be installed on the client machine.
2) Native-API driver
The Native API driver uses the client-side libraries of the database. The driver converts
JDBC method calls into native calls of the database API. It is not written entirely in java.
Functions:
1. This type of driver converts JDBC calls into calls to the client API for that database.
2. Client -> JDBC Driver -> Vendor Client DB Library -> Database
Advantage:
o performance upgraded than JDBC-ODBC bridge driver.
Disadvantage:
o The Native driver needs to be installed on the each client machine.
o The Vendor client library needs to be installed on client machine.
3) Network Protocol driver
The Network Protocol driver uses middleware (application server) that converts
JDBC calls directly or indirectly into the vendor-specific database protocol. It is fully
written in java.
Functions:
1. Follows a three tier communication approach.
2. Can interface to multiple databases - Not vendor specific.
3. The JDBC Client driver written in java, communicates with a middleware-net-server
using a database independent protocol, and then this net server translates this
request into database commands for that database.
4. Thus the client driver to middleware communication is database independent.
5. Client -> JDBC Driver -> Middleware-Net Server -> Any Database
Advantage:
o No client side library is required because of application server that can
perform many tasks like auditing, load balancing, logging etc.
Disadvantages:
o Network support is required on client machine.
o Requires database-specific coding to be done in the middle tier.
o Maintenance of Network Protocol driver becomes costly because it requires
database-specific coding to be done in the middle tier.
4) Thin driver
The thin driver converts JDBC calls directly into the vendor-specific database
protocol. That is why it is known as thin driver. It is fully written in Java language.
Functions
1. Type 4 drivers are entirely written in Java that communicate directly with a vendor's
database through socket connections. No translation or middleware layers, are
required, improving performance.
2. The driver converts JDBC calls into the vendor-specific database protocol so that
client applications can communicate directly with the database server.
3. Completely implemented in Java to achieve platform independence.
4. e.g include the widely used Oracle thin driver - oracle.jdbc.driver. OracleDriver which
connect to jdbc:oracle:thin URL format.
5. Client Machine -> Native protocol JDBC Driver -> Database server
Advantage:
o Better performance than all other drivers.
o No software is required at client side or server side.
Disadvantage:
At client side, a separate driver is needed for each database.
2. Create a Connection
getConnection() method of DriverManager class is used to create a connection.
Syntax
"jdbc:oracle:thin:@localhost:1521:XE","username","password");
Statement s=con.createStatement();
while(rs.next())
System.out.println(rs.getString(1)+" "+rs.getString(2));
con.close();
Example
Create a table in Oracle Database
create table emp(id number(10),name varchar2(20),salary number(5));
}
}
Output
101 adam 3000
102 abhi 5000
Procedure:
DECLARE
first_number NUMBER;
second_number NUMBER;
BEGIN
first_number := 10;
second_number := 20;
DBMS_OUTPUT.PUT_LINE('First Number = ' || TO_CHAR (first_number));
DBMS_OUTPUT.PUT_LINE('Second Number = ' || TO_CHAR (second_number));
begin
num1:=1000;
num2:=2000;
end;