Cursor and Trigger
Cursor and Trigger
Cursor and Trigger
• Implicit cursors
• Explicit cursors
Implicit Cursors
• Implicit cursors in PL/SQL are automatically created and managed by
the PL/SQL engine for SQL statements like SELECT, INSERT, UPDATE,
DELETE, and others. You don't need to explicitly declare, open, fetch,
or close these cursors. They simplify the code by handling these
operations implicitly.
In PL/SQL, you can refer to the most recent implicit cursor as the SQL
cursor, which always has attributes such as %FOUND, %ISOPEN,
%NOTFOUND, and %ROWCOUNT. The SQL cursor has additional
attributes, %BULK_ROWCOUNT and %BULK_EXCEPTIONS, designed
for use with the FORALL statement. The following table provides the
description of the most used attributes −
%FOUND
%NOTFOUND
%ISOPEN
3 Always returns FALSE for implicit cursors, because Oracle closes the SQL
cursor automatically after executing its associated SQL statement.
%ROWCOUNT
Example
To Print all the students details
declare
v_student_id varchar2(10);
v_student_name VARCHAR2(20);
v_dcontactnumber NUMBER(12);
v_dno number(5);
v_marks number(5);
Begin
LOOP
DBMS_OUTPUT.PUT_LINE('------------------------');
END LOOP;
End;
************************************************************************
We will be using the CUSTOMERS table we had created and used in the
previous chapters.
Select * from customers;
+----+----------+-----+-----------+----------+
| 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 |
+----+----------+-----+-----------+----------+
The following program will update the table and increase the salary of each
customer by 500 and use the SQL%ROWCOUNT attribute to determine the
number of rows affected −
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
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 |
+----+----------+-----+-----------+----------+
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
SELECT id, name, address FROM customers;
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
TRIGGERS
Triggers are stored programs, which are automatically executed or fired when
some events occur. Triggers are, in fact, written to be executed in response
to any of the following events −
Triggers can be defined on the table, view, schema, or database with which
the event is associated.
Benefits of Triggers
Triggers can be written for the following purposes −
• Generating some derived column values automatically
• Maintaining security
Creating Triggers
The syntax for creating a trigger is −
[OF col_name]
ON table_name
WHEN (condition)
DECLARE
Declaration-statements
BEGIN
Executable-statements
EXCEPTION
Exception-handling-statements
END;
Where,
• CREATE [OR REPLACE] TRIGGER trigger_name − Creates or replaces an existing
trigger with the trigger_name.
• {BEFORE | AFTER | INSTEAD OF} − This specifies when the trigger will be
executed. The INSTEAD OF clause is used for creating trigger on a view.
• {INSERT [OR] | UPDATE [OR] | DELETE} − This specifies the DML operation.
• [OF col_name] − This specifies the column name that will be updated.
• [ON table_name] − This specifies the name of the table associated with the
trigger.
• [REFERENCING OLD AS o NEW AS n] − This allows you to refer new and old values
for various DML statements, such as INSERT, UPDATE, and DELETE.
• [FOR EACH ROW] − This specifies a row-level trigger, i.e., the trigger will be
executed for each row being affected. Otherwise the trigger will execute just once
when the SQL statement is executed, which is called a table level trigger.
• WHEN (condition) − This provides a condition for rows for which the trigger would
fire. This clause is valid only for row-level triggers.
Example
To start with, we will be using the CUSTOMERS table we had created and
used in the previous chapters −
Select * from customers;
+----+----------+-----+-----------+----------+
| 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 |
+----+----------+-----+-----------+----------+
The following program creates a row-level trigger for the customers table
that would fire for INSERT or UPDATE or DELETE operations performed on
the CUSTOMERS table. This trigger will display the salary difference between
the old values and new values −
DECLARE
sal_diff number;
BEGIN
END;
When the above code is executed at the SQL prompt, it produces the following
result −
Trigger created.
• OLD and NEW references are not available for table-level triggers, rather you can
use them for record-level triggers.
• If you want to query the table in the same trigger, then you should use the AFTER
keyword, because triggers can query the table or change it again only after the
initial changes are applied and the table is back in a consistent state.
• The above trigger has been written in such a way that it will fire before any DELETE
or INSERT or UPDATE operation on the table, but you can write your trigger on a
single or multiple operations, for example BEFORE DELETE, which will fire
whenever a record will be deleted using the DELETE operation on the table.
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;
• System-defined exceptions
• User-defined exceptions
DECLARE
<declarations section>
BEGIN
<executable command(s)>
EXCEPTION
exception1-handling-statements
exception2-handling-statements
exception3-handling-statements
........
exception3-handling-statements
END;
Example
Let us write a code to illustrate the concept. We will be using the CUSTOMERS
table we had created and used in the previous chapters −
DECLARE
c_id customers.id%type := 8;
c_name customerS.Name%type;
c_addr customers.address%type;
BEGIN
FROM customers
WHERE id = c_id;
dbms_output.put_line('Error!');
END;
When the above code is executed at the SQL prompt, it produces the following
result −
No such customer!
The above program displays the name and address of a customer whose ID
is given. Since there is no customer with ID value 8 in our database, the
program raises the run-time exception NO_DATA_FOUND, which is
captured in the EXCEPTION block.
Raising Exceptions
Exceptions are raised by the database server automatically whenever there
is any internal database error, but exceptions can be raised explicitly by the
programmer by using the command RAISE. Following is the simple syntax
for raising an exception −
DECLARE
exception_name EXCEPTION;
BEGIN
IF condition THEN
RAISE exception_name;
END IF;
EXCEPTION
statement;
END;
You can use the above syntax in raising the Oracle standard exception or any
user-defined exception. In the next section, we will give you an example on
raising a user-defined exception. You can raise the Oracle standard
exceptions in a similar way.
User-defined Exceptions
PL/SQL allows you to define your own exceptions according to the need of
your program. A user-defined exception must be declared and then raised
explicitly, using either a RAISE statement or the
procedure DBMS_STANDARD.RAISE_APPLICATION_ERROR.
Example
The following example illustrates the concept. This program asks for a
customer ID, when the user enters an invalid ID, the exception invalid_id is
raised.
DECLARE
c_name customerS.Name%type;
c_addr customers.address%type;
ex_invalid_id EXCEPTION;
BEGIN
RAISE ex_invalid_id;
ELSE
FROM customers
WHERE id = c_id;
END IF;
EXCEPTION
dbms_output.put_line('Error!');
END;
When the above code is executed at the SQL prompt, it produces the following
result −
Enter value for cc_id: -6 (let's enter a value -6)
old 2: c_id customers.id%type := &cc_id;
new 2: c_id customers.id%type := -6;
ID must be greater than zero!
Pre-defined Exceptions
PL/SQL provides many pre-defined exceptions, which are executed when any
database rule is violated by a program. For example, the predefined
exception NO_DATA_FOUND is raised when a SELECT INTO statement
returns no rows. The following table lists few of the important pre-defined
exceptions −
Oracle
Exception SQLCODE Description
Error
It is raised when a null object is
ACCESS_INTO_NULL 06530 -6530
automatically assigned a value.
• Package specification
Package Specification
The specification is the interface to the package. It just DECLARES the types,
variables, constants, exceptions, cursors, and subprograms that can be
referenced from outside the package. In other words, it contains all
information about the content of the package, but excludes the code for the
subprograms.
All objects placed in the specification are called public objects. Any
subprogram not in the package specification but coded in the package body
is called a private object.
END cust_sal;
When the above code is executed at the SQL prompt, it produces the following
result −
Package created.
Package Body
The package body has the codes for various methods declared in the package
specification and other private declarations, which are hidden from the code
outside the package.
The CREATE PACKAGE BODY Statement is used for creating the package
body. The following code snippet shows the package body declaration for
the cust_sal package created above. I assumed that we already have
CUSTOMERS table created in our database as mentioned in the PL/SQL -
Variables chapter.
c_sal customers.salary%TYPE;
BEGIN
FROM customers
WHERE id = c_id;
END find_sal;
END cust_sal;
When the above code is executed at the SQL prompt, it produces the following
result −
Package body created.
DECLARE
BEGIN
cust_sal.find_sal(code);
END;
When the above code is executed at the SQL prompt, it prompts to enter the
customer ID and when you enter an ID, it displays the corresponding salary
as follows −
Enter value for cc_id: 1
Salary: 3000
Example
The following program provides a more complete package. We will use the
CUSTOMERS table stored in our database with the following records −
Select * from customers;
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 3000.00 |
| 2 | Khilan | 25 | Delhi | 3000.00 |
| 3 | kaushik | 23 | Kota | 3000.00 |
| 4 | Chaitali | 25 | Mumbai | 7500.00 |
| 5 | Hardik | 27 | Bhopal | 9500.00 |
| 6 | Komal | 22 | MP | 5500.00 |
+----+----------+-----+-----------+----------+
-- Adds a customer
c_name customerS.No.ame%type,
c_age customers.age%type,
c_addr customers.address%type,
c_sal customers.salary%type);
-- Removes a customer
PROCEDURE listCustomer;
END c_package;
When the above code is executed at the SQL prompt, it creates the above
package and displays the following result −
Package created.
c_name customerS.No.ame%type,
c_age customers.age%type,
c_addr customers.address%type,
c_sal customers.salary%type)
IS
BEGIN
END addCustomer;
PROCEDURE delCustomer(c_id customers.id%type) IS
BEGIN
WHERE id = c_id;
END delCustomer;
PROCEDURE listCustomer IS
CURSOR c_customers is
BEGIN
name_list.extend;
name_list(counter) := n.name;
END LOOP;
END listCustomer;
END c_package;
The above example makes use of the nested table. We will discuss the
concept of nested table in the next chapter.
When the above code is executed at the SQL prompt, it produces the following
result −
Package body created.
Using The Package
The following program uses the methods declared and defined in the
package c_package.
DECLARE
code customers.id%type:= 8;
BEGIN
c_package.listcustomer;
c_package.delcustomer(code);
c_package.listcustomer;
END;
When the above code is executed at the SQL prompt, it produces the following
result −
Customer(1): Ramesh
Customer(2): Khilan
Customer(3): kaushik
Customer(4): Chaitali
Customer(5): Hardik
Customer(6): Komal
Customer(7): Rajnish
Customer(8): Subham
Customer(1): Ramesh
Customer(2): Khilan
Customer(3): kaushik
Customer(4): Chaitali
Customer(5): Hardik
Customer(6): Komal
Customer(7): Rajnish