Subprograms in PL/SQL
PL/SQL blocks are anonymous, cannot be called from other PL/SQL blocks
Subprogram is a named PL/SQL block that could be either
Procedure, or
Function, or
Package
Syntax for Creating a Procedure
Stored Procedure
A stored procedure is a named PL/SQL block that performs an action. It can be stored in the database as a database object for repeated execution.
CREATE [ OR REPLACE ] PROCEDURE proc_name[(argument [mode] data type, argument [mode] data type,……)]
-- PROCEDURES and FUNCTIONS may or may not accept arguments
IS
Local PL/SQL variable declarations
BEGIN
Define action performed by the procedure
EXCEPTION
Handle exceptions, if any
END [ proc_name];
Advantage of Replace option
This option replaces the previous definition of the FUNCTION, PROCEDURE, PACKAGE in the schema with the same name. The advantage of using the “REPLACE” option over “Dropping and recreating an object with new definition” is that the object privileges granted on the object get automatically revoked when you drop the object and are to be explicitly granted again when you recreate it with the new definition where as when the REPLACE option is used the object privileges remain unchanged.
Proc_name : Name of the procedure
Argument : Name of the PL/SQL variable whose value is passed to, populated by the calling environment or both , depending on the mode being used.
Mode : Mode of the argument IN , OUT or IN OUT (explained later)
Datatype : Datatype of the argument
The REPLACE option indicates that if the procedure exist it’s definition will be overwritten by a new procedure body.
Eg # 1
CREATE OR REPLACE PROCEDURE raise_salary (p_eno emp.empno%TYPE)
IS
BEGIN
UPDATE emp
SET sal = sal * 0.1
WHERE empno = p_eno;
END raise_salary;
RAISE_APPLICATION_ERROR Procedure
This procedure is used to display error messages along with error numbers
Example
RAISE_APPLICATION_ERROR(-20001, ‘Invalid Employee’);
Note:
When called, RAISE_APPLICATION_ERROR ends a subprogram, rolls back any database changes it made, and returns a user-defined error message to the application
Error numbers should be between -20000 and -20999
Parameters Modes in Procedures and Functions
Formal parameters can have three modes IN, OUT or IN OUT which decides the behavior of parameters
IN Parameter: Example
CREATE OR REPLACE PROCEDURE raise_salary (p_eno emp.empno%TYPE)
IS
vsal emp.sal%TYPE;
BEGIN
SELECT sal
INTO vsal
FROM emp
WHERE empno = p_eno;
IF vsal < 2000
THEN
UPDATE emp
SET sal = sal + vsal * 0.1
WHERE empno = p_eno;
END IF;
-- An exception handler to raise error if empno is not valid
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line('Empno does not exist');
ENDraise_salary;
Invoking a Procedure
There are two methods to Invoke a Procedure
Invoke a Procedure from another PL/SQL block
Example:
BEGIN
raise_salary(1002);
END;
Invoke a procedure from SQL*Plus environment by using EXECUTE command
Example
-- PROCEDURE call with parameter
EXECUTE raise_salary(1002);
Note: If no parameters are specified for a procedure, directly specify procedure name without any parenthesis
e. g. EXECUTE procedure_name;
OUT Parameter: Example
CREATE OR REPLACE PROCEDURE query_emp (
p_eno IN emp.empno%TYPE,
p_name OUT emp.ename%TYPE,
p_sal OUT emp.sal%TYPE
)
IS
BEGIN
SELECT ename, sal
INTO p_name, p_sal
FROM emp
WHERE empno = p_eno;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
raise_application_error (-20001, 'Employee does not exist');
END query_emp;
Note: In this example, p_eno parameter value cannot be changed, since it is defined as IN parameter. It receives a value from the calling environment. Parameters p_name and p_sal do not receive any value from the calling environment. The procedure query_emp assigns value to the two parameters and these values are passed back to the calling environment.
Invoking a Procedure Having OUT Parameters
SQL> VARIABLE name VARCHAR2(20)
SQL> VARIABLE salary NUMBER
SQL> EXECUTE query_emp(1001,:name,:salary)
SQL> PRINT name salary
Note: The use of colon (:) is to reference the host variable in the EXECUTE syntax
IN OUT Parameter: Example
CREATE OR REPLACE PROCEDURE emp_salary_increase (
p_emp_id IN emp.empno%TYPE,
p_salary IN OUT emp.sal%TYPE
)
IS
BEGIN
IF p_salary BETWEEN 1000 AND 2000
THEN
p_salary := p_salary * 1.2;
ELSIF p_salary BETWEEN 2000 AND 3000
THEN
p_salary := p_salary * 1.3;
ELSIF p_salary > 3000
THEN
p_salary := p_salary * 1.4;
END IF;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line(SQLERRM);
END;
/
This PL/SQL block shows how to execute the above 'emp_salary_increase' procedure
DECLARE
CURSOR updated_sal
IS
SELECT empno, sal
FROM emp;
pre_sal emp.sal%TYPE;
BEGIN
FOR emp_rec INupdated_sal
LOOP
pre_sal := emp_rec.sal;
emp_salary_increase (emp_rec.empno, emp_rec.sal);
DBMS_OUTPUT.put_line( ' The salary of '
|| emp_rec.empno
|| ' will be increased from '
|| emp_rec.sal
|| ' to '
|| (emp_rec.sal + pre_sal)
);
END LOOP;
END;
/
Syntax for Creating a Function
A function is a named PL/SQL block that performs a task and returns a value to the calling environment.
Syntax:
CREATE [ OR REPLACE ] FUNCTION function_name
[( argument [mode] data type, argument [mode] data type )]
RETURN data type
IS
Local PL/SQL variable declarations
BEGIN
Define task performed by the function and return
result using RETURN statement
EXCEPTION
Handle exceptions if any
END [ function_name];
Functions in PL/SQL
Example 1
CREATE OR REPLACE FUNCTION cal_bonus (p_eno emp.empno%TYPE)
RETURN NUMBER
IS
v_sal emp.sal%TYPE;
BEGIN
SELECT sal
INTO v_sal
FROM emp
WHERE empno = p_eno;
RETURN (v_sal * 0.1);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN -1;
END;
Example 2
CREATE OR REPLACE FUNCTION chk_dept (p_deptno dept.deptno%TYPE)
RETURN BOOLEAN
IS
v_deptno dept.deptno%TYPE;
BEGIN
SELECT deptno
INTO v_deptno
FROM dept
WHERE deptno = p_deptno;
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN FALSE;
END;
Calling Stored Functions from Different Locations
Functions can be called from different locations through SELECT and DML statements like:
Column list of SELECT command
WHERE and HAVING Clause
ORDER BY, GROUP BY Clauses
VALUES clause of INSERT command
SET clause of UPDATE command
Note: Not all functions can be called from above mentioned locations.
Rules for Calling a Function through a SQL Statement
To be callable from SQL statement:
The function must be stored in database as either stand alone function or as a part of a package
The function can take only IN type of parameters
The formal parameters and return type of the function must be oracle data types
The function must not end the current transaction (commit or rollback) or rollback to a savepoint prior to the function execution
The function must not issue any alter session or alter system commands
Difference between Procedures and Functions


Referencing Objects from Other Schemas
To reference objects from other schemas we first need to have appropriate privileges on the objects
To refer to objects in schemas other than our own, prefix the schema name with the object name:
Schema_name.Object_name
Example: To get information from the emp table belonging to scott's schema the user HR should use the following command
SELECT * FROM scott.emp;
Note: The command will run successfully only if the user HR is granted SELECT right on Scott's emp table
To execute a procedure belonging to scott’s schema the user HR will use the following command
EXECUTE scott.procedure_name
Granting Privileges on Subprograms
The object privileges applicable to subprograms are
EXECUTE
Grants right to execute the subprogram belonging to the schema of the other user
Syntax
GRANT EXECUTE ON subprogram_name
TO username[, username….]|PUBLIC;
Example
GRANT EXECUTE ON emp_salary_increase TO PUBLIC;
DEBUG
Grants right to debug the subprogram belonging to the schema of the other user
Syntax
GRANT DEBUG ON subprogram_name TO username[, username….]|PUBLIC;
Example
GRANT DEBUG ON emp_salary_increase TO PUBLIC
Revoking Privileges on Subprograms
To take back a privilege that is granted to a user
Syntax
REVOKE EXECUTE/DEBUG ON subprogram_name FROM
Username[,username…..] |PUBLIC;
Example
REVOKE EXECUTE ON emp_salary_increase FROM itp_jul_01, itp_jul_02;
Dropping PROCEDURES and FUNCTIONS
To Delete a PROCEDURE:
DROP PROCEDURE <Procedurename>;
e.g.
DROP PROCEDURE emp_salary_increase;
To Delete a FUNCTION:
DROP FUNCTION < Functionname >;
e.g.
DROP FUNCTION chk_dept;
Local Procedures and Functions
The subprograms can also be defined within the declarative section of a block, such subprograms are known as Local Subprograms
Local subprograms can also be defined within an anonymous block
These subprograms follow the same scope and visibility rules as any other PL/SQL identifier
It is only visible in the block in which it is declared
No other block can call local subprograms, as they are not visible to any other block
Local Procedures and Functions within a Stored Subprogram
CREATE OR REPLACE PROCEDURE emp_pro
AS
CURSOR c_allemp
IS
SELECT deptno, ename
FROM emp;
v_dname dept.dname%TYPE;
-- Local function ,local to the procedure which will return the dept name for an employee
FUNCTION show_deptname (p_dno dept.deptno%TYPE)
RETURN VARCHAR2
IS
v_dname dept.dname%TYPE;
BEGIN
SELECT dname
INTO v_dname
FROM dept
WHERE deptno = p_dno;
RETURN v_dname;
END show_deptname;
BEGIN
FOR v_rec IN c_allemp
LOOP
v_dname := show_deptname (v_rec.deptno);
DBMS_OUTPUT.put_line(v_rec.ename || ' belongs to ' || v_dname);
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line
('Wrong department number');
END emp_pro;
Difference between Stand Alone and Local Subprograms
Methods of Passing Parameters
The various methods available for passing parameters to subprograms are:
Positional
Pass actual parameters in the same order as formal parameters
Named
Pass actual parameters in arbitrary order by associating each with its corresponding formal parameter using special syntax (=>)
Combination
Pass some of the actual parameters as positional and some as named
Note: While using combination the positional parameters should be passed first
Methods of Passing Parameters: Example
CREATE TABLE employee AS SELECT ename, sal, comm
FROM emp;
TRUNCATE TABLE employee;
CREATE OR REPLACE PROCEDURE add_employee (
p_name IN emp.ename%TYPE DEFAULT 'unknown',
p_sal IN emp.sal%TYPE DEFAULT 1000,
p_comm IN emp.comm%TYPE DEFAULT 0
)
IS
BEGIN
INSERT INTO employee
(ename, sal, comm
)
VALUES (p_name, p_sal, p_comm
);
COMMIT;
ENDadd_employee;
/
Methods of Passing Parameters: Example
BEGIN
add_employee ;
add_employee ('SMITH', 2000,600);
add_employee (p_sal=> 6000,p_comm=>200, p_name =>'STEVE');
add_employee (p_sal =>4000) ;
add_employee('MARK', p_sal=> 6000,p_comm=>200);
END;
/
SELECT * FROM employee;
Note: All the positional parameters should precede the named parameters in a subprogram call.
Data Dictionary View
USER_SOURCE
Is used to obtain the text of a stored procedure or a stored function
USER_ERRORS
Is used to find out the compilation errors in the subprogram, currently getting compiled
One can use the SQL*Plus command SHOW ERRORS, instead of firing a SELECT query on USER_ERRORS
USER_OBJECTS
Is used to get the details of all the objects created in a particular schema
USER_PROCEDURES
Is used to get the details of all procedures in that user’s schema
Hello,
ReplyDelete#Topic being contrived to exist for many projects simply so it can be run will be the first to hit the wall, but those projects where the functions to make existing transactions cheaper in real world applications will find the elusive real world demand.
I am trying to use this in a materialized view and got below error:
SQL Error: ORA-12015: cannot create a fast refresh materialized view from a complex query
12015. 00000 - "cannot create a fast refresh materialized view from a complex query"
*Cause: Neither ROWIDs and nor primary key constraints are supported for
complex queries.
*Action: Reissue the command with the REFRESH FORCE or REFRESH COMPLETE
option or create a simple materialized view.
select IR.rowid MV_INST_LOBR_ROWID, J.rowid Job_ROWID, J.* FROM JOB J
LEFT JOIN MV_INST_LOB_R IR ON
(IR.I1503_CUST_AC_NO_PT1 = J.I3200_CUST_AC_NO_PT1 AND IR.I1503_CUST_AC_NO_PT2 = J.I3200_CUST_AC_NO_PT2 AND IR.I1503_INST_SEQ_NO = J.I3200_INST_SEQ_NO)
WHERE IR.I1503_CUST_AC_NO_PT1 IS NOT NULL AND IR.I1503_CUST_AC_NO_PT2 IS NOT NULL
UNION SELECT null, J.rowid Job_ROWID, J.* FROM JOB J WHERE J.I3200_CUST_AC_NO_PT1 IS NULL AND J.I3200_CUST_AC_NO_PT1 IS NULL;
Basically, the intention is to get all the records joining MV_INST_LOB_R and JOB table
where MV_INST_LOB_R do not have record for the joining condition J.I3200_CUST_AC_NO_PT1 / J.I3200_CUST_AC_NO_PT2
Can you help me in converting to simple query, so that I can use simple materialized view.
Follow my new blog if you interested in just tag along me in any social media platforms!
,Merci
Hi Dayakar,
ReplyDeleteYour writing shines! There is no room for gibberish here clearly you have explained about Procedures and Functions . Keep writing!
I have a number of tables with
partitions by month
My first script where I input the actual table works fine - as in it will drop the partitions which meet the criteria (see below)
Code (SQL):
DECLARE
v_sql varchar2(500);
v_date DATE;
v_partition_name user_tab_partitions.partition_name%TYPE;
v_high_value user_tab_partitions.high_value%TYPE;
CURSOR c1 IS SELECT PARTITION_NAME, HIGH_VALUE
FROM user_tab_partitions WHERE TABLE_NAME='TEST_YFS_BAT_LOC_H' AND PARTITION_NAME!='P0';
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO v_partition_name, v_high_value;
EXIT WHEN c1%NOTFOUND;
v_date := to_date(SUBSTR(v_high_value,11,19),'YYYY-MM-DD HH24:MI:SS');
IF v_date < (sysdate - 30) THEN
v_sql := 'alter table TEST_YFS_BAT_LOC_H drop partition ' || v_partition_name;
EXECUTE immediate v_sql;
END IF;
END LOOP;
CLOSE c1;
END;
/
But I want to be able to drop all partitions from all tables belonging to this schema. So how can I do something similar which goes through all the tables and partitions and does the same thing?
I am executing this script as the schema owner with 100+ tables
But great job man, do keep posted with the new updates.
Kind Regards,
Ajeeth
Oracle Apps R12 and Oracle Fusion Cloud Self Paced Online Training Videos Published on Udemy with Life Time Access & Live Meeting Support to Clear your Queries. Avail 25% to 80% discount. Please Check https://www.oracleappstechnical.com for Never Before Offers and Discount Coupon Codes.
ReplyDelete