Sei sulla pagina 1di 78

Ramanujam

Features of PL/SQL
The PL/SQL programming language was developed by Oracle
Corporation in the late 1980s as procedural extension
language for SQL and the Oracle relational database

 PL/SQL is tightly integrated with SQL.


 It offers extensive error checking.
 It offers numerous data types.
 It offers a variety of programming structures.
 It supports structured programming through functions and
procedures.
 It supports object-oriented programming.
 It supports the development of web applications and server
pages.
Advantages of PL/SQL
 SQL is the standard database language and PL/SQL is strongly integrated
with SQL. PL/SQL supports both static and dynamic SQL. Static SQL
supports DML operations and transaction control from PL/SQL block. In
Dynamic SQL, SQL allows embedding DDL statements in PL/SQL blocks.
 PL/SQL allows sending an entire block of statements to the database at one
time. This reduces network traffic and provides high performance for the
applications.
 PL/SQL gives high productivity to programmers as it can query, transform,
and update data in a database.
 PL/SQL saves time on design and debugging by strong features, such as
exception handling, encapsulation, data hiding, and object-oriented data
types.
 Applications written in PL/SQL are fully portable.
 PL/SQL provides high security level.
 PL/SQL provides access to predefined SQL packages.
 PL/SQL provides support for Object-Oriented Programming.
 PL/SQL provides support for developing Web Applications and Server
Pages.
Architecture of PL/SQL
Basic Syntax
 Declarations
This section starts with the keyword DECLARE. It is an optional
section and defines all variables, cursors, subprograms, and other
elements to be used in the program.
 Executable Commands
This section is enclosed between the keywords BEGIN and END and
it is a mandatory section. It consists of the executable PL/SQL
statements of the program. It should have at least one executable
line of code, which may be just a NULL command to indicate that
nothing should be executed.
 Exception Handling
This section starts with the keyword EXCEPTION. This optional
section contains exception(s) that handle errors in the program.
Basic Syntax
 Every PL/SQL statement ends with a semicolon (;). PL/SQL blocks can be nested within other
PL/SQL blocks using BEGIN and END. Following is the basic structure of a PL/SQL block −
DECLARE
<declarations section>
BEGIN
<executable command(s)>
EXCEPTION
<exception handling>
END;
 The 'Hello World' Example
DECLARE
message varchar2(20):= 'Hello, World!';
BEGIN
dbms_output.put_line(message);
END;
/
PL/SQL Program Units
 PL/SQL block
 Function
 Package
 Package body
 Procedure
 Trigger
 Type
 Type body
Data Types
 Scalar
Single values with no internal components, such as
a NUMBER, DATE, or BOOLEAN.
 Large Object (LOB)
Pointers to large objects that are stored separately from
other data items, such as text, graphic images, video clips,
and sound waveforms.
 Composite
Data items that have internal components that can be
accessed individually. For example, collections and records.
 Reference
 Pointers to other data items.
Variable Declaration in PL/SQL
 Syntax
variable_name [CONSTANT] datatype [NOT
NULL] [:= | DEFAULT initial_value]

Ex:
sales number(10, 2);
pi CONSTANT double precision := 3.1415;
name varchar2(25);
address varchar2(100);
Initializing Variables in PL/SQL
Whenever you declare a variable, PL/SQL assigns
it a default value of NULL. If you want to initialize a
variable with a value other than the NULL value, you
can do so during the declaration, using either of the
following −
 The DEFAULT keyword
 The assignment operator
For example −
counter binary_integer := 0;
greetings varchar2(20) DEFAULT 'Have a Good Day';
Variable Scope in PL/SQL
PL/SQL allows the nesting of blocks, i.e., each program block may contain another inner block. If a variable is declared within an
inner block, it is not accessible to the outer block. However, if a variable is declared and accessible to an outer block, it is also
accessible to all nested inner blocks. There are two types of variable scope −

 Local variables − Variables declared in an inner block and not accessible to outer blocks.
 Global variables − Variables declared in the outermost block or a package.

Following example shows the usage of Local and Global variables in its simple form −
DECLARE
-- Global variables
num1 number := 95;
num2 number := 85;
BEGIN
dbms_output.put_line('Outer Variable num1: ' || num1);
dbms_output.put_line('Outer Variable num2: ' || num2);
DECLARE
-- Local variables
num1 number := 195;
num2 number := 185;
BEGIN
dbms_output.put_line('Inner Variable num1: ' || num1);
dbms_output.put_line('Inner Variable num2: ' || num2);
END;
END;
/
Assigning SQL Query Results to PL/SQL
Variables
DECLARE
c_id customers.id%type := 1;
c_name customers.name%type;
c_addr customers.address%type;
c_sal customers.salary%type;
BEGIN
SELECT name, address, salary INTO c_name, c_addr, c_sal
FROM customers
WHERE id = c_id;
dbms_output.put_line ('Customer ' ||c_name || ' from ' ||
c_addr || ' earns ' || c_sal);
END;
/
PL/SQL Literals
 Numeric Literals
050 78 -14 0 +32767
6.6667 0.0 -12.0 3.14159 +7800.00
6E5 1.0E-8 3.14159e0 -1E38 -9.5e-3
 Character Literals
'A' '%' '9' ' ' 'z' '('
 String Literals
'Hello, world!'
'Tutorials Point'
'19-NOV-12'
 BOOLEAN Literals
TRUE, FALSE, and NULL.
 Date and Time Literals
DATE '1978-12-25';
TIMESTAMP '2012-10-29 12:01:01';
PL/SQL - Operators
 Types of operators −
 Arithmetic operators : +, -, *, /, **
 Relational operators : =, !=, <>,~=, >, <, >=, <=
 Comparison operators : LIKE, BETWEEN, IN, IS NULL
 Logical operators : and, or, not
 The precedence of operators goes as follows: =, <, >, <=, >=, <>, !=, ~=, ^=,
IS NULL, LIKE, BETWEEN, IN.

 ** exponentiation
 +, - identity, negation
 *, / multiplication, division
 +, -, || addition, subtraction, concatenation
 Comparison
 NOT logical negation
 AND conjunction
 OR inclusion
PL/SQL - Conditions
 Syntax

 IF condition THEN S; END IF;


 IF condition THEN S1; ELSE S2; END IF;
 IF condition THEN S1; ELSIF condition THEN S2;
ELSE S3; END IF;
 Nested IF
 IF( boolean_expression 1)THEN
 -- executes when the boolean expression 1 is true
IF(boolean_expression 2) THEN
 -- executes when the boolean expression 2 is true sequence-of-
statements;
 END IF;
 ELSE -- executes when the boolean expression 1 is not true else-
statements;
 END IF;
PL/SQL - Basic Loop Statement
 Syntax
LOOP
Sequence of statements;
END LOOP;

Ex:
DECLARE
x number := 10;
BEGIN
LOOP
dbms_output.put_line(x);
x := x + 10;
IF x > 50 THEN
exit;
END IF;
END LOOP; -- after exit, control resumes here
dbms_output.put_line('After Exit x is: ' || x);
END;
/

exit WHEN x > 50;


PL/SQL - WHILE LOOP Statement
 Syntax
WHILE condition LOOP
sequence_of_statements
END LOOP;
Ex:
DECLARE
a number(2) := 10;
BEGIN
WHILE a < 20 LOOP
dbms_output.put_line('value of a: ' || a);
a := a + 1;
END LOOP;
END;
/
PL/SQL - FOR LOOP Statement
 Syntax
FOR counter IN initial_value .. final_value LOOP sequence_of_statements;
END LOOP;

Ex:
DECLARE
a number(2);
BEGIN
FOR a in 10 .. 20 LOOP
dbms_output.put_line('value of a: ' || a);
END LOOP;
END;
/
Reverse FOR LOOP Statement
DECLARE
a number(2) ;
BEGIN
FOR a IN REVERSE 10 .. 20 LOOP
dbms_output.put_line('value of a: ' || a);
END LOOP;
END; /
PL/SQL - Nested Loops
 Syntax
LOOP
Sequence of statements1
LOOP
Sequence of statements2
END LOOP;
END LOOP;

FOR counter1 IN initial_value1 .. final_value1 LOOP sequence_of_statements1


FOR counter2 IN initial_value2 .. final_value2 LOOP sequence_of_statements2
END LOOP;
END LOOP;

WHILE condition1 LOOP


sequence_of_statements1
WHILE condition2 LOOP
sequence_of_statements2
END LOOP;
END LOOP;
The Loop Control Statements
EXIT statement
The Exit statement completes the loop and control passes
to the statement immediately after the END LOOP.
CONTINUE statement
Causes the loop to skip the remainder of its body and
immediately retest its condition prior to reiterating.
GOTO statement
Transfers control to the labeled statement. Though it is
not advised to use the GOTO statement in your program.
PL/SQL - Records
PL/SQL can handle the following types of records −
 Table-based
 Cursor-based records
 User-defined records
Table-Based Records
The %ROWTYPE attribute enables a programmer to create table-
based and cursorbased records.
DECLARE
customer_rec customers%rowtype;
BEGIN
SELECT * into customer_rec
FROM customers
WHERE id = 5;
dbms_output.put_line('Customer ID: ' || customer_rec.id);
dbms_output.put_line('Customer Name: ' || customer_rec.name);
dbms_output.put_line('Customer Address: ' || customer_rec.address);
dbms_output.put_line('Customer Salary: ' || customer_rec.salary);
END;
/
PL/SQL – Records…
Cursor-Based Records
DECLARE
CURSOR customer_cur is
SELECT id, name, address
FROM customers;
customer_rec customer_cur%rowtype;
BEGIN
OPEN customer_cur; LOOP
FETCH customer_cur into customer_rec;
EXIT WHEN customer_cur%notfound;
DBMS_OUTPUT.put_line(customer_rec.id || ' ' ||
customer_rec.name);
END LOOP;
END;
/
PL/SQL – Records…
User-Defined Records
TYPE type_name IS RECORD
( field_name1 datatype1 [NOT NULL] [:= DEFAULT EXPRESSION],
field_name2 datatype2 [NOT NULL] [:= DEFAULT EXPRESSION],
... field_nameN datatypeN [NOT NULL] [:= DEFAULT EXPRESSION);
record-name type_name;
Ex:
DECLARE TYPE books IS RECORD
(title varchar(50),
author varchar(50),
subject varchar(100),
book_id number);
book1 books;
book2 books;
PL/SQL – Records…
DECLARE
type books is record
(title varchar(50),
author varchar(50),
subject varchar(100),
book_id number);
book1 books;
book2 books;
BEGIN
-- Book 1 specification
book1.title := 'C Programming';
book1.author := 'Nuha Ali ';
book1.subject := 'C Programming Tutorial';
book1.book_id := 6495407;
-- Book 2 specification
book2.title := 'Telecom Billing';
book2.author := 'Zara Ali';
book2.subject := 'Telecom Billing Tutorial';
book2.book_id := 6495700;
-- Print book 1 record
dbms_output.put_line('Book 1 title : '|| book1.title);
dbms_output.put_line('Book 1 author : '|| book1.author);
dbms_output.put_line('Book 1 subject : '|| book1.subject);
dbms_output.put_line('Book 1 book_id : ' || book1.book_id);
-- Print book 2 record
dbms_output.put_line('Book 2 title : '|| book2.title);
dbms_output.put_line('Book 2 author : '|| book2.author);
dbms_output.put_line('Book 2 subject : '|| book2.subject);
dbms_output.put_line('Book 2 book_id : '|| book2.book_id);
END;
/
String Functions
 CONCAT(x, y);
Concatenates the strings x and y and returns the appended string.
 INITCAP(x);
Converts the initial letter of each word in x to uppercase and returns that string.
 INSTR(x, find_string [, start] [, occurrence]);
Searches for find_string in x and returns the position at which it occurs.
 INSTRB(x);
Returns the location of a string within another string, but returns the value in
bytes.
 LENGTH(x);
Returns the number of characters in x.
 LOWER(x);
Converts the letters in x to lowercase and returns that string.
 NVL(x, value);
Returns value if x is null; otherwise, x is returned.
 NVL2(x, value1, value2);
Returns value1 if x is not null; if x is null, value2 is returned.
String Functions….
 REPLACE(x, search_string, replace_string);
Searches x for search_string and replaces it with replace_string.
 RPAD(x, width [, pad_string]);
Pads x to the right.
 RTRIM(x [, trim_string]);
Trims x from the right.
 SUBSTR(x, start [, length]);
Returns a substring of x that begins at the position specified by
start. An optional length for the substring may be supplied.
 TRIM([trim_char FROM) x);
Trims characters from the left and right of x.
 UPPER(x);
Converts the letters in x to uppercase and returns that
string.
String Functions….
DECLARE
greetings varchar2(11) := 'hello world';
BEGIN
dbms_output.put_line(UPPER(greetings));
dbms_output.put_line(LOWER(greetings));
dbms_output.put_line(INITCAP(greetings));
/* retrieve the first character in the string */ dbms_output.put_line (
SUBSTR (greetings, 1, 1));
/* retrieve the last character in the string */ dbms_output.put_line (
SUBSTR (greetings, -1, 1));
/* retrieve five characters, starting from the seventh position. */
dbms_output.put_line ( SUBSTR (greetings, 7, 5));
/* retrieve the remainder of the string, starting from the second position.
*/
dbms_output.put_line ( SUBSTR (greetings, 2));
/* find the location of the first "e" */
dbms_output.put_line ( INSTR (greetings, 'e'));
END; /
String Functions….
DECLARE
greetings varchar2(30) := '......Hello World.....';
BEGIN
dbms_output.put_line(RTRIM(greetings,'.'));
dbms_output.put_line(LTRIM(greetings, '.'));
dbms_output.put_line(TRIM( '.' from greetings));
END;
/
Difference between SUBSTR & INSTR functions
SUBSTR function returns the sub-part identified by numeric values
from the provided string.
Select SUBSTR (‘India is my country’, 1, 4) from dual] will return
“Indi”.
INSTR will return the position number of the sub-string within the
string.
SELECT INSTR (‘India is my country’, ‘a’) from dual] will return 5.
PL/SQL Cursor
A cursor is a pointer to this context area. PL/SQL controls the context
area through a cursor. A cursor is a pointer that points to a result of a
query.
Cursor is a named private area in SQL from which information can be
accessed. They are required to process each row individually for queries
which return multiple rows.
 Implicit cursors
Whenever Oracle executes an SQL statement such as SELECT
INTO, INSERT, UPDATE, and DELETE, it automatically creates an
implicit cursor.
Oracle internally manages the whole execution cycle of implicit cursors
and reveals only the cursor’s information and statuses such
as SQL%ROWCOUNT, SQL%ISOPEN, SQL%FOUND,
and SQL%NOTFOUND.
The implicit cursor is not elegant when the query returns zero or multiple
rows which cause NO_DATA_FOUND or TOO_MANY_ROWS exception
respectively.
PL/SQL Cursor…
 Explicit cursors
An explicit cursor is an SELECT statement declared explicitly
in the declaration section of the current block or a package
specification. For an explicit cursor, you have the control over
its execution cycle from OPEN, FETCH, and CLOSE.
 Declare a cursor
CURSOR cursor_name IS query;
 Open a cursor
OPEN cursor_name;
 Fetch from a cursor
FETCH cursor_name INTO variable_list;
 Closing a cursor
CLOSE cursor_name;
PL/SQL Cursor…
 Explicit Cursor Attributes
 %ISOPEN
This attribute is TRUE if the cursor is open or FALSE if it is not.
 %FOUND
This attribute has four values:
NULL before the first fetch
TRUE if a record was fetched successfully
FALSE if no row returned
INVALID_CURSOR if the cursor is not opened
 %NOTFOUND
This attribute has four values:
NULL before the first fetch
FALSE if a record was fetched successfully
TRUE if no row returned
INVALID_CURSOR if the cursor is not opened
 %ROWCOUNT
The %ROWCOUNT attribute returns the number of rows fetched from the cursor. If
the cursor is not opened, this attribute returns INVALID_CURSOR.
PL/SQL Cursor…
 DECLARE
 l_budget NUMBER := 1000000;
 -- cursor
 CURSOR c_sales IS
 SELECT * FROM sales
 ORDER BY total DESC;
 -- record
 r_sales c_sales%ROWTYPE;
 BEGIN

 -- reset credit limit of all customers
 UPDATE customers SET credit_limit = 0;

 OPEN c_sales;

 LOOP
 FETCH c_sales INTO r_sales;
 EXIT WHEN c_sales%NOTFOUND;

 -- update credit for the current customer
 UPDATE
 customers
 SET
 credit_limit =
 CASE WHEN l_budget > r_sales.credit
 THEN r_sales.credit
 ELSE l_budget
 END
 WHERE
 customer_id = r_sales.customer_id;

 -- reduce the budget for credit limit
 l_budget := l_budget - r_sales.credit;

 DBMS_OUTPUT.PUT_LINE( 'Customer id: ' ||r_sales.customer_id ||
 ' Credit: ' || r_sales.credit || ' Remaining Budget: ' || l_budget );

 -- check the budget
 EXIT WHEN l_budget <= 0;
 END LOOP;

 CLOSE c_sales;
 END;
PL/SQL Cursor FOR LOOP
Syntax 1:
FOR record IN cursor_name
LOOP
process_record_statements;
END LOOP;
Syntax 2:
FOR record IN (select_statement)
LOOP
process_record_statements;
END LOOP;
Ex :
DECLARE
CURSOR c_product
IS
SELECT
product_name, list_price
FROM
products
ORDER BY
list_price DESC;
BEGIN
FOR r_product IN c_product
LOOP
dbms_output.put_line( r_product.product_name || ': $' || r_product.list_price );
END LOOP;
END;
PL/SQL Cursor with Parameters
PL/SQL cursor with parameters to fetch data based on
parameters.
Syntax
CURSOR cursor_name (parameter_list)
IS
cursor_query;
OPEN cursor_name (value_list);
PL/SQL parameterized cursor with default values
CURSOR cursor_name (
parameter_name datatype := default_value,
parameter_name datatype := default_value,
...
) IS
cursor_query;
PL/SQL Cursor with Parameters
DECLARE
r_product products%rowtype;
CURSOR c_product (low_price NUMBER, high_price NUMBER)
IS
SELECT *
FROM products
WHERE list_price BETWEEN low_price AND high_price;
BEGIN
-- show mass products
dbms_output.put_line('Mass products: ');
OPEN c_product(50,100);
LOOP
FETCH c_product INTO r_product;
EXIT WHEN c_product%notfound;
dbms_output.put_line(r_product.product_name || ': ' ||r_product.list_price);
END LOOP;
CLOSE c_product;

-- show luxury products


dbms_output.put_line('Luxury products: ');
OPEN c_product(800,1000);
LOOP
FETCH c_product INTO r_product;
EXIT WHEN c_product%notfound;
dbms_output.put_line(r_product.product_name || ': ' ||r_product.list_price);
END LOOP;
CLOSE c_product;

END;
/
DECLARE
CURSOR c_revenue (in_year NUMBER :=2017 , in_customer_id NUMBER := 1)
IS
SELECT SUM(quantity * unit_price) revenue
FROM order_items
INNER JOIN orders USING (order_id)
WHERE status = 'Shipped' AND EXTRACT( YEAR FROM order_date) = in_year
GROUP BY customer_id
HAVING customer_id = in_customer_id;

r_revenue c_revenue%rowtype;
BEGIN
OPEN c_revenue;
LOOP
FETCH c_revenue INTO r_revenue;
EXIT WHEN c_revenue%notfound;
-- show the revenue
dbms_output.put_line(r_revenue.revenue);
END LOOP;
CLOSE c_revenue;
END;
CURSOR FOR UPDATE
Syntax
CURSOR cursor_name IS
SELECT select_clause
FROM from_clause
WHERE where_clause
FOR UPDATE;
CURSOR cursor_name IS
SELECT select_clause
FROM from_clause
WHERE where_clause
FOR UPDATE OF column_name;

 DECLARE
 -- customer cursor
 CURSOR c_customers IS
 SELECT
 customer_id,
 name,
 credit_limit
 FROM
 customers
 WHERE
 credit_limit > 0
 FOR UPDATE OF credit_limit;
 -- local variables
 l_order_count PLS_INTEGER := 0;
 l_increment PLS_INTEGER := 0;
CURSOR FOR UPDATE…

 BEGIN
 FOR r_customer IN c_customers
 LOOP
 -- get the number of orders of the customer
 SELECT COUNT(*)
 INTO l_order_count
 FROM orders
 WHERE customer_id = r_customer.customer_id;
 --
 IF l_order_count >= 5 THEN
 l_increment := 5;
 ELSIF l_order_count < 5 AND l_order_count >=2 THEN
 l_increment := 2;
 ELSIF l_increment = 1 THEN
 l_increment := 1;
 ELSE
 l_increment := 0;
 END IF;

 IF l_increment > 0 THEN
 -- update the credit limit
 UPDATE
 customers
 SET
 credit_limit = credit_limit * ( 1 + l_increment/ 100)
 WHERE
 customer_id = r_customer.customer_id;

 -- show the customers whose credits are increased
 dbms_output.put_line('Increase credit for customer '
 || r_customer.NAME || ' by '
 || l_increment || '%' );
 END IF;
 END LOOP;

 EXCEPTION
 WHEN OTHERS THEN
 dbms_output.put_line('Error code:' || SQLCODE);
 dbms_output.put_line('Error message:' || sqlerrm);
 RAISE;

 END;
 /
PL/SQL Exception
Syntax:
BEGIN
-- executable section
...
-- exception-handling section
EXCEPTION
WHEN e1 THEN
-- exception_handler1
WHEN e2 THEN
-- exception_handler1
WHEN OTHERS THEN
-- other_exception_handler
END;
PL/SQL Exception
DECLARE
l_name customers.NAME%TYPE;
l_customer_id customers.customer_id%TYPE := &customer_id;
BEGIN
-- get the customer name by id
SELECT name INTO l_name
FROM customers
WHERE customer_id = l_customer_id;

-- show the customer name


dbms_output.put_line('Customer name is ' || l_name);

END;
/
PL/SQL Exception…
DECLARE
l_name customers.NAME%TYPE;
l_customer_id customers.customer_id%TYPE := &customer_id;
BEGIN
-- get the customer
SELECT NAME INTO l_name
FROM customers
WHERE customer_id = l_customer_id;

-- show the customer name


dbms_output.put_line('customer name is ' || l_name);

EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('Customer ' || l_customer_id || ' does not exist');
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line('The database returns more than one customer');
END;
/
PL/SQL Procedure
PL/SQL procedure syntax
A PL/SQL procedure is a reusable unit that encapsulates
specific business logic of the application. Technically
speaking, a PL/SQL procedure is a named block stored as a
schema object in the Oracle Database.
CREATE [OR REPLACE ] PROCEDURE procedure_name (pa
rameter_list)
IS
[declaration statements]
BEGIN
[execution statements]
EXCEPTION
[exception handler]
END [procedure_name ];
PL/SQL Procedure…
How to pass parameters to Procedures and Functions in
PL/SQL?
1) IN type parameter: These types of parameters are
used to send values to stored procedures.
2) OUT type parameter: These types of parameters are
used to get values from stored procedures. This is similar
to a return type in functions.
3) IN OUT parameter: These types of parameters are
used to send values and get values from stored
procedures.
NOTE: If a parameter is not explicitly defined a
parameter type, then by default it is an IN type
parameter.
PL/SQL Procedure…
Let’s create a procedure which gets the name of the
employee when the employee id is passed.
CREATE OR REPLACE PROCEDURE emp_name (id IN
NUMBER, emp_name OUT NUMBER)
IS
BEGIN
SELECT first_name INTO emp_name
FROM emp_tbl WHERE empID = id;
END;
/
PL/SQL Procedure…
We can call the procedure ‘emp_name’ in this way from a
PL/SQL Block.
DECLARE
empName varchar(20);
CURSOR id_cur SELECT id FROM emp_ids;
BEGIN
FOR emp_rec in id_cur
LOOP
emp_name(emp_rec.id, empName);
dbms_output.putline('The employee ' || empName || ' has id
' || emp-rec.id);
END LOOP;
END;
/
PL/SQL Procedure…
Using IN OUT parameter in procedures:
CREATE OR REPLACE PROCEDURE emp_salary_increase
(emp_id IN emptbl.empID%type, salary_inc IN OUT
emptbl.salary%type)
IS
tmp_sal number;
BEGIN
SELECT salary INTO tmp_sal FROM emp_tblWHERE empID = emp_id;
IF tmp_sal between 10000 and 20000 THEN 11> salary_inout := tmp_sal *
1.2;
ELSIF tmp_sal between 20000 and 30000 THEN
salary_inout := tmp_sal * 1.3;
ELSIF tmp_sal > 30000 THEN
salary_inout := tmp_sal * 1.4;
END IF;
END;
/
PL/SQL Procedure…
The below PL/SQL block shows how to execute the above
'emp_salary_increase' procedure.
DECLARE
CURSOR updated_sal is
SELECT empID,salary FROM emp_tbl;
pre_sal number;
BEGIN
FOR emp_rec IN updated_sal LOOP
pre_sal := emp_rec.salary;
emp_salary_increase(emp_rec.empID, emp_rec.salary);
dbms_output.put_line('The salary of ' || emp_rec.empID || '
increased from '|| pre_sal || ' to '||emp_rec.salary);
END LOOP;
END;
/
PL/SQL Function
Similar to a procedure, a PL/SQL function is a reusable program unit stored as a schema object in the Oracle Database.
CREATE [OR REPLACE] FUNCTION function_name (parameter_list)
RETURN return_type
IS
[declarative section]
BEGIN
[executable section]
[EXCEPTION]
[exception-handling section]
END;

CREATE OR REPLACE FUNCTION get_total_sales(


in_year PLS_INTEGER
)
RETURN NUMBER
IS
l_total_sales NUMBER := 0;
BEGIN
-- get total sales
SELECT SUM(unit_price * quantity)
INTO l_total_sales
FROM order_items
INNER JOIN orders USING (order_id)
WHERE status = 'Shipped'
GROUP BY EXTRACT(YEAR FROM order_date)
HAVING EXTRACT(YEAR FROM order_date) = in_year;

-- return the total sales


RETURN l_total_sales;
END;
PL/SQL Function…
 in an assignment statement:
DECLARE
l_sales_2017 NUMBER := 0;
BEGIN
l_sales_2017 := get_total_sales (2017);
DBMS_OUTPUT.PUT_LINE('Sales 2017: ' || l_sales_2017);
END;
in a Boolean expression
BEGIN
IF get_total_sales (2017) > 10000000 THEN
DBMS_OUTPUT.PUT_LINE('Sales 2017 is above target');
END IF;
END;
 in an SQL statement
SELECT
get_total_sales(2017)
FROM
dual;
Difference of Procedure & Function
 Stored Procedures are pre-compiled objects which are
compiled for the first time and its compiled format is
saved, which executes (compiled code) whenever it is
called.A stored procedure is a set of SQL statements
that are written to perform a specific task. These
statements can be saved as a group in the database
with an assigned name and can be shared with
different programs if permissions are there to access
the same.
 A function is compiled and executed every time
whenever it is called. A function must return a
value. Functions are again subprograms that are
written to perform specific tasks but there are
differences between both of them.
Difference of Procedure & Function
Functions Stored procedures
Functions must always return a Stored procedures do not have this
value. requirement.
Functions cannot alter data or Stored procedures can alter data and objects in
objects in a server. database and server.

You can embed functions within a Stored procedures cannot be embedded within
SELECT statement. a SELECT statement.

Both functions and stored


procedures can accept
Stored procedures can also accept OUTPUT
parameters. Functions can accept
parameters.
input parameters but can return
only a single return value.

TEMP tables can’t be used in Both TEMP tables and Table variables can be
functions. used in stored procedures.
PL/SQL Cursor Variables with REF
CURSOR
 A cursor variable is a variable that references to a cursor.
Different from implicit and explicit cursors, a cursor
variable is not tied to any specific query. Meaning that a
cursor variable can be opened for any query.
 The most important benefit of a cursor variable is that it
enables passing the result of a query between PL/SQL
programs. Without a cursor variable, you have to fetch all
data from a cursor, store it in a variable e.g., a collection,
and pass this variable as an argument. With a cursor
variable, you simply pass the reference to that cursor.
 To declare a cursor variable, you use the REF CURSOR is
the data type. PL/SQL has two forms of REF
CURSOR types: strong typed and weak typed REF
CURSOR.
PL/SQL Cursor Variables with REF
CURSOR
 Example of a strong REF CURSOR.
DECLARE
TYPE customer_t IS REF CURSOR RETURN customers%ROWT
YPE;
c_customer customer_t;
 Example of a weak typed REF CURSOR declaration that is not
associated with any specific structure:
DECLARE
TYPE customer_t IS REF CURSOR;
c_customer customer_t;
Starting from Oracle 9i, you can use SYS_REFCURSOR, which is a
predefined weak typed REF CURSOR, to declare a weak REF CURS
OR
DECLARE
c_customer SYS_REFCURSOR;
PL/SQL Cursor Variables with REF
CURSOR
CREATE OR REPLACE FUNCTION get_direct_reports(
in_manager_id IN employees.manager_id%TYPE)
RETURN SYS_REFCURSOR
AS
c_direct_reports SYS_REFCURSOR;
BEGIN

OPEN c_direct_reports FOR


SELECT
employee_id,
first_name,
last_name,
email
FROM
employees
WHERE
manager_id = in_manager_id
ORDER BY
first_name,
last_name;

RETURN c_direct_reports;
END;
PL/SQL Cursor Variables with REF
CURSOR
anonymous block calls the get_direct_reports() function and processes the cursor variable to display the direct reports of the manager with id of
46.
DECLARE
c_direct_reports SYS_REFCURSOR;
l_employee_id employees.employee_id%TYPE;
l_first_name employees.first_name%TYPE;
l_last_name employees.last_name%TYPE;
l_email employees.email%TYPE;
BEGIN
-- get the ref cursor from function
c_direct_reports := get_direct_reports(46);

-- process each employee


LOOP
FETCH
c_direct_reports
INTO
l_employee_id,
l_first_name,
l_last_name,
l_email;
EXIT
WHEN c_direct_reports%notfound;
dbms_output.put_line(l_first_name || ' ' || l_last_name || ' - ' || l_email );
END LOOP;
-- close the cursor
CLOSE c_direct_reports;
END;
/
In Oracle PL/SQL : PRAGMA
In Oracle PL/SQL, PRAGMA refers to a compiler directive or "hint" it is used to
provide an instruction to the compiler. The directive restricts member subprograms to
query or modify database tables and packaged variables. Pragma directives are
processed at compile time where they pass necessary information to the compiler; they
are not processed at runtime.
The 5 types of Pragma directives available in Oracle
 PRAGMA AUTONOMOUS_TRANSACTION: This pragma can perform an
autonomous transaction within a PL/SQL block between a BEGIN and END
statement without affecting the entire transaction.

PRAGMA SERIALLY_REUSABLE: This directive tels Oracle that the package state
is needed only for the duration of one call to the server. After the call is made the
package may be unloaded to reclaim memory.

PRAGMA RESTRICT_REFRENCES: Defines the purity level of a packaged
program. After Oracle8i this is no longer required.

PRAGMA EXCEPTION_INIT: This directive binds a user defined exception to a
particular error number.

PRAGMA INLINE: (Introduced in Oracle 11g) This directive specifies that a
subprogram call either is or is not to be inlined. Inlining replaces a subprogram call
with a copy of the called subprogram.
In Oracle PL/SQL : PRAGMA
Syntax
CREATE OR REPLACE [FUNCTION | PROCEDURE]
[NAME] IS
IS
[PRAGMA];
BEGIN
...
...
END;
Note that PRAGMA resides in the Declarative
section of a PL/SQL block.
PRAGMA
AUTONOMOUS_TRANSACTION
The procedure P_ERR_LOG uses the PRAGMA
AUTONOMOUS_TRANSACTION directive to capture the
error occuring in a program unit.

CREATE OR REPLACE PROCEDURE P_ERR_LOG (P_UNIT


VARCHAR2, P_SQLCODE NUMBER, P_SQLERRM
VARCHAR2)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO ERR_TABLE
VALUES (P_UNIT, P_SQLCODE, P_SQLERRM);
COMMIT;
END;
PL/SQL PRAGMA EXCEPTION_INIT
pragma EXCEPTION_INIT: Pragma is a keyword
directive to execute proceed at compile time. pragma
EXCEPTION_INIT function take this two argument,
 exception_name
 error_number
You can define pragrma EXCEPTION_INIT in DECLARE
BLOCK on your program.
 PRAGMA EXCEPTION_INIT(exception_name, -
error_number);
exception_name and error_number define on yourself,
where exception_name is character string up to 2048
bytes suppot and error_number is a negative integer
range from -20000 to -20999.
PL/SQL PRAGMA EXCEPTION_INIT
Syntax
DECLARE
user_define_exception_name EXCEPTION;
PRAGMA EXCEPTION_INIT(user_define_exception_name, -
error_number);
BEGIN
statement(s);
IF condition THEN
RAISE user_define_exception_name;
END IF;
EXCEPTION
WHEN user_define_exception_name THEN
User defined statement (action) will be taken;
END;
PL/SQL PRAGMA EXCEPTION_INIT
DECLARE
myex EXCEPTION;
PRAGMA EXCEPTION_INIT(myex,-20015);
n NUMBER := &n;
BEGIN
FOR i IN 1..n LOOP
dbms_output.put.line(i);
IF i=n THEN
RAISE myex;
END IF;
END LOOP;
EXCEPTION
WHEN myex THEN
dbms_output.put.line('loop finish');
END;
/
PRAGMA SERIALLY_REUSABLE
The SERIALLY_REUSABLE Pragma specifies that the package state is needed for only one
call to the server After this call, the storage for the package variables can be reused, reducing
the memory overhead for long-running sessions.
Why Serially Reusable Packages?
Since the state of a non-reusable package persists for the lifetime of the session, this locks up
UGA memory for the whole session. In applications such as Oracle Office a log-on session
can typically exist for days together. Applications often need to use certain packages only for
certain localized periods in the session and would ideally like to de-instantiate the package
state in the middle of the session once they are done using the package.
Create two packages with & without SERIALLY_REUSABLE
sql_11g> create or replace package without_serially_reusable_pkg as
2 v_without_sr int := 0;
3 end;
4 /
Package created.

sql_11g> create or replace package with_serially_reusable_pkg as


2 pragma serially_reusable;
3 v_with_sr int := 0;
4 end;
5 /
Package created.
PRAGMA SERIALLY_REUSABLE…
Now, let us assign values to packaged variables

sql_11g> begin
2 without_serially_reusable_pkg.v_without_sr := 100;
3 with_serially_reusable_pkg.v_with_sr := 100;
4 end;
5 /
PL/SQL procedure successfully completed.

Now, let us display the values of packaged variables


sql_11g> begin
2 dbms_output.put_line ('without_serially_reusable_pkg.v_without_sr value is -> ' || without_serially_reusable_pkg.v_without_sr );

3 dbms_output.put_line ('with_serially_reusable_pkg.v_with_sr values is ->' || with_serially_reusable_pkg.v_with_sr );


4 end;
5 /

without_serially_reusable_pkg.v_without_sr value is -> 100


with_serially_reusable_pkg.v_with_sr values is ->0

PL/SQL procedure successfully completed.

with_serially_reusable_pkg.v_with_sr is showing 0 because the package is marked as serially_reusable which resets the packaged variable global values to default
immediately after its call.
Now, clubbing assignment of variables & displaying the values of variables in single plsql block.

sql_11g> begin
2 without_serially_reusable_pkg.v_without_sr := 100;
3 with_serially_reusable_pkg.v_with_sr := 100;
4 dbms_output.put_line ('without_serially_reusable_pkg.v_without_sr value is -> ' || without_serially_reusable_pkg.v_without_sr );
5 dbms_output.put_line ('with_serially_reusable_pkg.v_with_sr values is ->' || with_serially_reusable_pkg.v_with_sr );
6 end;
7 /

without_serially_reusable_pkg.v_without_sr value is -> 100


with_serially_reusable_pkg.v_with_sr values is ->100
PL/SQL procedure successfully completed.
PRAGMA RESTRICT_REFERENCES
PRAGMA RESTRICT_REFERENCES uses to control the side effects of PL/SQL
Subprograms. Every PL/SQL Subprograms must follow some rules in terms of
transaction control and security.
CREATE OR REPLACE PACKAGE pkg_salary
IS
function get_emp_salary(p_empno integer) return number;
PRAGMA restrict_references(get_emp_salary, RNDS, RNPS, WNDS, WNPS);
END pkg_salary;
RNDS – Read No Database State. Asserts that the function not to read or query
tables
RNDS – Read No Package State. Asserts that the function not to read or reference
package variables
WNDS – Write No Database State. Asserts that the function not modify database
tables
WNPS – Write No Package State. Asserts that the function not modify package
variables
In the above example Function get_emp_salary is associated with PRAGMA
restrict_references. Oracle conveying the compiler to follow four rules WNDS,
WNPS, RNDS, RNPS. When the package body compiles and find any rules which
violates any of the rules (RNDS, RNPS, WNDS, WNPS, TRUST) it will raise a
compilation error. Note that if there is a PRAGMA derivative and violates any rules
it will NOT raise any compiler error and it might raise run time error.
PRAGMA RESTRICT_REFERENCES…
Ex:
CREATE OR REPLACE PACKAGE pkg_salary
IS
function get_emp_salary(p_empno integer) return number;
END pkg_salary;
/
CREATE OR REPLACE PACKAGE body pkg_salary
IS
function get_emp_salary(p_empno integer) return number
is
n_sal number;
Begin
update emp set salary = salary + salary * 0.1 where empno = p_empno
returning salary into n_sal;
commit;
return n_sal;
End get_emp_salary;
END pkg_salary;
/
Compiling……..
SQL> ../pkg_salary.sql;
Package created.
Package body created.
Executing………
SQL> select pkg_salary.get_emp_salary(10) from dual;
select pkg_salary.get_emp_salary(10) from dual
*
ERROR at line 1:
ORA-14551: cannot perform a DML operation inside a query
So package specification and body compiled properly but unable to use it as it raise error while executing.
PRAGMA RESTRICT_REFERENCES…
2) Function to raise employee salary – With PRAGMA restrict_references
CREATE OR REPLACE PACKAGE pkg_salary
IS
function get_emp_salary(p_empno integer) return number;
PRAGMA restrict_references(get_emp_salary, WNDS);
END pkg_salary;
/
CREATE OR REPLACE PACKAGE body pkg_salary
IS
function get_emp_salary(p_empno integer) return number
is
n_sal number;
Begin
update emp set salary = salary + salary * 0.1 where empno = p_empno
returning salary into n_sal;
commit;
return n_sal;
End get_emp_salary;
END pkg_salary;
/
Compiling……..
SQL> ../pkg_salary.sql;
Package created.
Warning: Package Body created with compilation errors.
SQL> show err
Errors for PACKAGE BODY PKG_SALARY:
LINE/COL ERROR
——– —————————————————————–
4/1 PLS-00452: Subprogram ‘GET_EMP_SALARY’ violates its associated
pragma
When we use PRAGMA restrict_references it raises a compiler error which helps developer to re-write his code.
Generally PRAGMA restrict_references are used with functions.
Note:-
DEFAULT key word applies PRAGMA restrict_references to all of the sub programs in side the package
See below example
CREATE OR REPLACE PACKAGE pkg_salary
IS
function get_emp_salary(p_empno integer) return number;
function get_emp_name(p_empno integer) return varchar2;
PRAGMA restrict_references(DEFAULT, WNDS);
END pkg_salary;
/
Package created.
Note:- Normally functions are not created for DML related processes and PRAGMA restrict_references are not necessary.
PL/SQL Raise Exceptions
How to use the PL/SQL RAISE statement to raise a user-defined
exception, internally defined exception, and reraising an exception.
 Raise a user-defined exception.
 Raise an internally defined exception.
 Reraising the current exception.
Declaring a user-defined exception
DECLARE
exception_name EXCEPTION;
BEGIN
IF condition THEN
RAISE exception_name;
END IF;
EXCEPTION
WHEN exception_name THEN
statement;
END;
PL/SQL User-Defined Exceptions…
DECLARE
e_credit_too_high EXCEPTION;
PRAGMA exception_init( e_credit_too_high, -20001 );
l_max_credit customers.credit_limit%TYPE;
l_customer_id customers.customer_id%TYPE := &customer_id;
l_credit customers.credit_limit%TYPE := &credit_limit;
BEGIN
-- get the meax credit limit
SELECT MAX(credit_limit)
INTO l_max_credit
FROM customers;

-- check if input credit is greater than the max credit


IF l_credit > l_max_credit THEN
RAISE e_credit_too_high;
END IF;

-- if not, update credit limit


UPDATE customers
SET credit_limit = l_credit
WHERE customer_id = l_customer_id;

COMMIT;
END;/
Raising an internally defined
exception
Typically, the runtime system raises internally defined exceptions i
mplicitly when they occur. Besides, you can explicitly raise an inter
nally defined exception with the RAISE statement if the exception
has a name:

DECLARE
l_customer_id customers.customer_id%TYPE := &customer_id;
BEGIN
-- get the meax credit limit
IF l_customer_id < 0 THEN
RAISE invalid_number;
END IF;
END;
/
Reraising the current exception
DECLARE
e_credit_too_high EXCEPTION;
PRAGMA exception_init( e_credit_too_high, -20001 );
l_max_credit customers.credit_limit%TYPE;
l_customer_id customers.customer_id%TYPE := &customer_id;
l_credit customers.credit_limit%TYPE := &credit_limit;
BEGIN
BEGIN
-- get the max credit limit
SELECT MAX(credit_limit)
INTO l_max_credit
FROM customers;

-- check if input credit is greater than the max credit


IF l_credit > l_max_credit THEN
RAISE e_credit_too_high;
END IF;
EXCEPTION
WHEN e_credit_too_high THEN
dbms_output.put_line('The credit is too high' || l_credit);
RAISE; -- reraise the exception
END;
EXCEPTION
WHEN e_credit_too_high THEN
-- get average credit limit
SELECT avg(credit_limit)
into l_credit
from customers;

-- adjust the credit limit to the average


dbms_output.put_line('Adjusted credit to ' || l_credit);

-- update credit limit


UPDATE customers
SET credit_limit = l_credit
WHERE customer_id = l_customer_id;

COMMIT;
END;
/
PL/SQL Exception Propagation
 When an exception occurs, PL/SQL looks for an exception
handler in the current block e.g., anonymous
block, procedure, or function of the exception. If it does
not find a match, PL/SQL propagates the exception to the
enclosing block of the current block.
 PL/SQL then attempts to handle the exception by raising it
once more in the enclosing block. This process continues
in each successive enclosing block until there is no
remaining block in which to raise the exception. If there is
no exception handler in all blocks, PL/SQL returns an
unhandled exception to the application environment that
executed the outermost PL/SQL block.
 Note that an unhandled exception stops the execution of
the block.
PL/SQL Exception Propagation…
DECLARE
e1 EXCEPTION;
PRAGMA exception_init (e1, -20001);
e2 EXCEPTION;
PRAGMA exception_init (e2, -20002);
e3 EXCEPTION;
PRAGMA exception_init (e2, -20003);
l_input NUMBER := &input_number;
BEGIN
-- inner block
BEGIN
IF l_input = 1 THEN
raise_application_error(-20001,'Exception: the input number is 1');
ELSIF l_input = 2 THEN
raise_application_error(-20002,'Exception: the input number is 2');
ELSE
raise_application_error(-20003,'Exception: the input number is not 1 or 2');
END IF;
-- exception handling of the inner block
EXCEPTION
WHEN e1 THEN
dbms_output.put_line('Handle exception when the input number is 1');
END;
-- exception handling of the outer block
EXCEPTION
WHEN e2 THEN
dbms_output.put_line('Handle exception when the input number is 2');
END;
/
Pre-defined Exceptions
Differentiate between Syntax and
runtime errors
 A syntax error can be easily detected by a PL/SQL
compiler. For eg, incorrect spelling.
 A runtime error is handled with the help of exception-
handling section in an PL/SQL block. For eg, SELECT
INTO statement, which does not return any rows.
SQLCODE and SQLERRM
 SQLCODE returns the value of the number of error for
the last encountered error whereas SQLERRM returns
the message for the last error.
PL/SQL Packages
PL/SQL Packages is schema object and collection of related data type (variables,
constants), cursors, procedures, functions are defining within a single context.
Package are divide into two part,
 Package Specification
 Package Body
Package specification block you can define variables, constants, exceptions and
package body you can create procedure, function, subprogram.

PL/SQL Package Advantages


 You can create package to store all related functions and procedures are
grouped together into single unit called packages.
 Package are reliable to granting a privileges.
 All function and procedure within a package can share variable among them.
 Package are support overloading to overload functions and procedures.
 Package are improve the performance to loading the multiple object into
memory at once, therefore, subsequent calls to related program doesn't
required to calling physically I/O.
 Package are reduce the traffic because all block execute all at once.
PL/SQL Packages…
PL/SQL Package Syntax
PL/SQL Specification: This contain the list of variables, constants,
functions, procedure names which are the part of the package. PL/SQL
specification are public declaration and visible to a program.
CREATE [OR REPLACE] PACKAGE package_name
IS | AS
[variable_declaration ...]
[constant_declaration ...]
[exception_declaration ...]
[cursor_specification ...]
[PROCEDURE [Schema..]
procedure_name [ (parameter {IN,OUT,IN OUT} datatype
[,parameter]) ] ]
[FUNCTION [Schema..] function_name [ (parameter {IN,OUT,IN OUT}
datatype [,parameter]) ]
RETURN return_datatype ]
END [package_name];
PL/SQL Packages…
PL/SQL Body: This contains the actual PL/SQL statement code implementing the logics of functions, procedures which are you already before
declare in "Package specification".
CREATE [OR REPLACE] PACKAGE BODY package_name
IS | AS
[private_variable_declaration ...]
[private_constant_declaration ...]
BEGIN [initialization_statement]
[PROCEDURE [Schema..] procedure_name
[ (parameter [,parameter]) ]
IS | AS
variable declarations;
constant declarations;
BEGIN
statement(s);
EXCEPTION
WHEN ...
END ]
[FUNCTION [Schema..] function_name
[ (parameter [,parameter]) ]
RETURN return_datatype
IS | AS
variable declarations;
constant declarations;
BEGIN
statement(s);
EXCEPTION
WHEN ...
END ]
[EXCEPTION
WHEN built-in_exception_name_1 THEN
User defined statement (action) will be taken; ]
END;
/
PL/SQL Packages…
CREATE or REPLACE PACKAGE pkg1
IS | AS
PROCEDURE pro1 (no in number, name out varchar2);
FUNCTION fun1 (no in number) RETURN varchar2;
END;
/
CREATE or REPLACE PACKAGE BODY pkg1 IS
PROCEDURE pro1(no in number,info our varchar2)
IS
BEGIN
SELECT * INTO temp FROM emp1 WHERE eno = no;
END;
FUNCTION fun1(no in number) return varchar2
IS
name varchar2(20);
BEGIN
SELECT ename INTO name FROM emp1 WHERE eno = no;
RETURN name;
END;
END;
/
PL/SQL Packages…
DECLARE
no number := &no;
name varchar2(20);
BEGIN
pkg1.pro1(no,info);
dbms_output.put_line('Procedure Result');
dbms_output.put_line(info.eno||' '|| info.ename||' '||
info.edept||' '|| info.esalary||' '||);
dbms_output.put_line('Function Result');
name := pkg1.fun1(no);
dbms_output.put_line(name);
END;
/
ALTER PACKAGE package_name COMPILE BODY;
DROP PACKAGE package_name;

Potrebbero piacerti anche