0% found this document useful (0 votes)
110 views32 pages

Chapter 1

This document provides an overview of PLSQL including its introduction, architecture, data types, variables, conditional and loop statements, stored procedures, and functions. PLSQL extends SQL by adding programming constructs like conditions and loops. It allows developers to write reusable code in the form of stored procedures, functions and triggers. PLSQL code is stored and executed on the database server rather than on the client side.

Uploaded by

Samiksha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
110 views32 pages

Chapter 1

This document provides an overview of PLSQL including its introduction, architecture, data types, variables, conditional and loop statements, stored procedures, and functions. PLSQL extends SQL by adding programming constructs like conditions and loops. It allows developers to write reusable code in the form of stored procedures, functions and triggers. PLSQL code is stored and executed on the database server rather than on the client side.

Uploaded by

Samiksha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 32

Chapter 1 - Relational Database Design Using PLSQL

1.1 Introduction to PLSQL


1.2 PL/PgSqL: Datatypes, Language structure
1.3 Controlling the program flow, conditional statements, loops
1.4 Stored Procedures
1.5 Stored Functions
1.6 Handling Errors and Exceptions
1.7 Cursors
1.8 Triggers

1.1 Introduction to PLSQL:


• PLSQL stands for “Procedural Language extensions to the Structured Query Language”.
• PL/SQL is a combination of SQL along with the procedural features of programming
languages.
• It was developed by Oracle Corporation in the early 90's to enhance the capabilities of
SQL.
• PL/SQL is a completely portable, high-performance transaction-processing language.
• PL/SQL provides a built-in, interpreted and OS independent programming environment.
• PL/SQL can also directly be called from the command-line SQL Plus interface.
• Direct call can also be made from external programming language calls to database.
PLSQL architecture:
1. PLSQL Block:
• This is the component which has the actual PL/SQL code.
• This consists of different sections that divides the code logically.
• It also contains the SQL instruction that used to interact with the database server.
• All the PL/SQL units are treated as PL/SQL blocks, and this is the starting stage of the
architecture which serves as the primary input.
2. PL/SQL Engine:
• PL/SQL engine is the component where the actual processing of the codes takes place.
• PL/SQL engine separates PL/SQL units and SQL part in the input.
• The separated PL/SQL units will be handled by the PL/SQL engine itself.
• The SQL part will be sent to database server where the actual interaction with database
takes place.
• It can be installed in both database server and in the application server.
3. Database Server:
• This is the most important component of Pl/SQL unit which stores the data.
• The PL/SQL engine uses the SQL from PL/SQL units to interact with the database
server.
• It consists of SQL executor which parses the input SQL statements and execute the same.
Difference between SQL and PL/SQL:

SQL PL/SQL

• SQL is a single query that is used to perform • PL/SQL is a block of codes that
DML and DDL operations. used to write the entire program
blocks/ procedure/ function, etc.

• It is declarative, that defines what need to be • PL/SQL is procedural that defines


done, rather than how things need to be done. how the things needs to be done.

• Execute as a single statement. • Execute as a whole block.

• Mainly used to manipulate data. • Mainly used to create an application.


• Interaction with a Database server. • No interaction with the database
server.

• Cannot contain PL/SQL code in it. • It is an extension of SQL, so that it


can contain SQL inside it.

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
Block Structure:
DECLARE --optional
<declarations>
BEGIN --mandatory
<executable statements. At least one executable statement is mandatory>
EXCEPTION --optional
<exception handles>
END; --mandatory
Types of PL/SQL block:
1. 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 start with the keyword 'DECLARE' or 'BEGIN'.
• e.g.
do
$$
BEGIN
raise notice ‘Hello';
END;
$$

2. 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.
• The block structure is same as an anonymous block, except it will never start with the
keyword 'DECLARE'. Instead, it will start with the keyword 'CREATE' which instruct
the compiler to create it as a database object.
• Named blocks are basically of two types:
1. Procedure
2. Function
PL/SQL Comments:
• Program comments are explanatory statements that can be included in the PL/SQL code
that you write and helps anyone reading its source code. All programming languages
allow some form of comments.
• The PL/SQL supports single-line and multi-line comments. All characters available
inside any comment are ignored by the PL/SQL compiler.
• The PL/SQL single-line comments start with the delimiter -- (double hyphen) and
multi-line comments are enclosed by /* and */.
do
$$
-- Start of the block
BEGIN
/* This statement is to display Hello.
raise notice is used to display output screen. */
raise notice 'Hello';
END;
$$
PL/SQL Data types:
1. Numeric: Numeric values on which arithmetic operations are performed.
• smallint - 2 bytes -32768 to +32767
• integer - 4 bytes -2147483648 to +2147483647
• bigint - 8 bytes -9223372036854775808 to 9223372036854775807
• numeric - user-specified precision, exact
• decimal - user-specified precision, exact
2. Monetary Types
money - 8 bytes -92233720368547758.08 to +92233720368547758.07
3. Character Types
• character(n), char(n) - fixed-length, blank padded
• character varying(n), varchar(n) - variable-length with limit
• text - variable unlimited length
Variable Declaration in PL/SQL:
PL/SQL variables must be declared in the declaration section.
Syntax:
variable_name [CONSTANT] datatype [NOT NULL] [:= | DEFAULT initial_value]
e.g.
• sales number(10, 2);
• pi CONSTANT double := 3.1415;
• name varchar(25);
• greetings varchar(20) DEFAULT 'Have a Good Day';

Example:
do
$$
DECLARE
message char(20);
greetings varchar(100);
BEGIN
message := 'Reader ';
greetings := 'Welcome to the World of PL/SQL';
RAISE NOTICE 'Hello % %' ,message,greetings;
END
$$
Conditional Statement:
• IF condition THEN
statements;
END IF;
• IF condition THEN
statements;
ELSE
statements;
END IF;
• IF condition_1 THEN
statements_1
ELSIF condition_2 THEN
statements_2
[ ELSE
else_statements
]
END IF;

Conditional Statement:
Example:
do
$$
DECLARE
n_sales integer := 300000;
n_commission numeric( 10, 2 ) := 0;
BEGIN
IF n_sales > 200000 THEN
n_commission := n_sales * 0.1;
ELSE
n_commission := n_sales * 0.05;
END IF;
RAISE NOTICE 'Commission is %', n_commission;
END
$$

For loop:
Syntax:
FOR index IN lower_bound .. upper_bound
LOOP
statements;
END LOOP;
e.g.
do
$$
BEGIN
FOR counter IN 1..5
LOOP
RAISE NOTICE '%', counter;
END LOOP;
END;
$$

While loop:
Syntax:
WHILE condition
LOOP
statements;
END LOOP;
e.g.
do
$$
DECLARE
n_counter integer := 1;
BEGIN
WHILE n_counter <= 5
LOOP
RAISE NOTICE '%', n_counter;
n_counter := n_counter + 1;
END LOOP;
END;
$$

Stored Procedure:
• PL/SQL is a subprogram that performs a particular task. These subprograms are
combined to form larger programs.
• It is a reusable unit that encapsulates specific business logic of the application.
• It is a named block stored as a schema object in the Postgre Database.
Syntax:
CREATE [OR REPLACE] PROCEDURE procedure_name(parameter_list) AS
'
DECLARE
-- variable declaration
BEGIN
-- stored procedure body
END;
'
language 'plpgsql';

• procedure-name specifies the name of the procedure.


• [OR REPLACE] option allows the modification of an existing procedure.
• Parameters in stored procedures can have the IN and INOUT modes. They cannot have
the OUT mode.
• A stored procedure does not return a value.
• return statement without the expression to stop the stored procedure immediately.
e.g. return;
To return a value from stored procedure use INOUT parameter.

Examples:

1. Write a procedure to set salary of eno 102 as 75000.

CREATE OR REPLACE PROCEDURE updateSal() AS


'
BEGIN
update emp set salary=75000 where eno=102;
END;
'
language 'plpgsql';

To Execute Procedure:
CALL updateSal();

2. Write a procedure to increase the salary of all employees by 7%.

CREATE OR REPLACE PROCEDURE increaseSal() AS


'
BEGIN
update emp set salary=(salary*0.07)+salary;
END;
'
language 'plpgsql';

To Execute Procedure:
CALL increaseSal();

3. Transfer money from one account to another account.

CREATE OR REPLACE PROCEDURE transfer(sender int, receiver int, amount dec) AS


'
BEGIN
-- subtracting the amount from the sender account
update accounts
set balance = balance - amount
where id = sender;
-- adding the amount to the receiver account
update accounts
set balance = balance + amount
where id = receiver;
COMMIT;
END;
'
language 'plpgsql';

To Execute Procedure:
CALL transfer(1,2,3000);

PLSQL supports three parameter modes:


IN, OUT, INOUT. A parameter takes IN is by default if you do not explicitly specified it.
IN – To pass value to Procedure or function
OUT – To return value from function. OUT parameter cannot be used for procedure.
INOUT – To pass an initial value, update the value in the Procedure or function and return it
updated value back.

4. To display sum and multiplication using INOUT parameter. Here X and Y are acting as
input as well as output parameter.
CREATE OR REPLACE PROCEDURE sum_n_product(INOUT x int, INOUT y int) AS $$
BEGIN
IF x < 2 THEN
RAISE WARNING 'information message %', now();
RAISE NOTICE 'information message %', now();
RAISE INFO 'information message %', now();
END IF;
x:= x + y;
y:= x * y;
RAISE NOTICE 'Addition : % Multiplication : % ',x,y;
END;
$$
LANGUAGE plpgsql;

To Execute Procedure:
CALL sum_n_product(6,4);

Argument Variables:
• PL/pgSQL procedure can accept argument variables of different types. Procedure
arguments allow a user to pass information into a procedure, that the procedure may
need.
• Each procedure argument that is received by a procedure is incrementally assigned to an
identifier that begins with the dollar ($) sign and is labeled with the argument number.
• Thus the identifier $1 is used for the first argument, $2 is used for the second argument
and so on an so forth.
• PL/pgSQL allows us to create variable aliases. Aliases are created using the ALIAS
keyword and it gives us the ability to provide an alternate variable to use when
referencing argument variables. All aliases should be declared within the DECLARE
section of a block before they are used.
5. To display count of employees of particular department.

CREATE OR REPLACE PROCEDURE countemp(int) AS


$$
DECLARE
cnt int;
BEGIN
select into cnt count(eno) from emp where dno=$1;
RAISE NOTICE 'Count : %' ,cnt;
END;
$$
LANGUAGE plpgsql;

To call procedure:
CALL countemp(10);

SET B 2:
6. Write a procedure to accept dept and display all employees working in that dept.

CREATE OR REPLACE PROCEDURE displayemp(int) AS $$


DECLARE
emp_rec record;
BEGIN
for emp_rec in(select eno,ename,salary from emp where dno=$1)
loop
RAISE NOTICE ' % % %' , emp_rec.eno,emp_rec.ename,emp_rec.salary;
end loop;
END;
$$
LANGUAGE plpgsql;

To call procedure:
CALL displayemp(10);

OR Using Alias for Arguments

CREATE OR REPLACE PROCEDURE displayemp1(int) AS $$


DECLARE
emp_rec record;
deptno alias for $1;
BEGIN
for emp_rec in(select eno,ename,salary from emp where dno=deptno)
loop
RAISE NOTICE ' % % %' , emp_rec.eno,emp_rec.ename,emp_rec.salary;
end loop;
END;
$$
LANGUAGE plpgsql;

To call procedure:
CALL displayemp1(10);

SET B 1:
7. Write a procedure to insert values in employee table.

CREATE OR REPLACE PROCEDURE insertemp() AS $$


BEGIN
insert into emp values(1, 'Anita',10,45000);
insert into emp values(2, ‘Rajesh',20,42000);
insert into emp values(3, ‘Kiran',10,55000);
END;
$$
LANGUAGE plpgsql;

SET C:
8. Route(route_no, source, destination, no_of_station)
Bus (bus_no, capacity, depot_name, route_no(FK))
Relationship between Route and Bus is one-to-many
Create Route table first and then Bus table by taking route_no in BUS.
Insert atleast 2 Routes and 3 Buses for each route.
1. Display all bus information. Accept route_no as a parameter from user.
2. SQL : update route set source= 'Karve Road' where route_no=101;
Nested Query:
Display details of all bus for destination as 'Kothrud depo'.
select * from emp where dno=(select dno from dept where dname='Sales');

To delete procedure completely from database:


Syntax:
drop procedure procedurename(parameters);
e.g.
drop procedure countemp(int);

1.5 Function:
• It allows to write user defined function.
CREATE [OR REPLACE] FUNCTION function_name(arguments)
RETURNS return_datatype AS
'
DECLARE
--declaration
BEGIN
--function body
RETURN {variable_name | value }
END;
'
language 'plpgsql';
To call function:
select function_name();

Example:
1.
CREATE OR REPLACE FUNCTION sum_n_product1(IN x int,IN y int, OUT sum int, OUT
prod int) AS $$
BEGIN
IF x < 2 THEN
RAISE WARNING 'information message %', now();
RAISE NOTICE 'information message %', now();
RAISE INFO 'information message %', now();
END IF;
sum := x + y;
prod := x * y;
END;
$$
LANGUAGE plpgsql;

To call procedure:
select sum_n_product1(6,4);

2. Function to count number of employees.


CREATE OR REPLACE FUNCTION count_emp()
RETURNS int AS
'
DECLARE
ecnt int;
BEGIN
select into ecnt count(*) from emp;
return ecnt;
END;
'
language 'plpgsql';

Assignment 2 SET B :
• BRANCH (BID INTEGER(PK), BRNAME CHAR (30), BRCITY CHAR (10))
• CUSTOMER (CNO INTEGER(PK), CNAME CHAR (20), CADDR CHAR (35), CITY
CHAR(20))
• LOAN_APPLICATION (LNO INTEGER(PK), LAMTREQUIRED MONEY,
LAMTAPPROVED MONEY, L_DATE DATE)
• TERNARY (BID INTEGER, CNO INTEGER, LNO INTEGER)
Solution:
Create table of BRANCH, CUSTOMER, LOAN_APPLICATION
create table ternary(b_no int reference branch(b_no) on delete cascade on update cascade,c_no
int references customer(c_no) on delete cascade on update cascade,l_no int references
loan_application(l_no) on delete cascade on update cascade, primary key(b_no, c_no, l_no));

Insert the values in Branch, Customer, Loan_Application table. Insert atleast 3 rows in each
table. Insert combinations in Ternary table.
1. Write a function that returns the total number of customers of a particular branch.
( Accept branch name as input parameter.)
-> select from branch where brname=$1;
Select count(cno) from ternary where bid=(select bid from branch where brname=$1);
OR
Select count(cno) from customer where cno in (select cno from ternary where bid=(select bid
from branch where brname=$1);
2. Write a function to find the maximum loan amount approved.
Select max(LAMTAPPROVED) from LOAN_APPLICATION;
3. Create a function which returns the total number of customers who have applied for a loan
more than Rs.100000.
Select count(cno) from customer where cno in (select cno from ternary where lno in(select lno
from loan_application where LAMTREQUIRED > ‘100000’);

Assignment 2 SET D :
Project – Employee Database
Project (pno int(PK), pname char (30), ptype char (20), duration int)
Employee (empno int(PK), ename char (20), joining_date date)
The relationship between Project and Employee is many to many with descriptive attribute
start_date.
create table Project(pno int primary key, pname varchar(30), ptype varchar(30), duration int);
Create table Employee(empno int primary key, ename varchar(20), jdate date);
Create table Proj_Emp(pno int references Project(pno) on delete cascade on update cascade,
empno int Employee(empno) on delete cascade on update cascade, start_date date, primary
key(pno, empno));
Insert the values in Project, Employee and Proj_Emp.

Project – Employee Database


Project
Pno(PK) pname
101 Admission System
102 Flight reservation
Employee
Empno(PK) ename
1001 ‘Anil’
1002 ‘Sachin’
1003 ‘Priya’
Proj_Emp
Pno empno start_date
101 1001
102 1001
101 1002
101 1003

Project – Employee Database


1. Write a stored function to accept project type as an input and display all project names of
that type.
CREATE OR REPLACE FUNCTION displayproj(varchar) RETURNS int AS $$
DECLARE
proj_rec record;
BEGIN
for proj_rec in(Select pname from Project where ptype=$1)
loop
RAISE NOTICE ' % ' , proj_rec.pname;
end loop;
RETURN 1;
END;
$$
LANGUAGE plpgsql;

To call function:
select displayproj(' AI');

2. Write a function which accepts employee name and prints the details of the project which the
employee works on.
Select pno, pname, ptype, duration from project where pno in(Select pno from Proj_Emp where
empno=(Select empno from employee where ename=‘$1’));
OR
Select pno, pname, ptype, duration from project, employee, proj_emp where
project.pno=proj_emp.pno and proj_emp.empno=employee.empno where ename=$1;

CREATE OR REPLACE FUNCTION displayproj1(varchar) RETURNS int AS $$


DECLARE
proj_rec record;
BEGIN
for proj_rec in (Select pno, pname, ptype, duration from project where pno in(Select pno from
Proj_Emp where empno=(Select empno from employee where ename=‘$1’)))
loop
RAISE NOTICE ' % % % % ' , proj_rec.pno, proj_rec.pname, proj_rec.ptype, proj_rec.duration;
end loop;
RETURN 1;
END;
$$
LANGUAGE plpgsql;

To call function:
select displayproj1('Anil');

Function: (Procedure converted to function)


• Example:
CREATE OR REPLACE FUNCTION increaseSal1() RETURNS int AS $$
BEGIN
update emp set salary=(salary*0.07)+salary;
RETURN 1;
END;
$$
language plpgsql;
To Execute Function:
Select increaseSal1();

Attributes:
Database variables or row structure can assigned to attributes using %TYPE or %ROWTYPE
The %TYPE attribute:
It is used to declare a variable with the type of referenced database object.
Syntax:
variable_name table_name.column_name%TYPE;
CREATE OR REPLACE FUNCTION getEmpname(int) RETURNS varchar AS $$
DECLARE
empname emp.ename%TYPE;
BEGIN
Select into empname ename from emp where eno=$1;
RETURN empname;
END;
$$
language plpgsql;

To Execute Function:
Select getEmpname(101);

The %ROWTYPE attribute:


It is used to declare PL/SQL row with the same structure as the row specified during declaration.
It will have exact structure of that table row.
Syntax:
variable_name table_name%ROWTYPE
CREATE OR REPLACE FUNCTION getEmp(int) RETURNS text AS $$
DECLARE
emprec emp%ROWTYPE;
BEGIN
Select into emprec * from emp where eno=$1;
RETURN emprec;
--RETURN emprec.eno||' Name: '|| emprec.ename||' Salary: '|| emprec.salary;
END;
$$
language plpgsql;

To Execute Function:
Select getEmp(101);

RECORD:
• Record variable are similar to ROW variables, but they have no predefined structure.
Their structure depends on the structure of the actual row assigned to them during
SELECT or FOR Command.
• Record is only placeholder and not true datatype.
• Record accepts a row of any table.
Syntax:
variable_name RECORD;

1.6 Handling Errors and Exceptions


• The RAISE statements raise errors and exceptions during a PL/pgSQL function’s
execution.
• Raise statement is also given the level of error it should raise and the string error message
it should send to postgreSQL. The string can also be embedded with variables and
expressions, that one needs to list along with the error message. The percent (%) sign is
used as the place holder for the variables that are inserted into the string.
• Syntax:
RAISE level 'message string' [, identifier [….]];
• RAISE statement’s level are as follows:
• DEBUG
• LOG
• NOTICE
• INFO
• WARNING
• EXCEPTION

• EXCEPTION - Exception level statements send the specified text as an ERROR.


The exception level also causes the current transaction to be aborted.
• Example:
CREATE OR REPLACE FUNCTION raise_demo() RETURNS int AS
$$
DECLARE
n int:=1;
BEGIN
-- raise a debug level message
RAISE DEBUG 'The raise_demo function';
n:= n + 1;
--raise a notice stating the change in value of variable
RAISE NOTICE 'Variable n value is now % . ',n;
--raise a notice stating the change in value of variable
RAISE EXCEPTION 'Variable % changed. Transaction aborted. ',n;
RAISE NOTICE 'Variable n value is now % . ',n;
RETURN 1;
END;
$$
LANGUAGE plpgsql;

• The message is printed as an ERROR, and the transaction is aborted, so the next
RAISE statement isn't executed.
• All messages are not reported back to the client. PostgreSQL only reports the
info, warning, and notice level messages back to the client. This is controlled by
client_min_messages and log_min_messages configuration parameters.

• Raising ERRORS:
• To raise an error, use the exception level after the raise statement. Raise statement
uses the exception level by default. More information can be added while raising
an error by writing,
USING option = expression
The option can be:
MESSAGE: set error message
HINT: provide the hint message so that the root cause of the error is easier to be
discovered.
DETAIL: give detailed information about the error.
ERRCODE: identify the error code, which can be either by condition name or directly
five-character SQLSTATE code that follows SQL standard conventions for SQLSTATE
codes.

• Example:
DO
$$
DECLARE
email varchar(255):='[email protected]';
BEGIN
-- check email for duplicate
-- report duplicate email
RAISE EXCEPTION 'Duplicate email: %', email USING HINT= 'check the email
again';
END $$;
• Example:
To raise exception using SQLSTATE:
DO
$$
BEGIN

--...
RAISE EXCEPTION SQLSTATE '2201B';
END
$$;
OR
DO $$
BEGIN
--...
RAISE EXCEPTION invalid_regular_expression;
END $$;
To check more error codes: https://www.postgresql.org/docs/current/errcodes-
appendix.html

• Trapping Errors: By default any error occurring in PLSQL function aborts execution of the
function. We can trap errors and recover from them using BEGIN and EXCEPTION clause.
• Syntax:
DECLARE
BEGIN
statements;
EXCEPTION
WHEN condition [or condition...] THEN
handle_exception;
[WHEN condition [or condition...] THEN
handle_exception;]
[WHEN others then
handle_other_exceptions;
]
END;


When an error occurs between the BEGIN and EXCEPTION, PL/pgSQL stops
the execution and passes the control to the exception list.
• PL/pgSQL searches for the first condition that matches the occurring error.
• If there is a match, the corresponding handle_exception statements will execute.
PL/pgSQL passes the control to the statement after the END keyword.
• Example:
CREATE OR REPLACE FUNCTION display_emp() RETURNS void AS $$
DECLARE
rec RECORD;
empno int :=60;
BEGIN
SELECT eno, ename INTO strict rec from emp WHERE eno = empno;
RAISE NOTICE '% %',rec.eno, rec.ename;
-- catch exception
/*EXCEPTION
WHEN no_data_found THEN
-- WHEN sqlstate 'P0002' THEN
RAISE EXCEPTION 'Employee % not found', empno;*/
END;
$$
LANGUAGE plpgsql;

• PL/pgSQL searches for the first condition that matches the occurring error.
• If there is a match, the corresponding handle_exception statements will execute.
PL/pgSQL passes the control to the statement after the END keyword.
• Example:
CREATE OR REPLACE FUNCTION count_emp1(int) RETURNS int AS $$
DECLARE
cnt int:=0;
BEGIN
SELECT count(eno) into cnt from emp WHERE dno = $1;
--SELECT into cnt count(eno) from emp WHERE dno = $1;
IF cnt=0 THEN
RAISE EXCEPTION 'Department no is invalid';
END IF;
RETURN cnt;
END;
$$
LANGUAGE plpgsql;
Note: Comment if section and see the result. It will not show any message if dno is
invalid.

1.7 Cursor
• A PL/SQL cursor allows you to encapsulate a query and processing of each individual
row at a time.
• Typically, cursors can be used to divide a large result set into parts and process each part
individually. If you process it at once, you may have a memory overflow error.
• To develop a function that returns a reference to a cursor. This is an effective way to
return a large result set from a function. The caller of the function can process the result
set based on the cursor reference.
• There are two types of cursors:
• Implicit Cursor
• Explicit Cursor
• Implicit Cursor : Implicit cursors are automatically created and managed by PL/pgSQL.
Programmers cannot control the implicit cursors and the information in it.
• Whenever a DML statement (INSERT, UPDATE and DELETE) is issued, an implicit
cursor is associated with this statement. For INSERT operations, the cursor holds the data
that needs to be inserted. For UPDATE and DELETE operations, the cursor identifies the
rows that would be affected.
• 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.

• Explicit Cursor :
• Explicit cursors are declared and managed by the programmer.
• 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.
• Explicit cursors are operations:

1. Declaring cursor variable:


Declare a cursor variable in the declaration section of a block to access to a cursor.
PostgreSQL provides a special datatype called REFCURSOR.
Following are the ways to declare the cursor:
1. DECLARE
my_cursor REFCURSOR;
2. A cursor that bounds to a query by using the following syntax:
cursor_name [ [no] scroll ] CURSOR [( name datatype, name data type, ...)] for query;
Specify a variable name for the cursor. Specify whether the cursor can be scrolled
backward using the SCROLL. If NO SCROLL, the cursor cannot be scrolled backward. Put the
CURSOR keyword followed by a list of comma-separated arguments ( name datatype) that
defines parameters for the query. These arguments will be substituted by values when the cursor
is opened.
Then specify a query following the FOR keyword. Use any valid SELECT statement.
Eg.
DECLARE
cur1 REFCURSOR; /* First Unbounded Cursor */
emplist CURSOR for /* Second Bounded Cursor */
SELECT *
from emp;
emp_sal CURSOR (sal integer) for /* Third Bounded Parameterized Cursor */
SELECT *
FROM emp
WHERE salary = sal;
Third is parameterized cursor as parameter sal will be replaced by an integer parameter
value when the cursor is opened.

2. Opening a cursor:
Cursors must be opened before they can be used to query rows. PostgreSQL provides the
syntax for opening an unbound and bound cursor.
Opening unbound cursors:
Syntax:
OPEN unbound_cursor_variable [ [ NO ] SCROLL ] FOR query;
Unbound cursor variable is not bounded to any query when we declared it, we have to
specify the query when we open it.
OPEN my_cursor FOR SELECT * FROM EMP WHERE address = 'Pune';
PostgreSQL allows you to open a cursor and bound it to a dynamic query.
Syntax:
OPEN unbound_cursor_variable[ [ no ] scroll ]
FOR EXECUTE query_string [USING expression [, ... ] ];
query := 'select * from emp order by $1';
OPEN cur_addr FOR EXECUTE query USING ename;
Opening Bound Cursor:
Bound cursor already bounds to a query when we declared it, so when we open it, we just
need to pass the arguments to the query if necessary.
Syntax:
OPEN cursor_variable[ (name:=value,name:=value,...)]
e.g.
OPEN emplist;
OPEN emp_sal(sal:=35000);
Fetching row:
After opening a cursor we can manipulate it using FETCH, MOVE, UPDATE or
DELETE statement.
Syntax:
FETCH [ direction { FROM| IN} ] cursor_variable INTO target_variable;
The FETCH statement gets the next row from the cursor and assigns it a target_variable,
which could be a record, a row variable, or a comma-separated list of variables. If no more row
found, the target_variable is set to NULL.
By default, a cursor gets the next row if you don’t specify the direction explicitly. The
following is valid for the cursor:
NEXT
LAST
PRIOR
FIRST
ABSOLUTE count
RELATIVE count
FORWARD
BACKWARD
FORWARD and BACKWARD directions are only for cursors declared with SCROLL
option.
Moving the cursor:
Syntax:
move [ direction { from | in } ] cursor_variable;
To move the cursor only without retrieving any row, you use the MOVE statement. The
direction accepts the same value as the FETCH statement.
e.g.
MOVE my_cursor;
MOVE LAST FROM my_cursor;
MOVE RELATIVE -1 from my_cursor;
MOVE FORWARD 3 from my_cursor;
Deleting or updating row:
Once a cursor is positioned, we can delete or update row identifying by the cursor using
DELETE WHERE CURRENT OF or UPDATE WHERE CURRENT OF statement.
Syntax:
update table_name
set column = value, ...
where current of cursor_variable;
delete from table_name
where current of cursor_variable;
e.g.
UPDATE emp
SET salary= sal
where CURRENT OF emp_sal;
Closing of cursor:
The CLOSE statement releases resources or frees up cursor variable to allow it to be
opened again using OPEN statement.
Syntax:
CLOSE cursor_variable;
e.g.
CLOSE my_cursor;
Display all employees using cursor
CREATE OR REPLACE FUNCTION displayemp2() RETURNS int AS $$
DECLARE
empno int;
empname text;
c1 CURSOR FOR select eno,ename from emp; /*c1 is bounded cursor */
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO empno, empname;
EXIT WHEN NOT FOUND;
RAISE NOTICE ' % %' , empno, empname;
END LOOP;
CLOSE c1;
RETURN 1;
END;
$$
LANGUAGE plpgsql;
Assignment 3:
SET A 1
Bus (bus_no int , capacity int , depot_name varchar(20))
Route (route_no int, source varchar(20), destination varchar(20), No_of_stations int)
Route to Bus are related with one to many relationship.
1. Write a stored function using cursor, which will give details of all Buses for route
no 174.
CREATE OR REPLACE FUNCTION displaybus() RETURNS int AS $$
DECLARE
busrec Bus%rowtype;
buscur CURSOR FOR select * from Bus where route_no=174;
BEGIN
OPEN buscur;
LOOP
FETCH buscur INTO busrec;
EXIT WHEN NOT FOUND;
RAISE NOTICE ' % % %' , busrec.bus_no , busrec.capacity,
busrec.dpot_name;
END LOOP;
CLOSE buscur;
RETURN 1;
END;
$$
LANGUAGE plpgsql;
Assignment 3:
SET A 2
2. Write a stored function using cursor, which will give details of all buses on route
from “Station” to “Airport”.
CREATE OR REPLACE FUNCTION displaybus() RETURNS int AS $$
DECLARE
busrec Bus%rowtype;
buscur CURSOR FOR select * from Bus where route_no in (select route_no from
route where source= 'station' and destination= 'airport';
BEGIN
OPEN buscur;
LOOP
FETCH buscur INTO busrec;
EXIT WHEN NOT FOUND;
RAISE NOTICE ' % % %' , busrec.bus_no , busrec.capacity,
busrec.dpot_name;
END LOOP;
CLOSE buscur;
RETURN 1;
END;
$$
LANGUAGE plpgsql;
Assignment 3:
SET B
Teacher( t_no int(PK), t_name varchar(20), age int, yr_experience int)
Subject (s_no int(PK), s_name varchar(15))
Teacher and Subject are related with many to many relationship.
create table teacher(tno int primary key, tname varchar(30), age int, expr int);
create table subject(subno int primary key, sname varchar(30));
create table teach_sub(tno int references teacher(tno) on delete cascade on update
cascade,subno int references subject(subno) on delete cascade on update cascade, primary
key(tno,subno));
postgres=# insert into teacher values(1,'Mr.Amit',45,20);
postgres=# insert into teacher values(2,'Mrs.Pooja',30,6);
postgres=# insert into subject values(111, 'OS');
postgres=# insert into subject values(112, 'TCS');
postgres=# insert into subject values(113, 'DAA');
postgres=# insert into teach_sub values(1, 111);
postgres=# insert into teach_sub values(1, 113);
postgres=# insert into teach_sub values(2, 112);
postgres=# insert into teach_sub values(2, 113);
Assignment 3:
SET B 1
Write a stored function using cursor which will accept the subject name and print
the
names of all teachers teaching that subject.
CREATE OR REPLACE FUNCTION displaytname(varchar) RETURNS void AS $$
DECLARE
teachername teacher.tname%TYPE;
tnamecur CURSOR FOR select tname from teacher where tno in(select tno from
teach_sub where subno=(select subno from subject where sname=$1));
-- OR
-- tnamecur CURSOR FOR select tname from teacher, teach_sub, subject where
teacher.tno=teach_sub.tno and -- teach_sub.subno=subject.subno and sname=$1;
BEGIN
OPEN tnamecur;
LOOP
FETCH tnamecur INTO teachername;
EXIT WHEN NOT FOUND;
RAISE NOTICE ' % ' , teachername;
END LOOP;
CLOSE tnamecur;

END;
$$
LANGUAGE plpgsql;
Assignment 3:
SET B 1 (Same question using parameterized cursor)
CREATE OR REPLACE FUNCTION displaytname(varchar) RETURNS void AS $$
DECLARE
teachername teacher.tname%TYPE;
tnamecur CURSOR(subname varchar(30)) FOR select tname from teacher where
tno in(select tno from teach_sub where subno=(select subno from subject where
sname=subname));
-- OR
-- tnamecur CURSOR FOR select tname from teacher, teach_sub, subject where
teacher.tno=teach_sub.tno and -- teach_sub.subno=subject.subno and sname=subname;
BEGIN
OPEN tnamecur(subname:=$1);
LOOP
FETCH tnamecur INTO teachername;
EXIT WHEN NOT FOUND;
RAISE NOTICE ' % ' , teachername;
END LOOP;
CLOSE tnamecur;

END;
$$
LANGUAGE plpgsql;
Assignment 3:
SET C 1
Write a cursor to accept a month as an input parameter from the user and display
the
names of persons whose birthday falls in that particular month.
CREATE OR REPLACE FUNCTION displaypname(int) RETURNS void AS $$
DECLARE
personname person.pname%TYPE;
pnamecur CURSOR FOR select pname from person where EXTRACT(month
from birthdate)=$1;
BEGIN
OPEN pnamecur;
LOOP
FETCH pnamecur INTO personname;
EXIT WHEN NOT FOUND;
RAISE NOTICE ' % ' , personname;
END LOOP;
CLOSE pnamecur;

END;
$$
LANGUAGE plpgsql;
Assignment 3:
SET C 2
Write a cursor to display the names of persons living in urban area.
CREATE OR REPLACE FUNCTION displaypname1() RETURNS void AS $$
DECLARE
personname person.pname%TYPE;
pnamecur CURSOR FOR select pname from person where aid=(select aid area
where area_type=‘Urban’);
BEGIN
OPEN pnamecur;
LOOP
FETCH pnamecur INTO personname;
EXIT WHEN NOT FOUND;
RAISE NOTICE ' % ' , personname;
END LOOP;
CLOSE pnamecur;

END;
$$
LANGUAGE plpgsql;
1.8 Triggers:
• Triggers are stored programs, which are automatically executed or fired when
some events occur.
• A trigger is a set of actions that are run automatically when operations like Insert,
Delete, Update etc are performed.
• The difference between a trigger and a user-defined function is that a trigger is
automatically invoked when a triggering event occurs, where function needs to be
called explicitly.
• Trigger can be set to fire BEFORE an event occur or AFTER an event occur or
even we can bypass the event by using the INSTEAD OF command.
• There are two types of trigger:
• Row level trigger: It is fired for each affected row.
• Statement level trigger: It is fired only once for a statement.
If 20 rows are affected then row level trigger gets fired for each affected row and
statement level trigger gets fired only once.
Use CREATE OR REPLACE FUNTION with no arguments and return type of trigger.
When PL/SQL function is called as trigger, several variables are created automatically.
1. NEW: Data type RECORD. Variable holding new database row for
INSERT/UPDATE operations in row-level triggers. This variable is NULL in
statement-level triggers for DELETE operations.
2. OLD: Data type RECORD. Variable holding the old database row for
UPDATE/DELETE operations in row-level triggers. This variable is NULL in
statement-level triggers for INSERT operations.
There are many other variables also.
Creating trigger function:
CREATE OR REPLACE FUNCTION function_name() RETURNS TRIGGER AS $$
BEGIN
-- trigger logic
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER trigger_name
{BEFORE | AFTER} { event }
ON table_name
[FOR [EACH] { ROW | STATEMENT }]
EXECUTE PROCEDURE function_name;
Listing Trigger:
We can list down all the triggers in the current database from pg_trigger as :
SELECT * FROM pg_trigger;
Dropping a trigger:
DROP TRIGGER [IF EXISTS] trigger_name
ON table_name [ CASCADE | RESTRICT ];

Creating trigger:
This trigger ensures that any time a row is inserted or updated in the table, the current
user name. And it checks that an employee's name is given and that the salary is a positive value.
CREATE FUNCTION emp_check() RETURNS trigger AS $$
BEGIN
-- Check that empname and salary are given
IF NEW.ename IS NULL THEN
RAISE EXCEPTION 'Employee name cannot be null';
END IF;
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% cannot have null salary', NEW.ename;
END IF;
IF NEW.salary< 0 THEN
RAISE EXCEPTION '% cannot have a negative salary', NEW.ename;
END IF;
RETURN NEW;
END; $$
LANGUAGE plpgsql;
CREATE TRIGGER temp_check BEFORE INSERT OR UPDATE ON emp FOR
EACH ROW EXECUTE PROCEDURE emp_check();
insert into emp values(109, NULL, 'Pune',10,9890983458,50000,'1989-04-30');
insert into emp values(109, NULL, 'Pune',10,9890983458,NULL,'1989-04-30');
insert into emp values(109, NULL, 'Pune',10,9890983458,-50000,'1989-04-30');
Display a proper message after deleting record from table.
CREATE OR REPLACE FUNCTION emp_del() RETURNS trigger AS $$
BEGIN
RAISE NOTICE '% record is deleted', OLD.ename;
RETURN OLD;
END; $$
LANGUAGE plpgsql;
CREATE TRIGGER temp_del AFTER DELETE ON emp FOR EACH ROW
EXECUTE PROCEDURE emp_del();
Delete from emp where eno=109;

You might also like