Procedure in an Oracle Database
The Oracle database contains strong, reusable bits of computer logic called stored procedures. In essence, they are named pieces of PL/SQL code or even statements in Java or C that carry out particular operations. Instead of having it dispersed over several apps, this approach enables you to centralise application logic and business rules within the database. This centralisation has a number of noteworthy advantages:
- Reusability and Consistency: Once a procedure is developed, it can be called by several applications, guaranteeing that business rules are implemented uniformly over all interfaces. Application development is made simpler and code redundancy is decreased as a result.
- Improved Performance: Compiles stored procedures and stores them in the database in their compiled version. By lowering parsing and compilation overhead, Oracle’s pre-compiled code is executed when a procedure is called, greatly enhancing efficiency. Performance can also be significantly improved in client-server or three-tier architectures by shifting complex processing from the client application to the database server.
- Enhanced Security: Procedures can serve as “gatekeepers” to the underlying data tables, which improves security. You can only provide users the
EXECUTE
privilege on a procedure rather than giving them direct access to tables. The process, which is owned by a distinct schema, is then granted the privileges required to carry out DML operations, guaranteeing data integrity and allowing for more precise access control. - Reduced Network Traffic: Encapsulating complex tasks into a single stored procedure eliminates the need for several SQL statements delivered by a client application. By doing this, network traffic is decreased because there are fewer round trips between the client and the server.
- Maintainability: Updates and modifications are simpler to distribute and manage when business logic is centrally located. Every application that uses a procedure is immediately updated when it is modified.
- Procedural Language/Structured Query Language, or PL/SQL, is the procedural extension for SQL and the Oracle relational database developed by Oracle Corporation. Programs written in PL/SQL are organised into blocks, which usually include sections for declarations, executable commands, and optional exception handling. “Named block” is a sort of stored procedure.
CREATE PROCEDURE Syntax
A stored procedure is created using the CREATE PROCEDURE
statement. The procedure name, arguments, and PL/SQL block that makes up the procedure’s body are all defined in the basic syntax:
CREATE [OR REPLACE] PROCEDURE [schema.]procedure_name
[(parameter_name [IN | OUT | IN OUT] DATATYPE [, ...])]
[AUTHID {CURRENT_USER | DEFINER}]
{IS | AS}
[<declarations>]
BEGIN
<procedure_body>
[EXCEPTION
<exception_handling_statements>]
END [procedure_name];
/
Let’s examine each of the essential elements:
- OR REPLACE: If the procedure is already in place, you can use this optional clause to recreate it without having to
DROP
it first. TheCREATE
statement won’t work if you leave outOR REPLACE
and the procedure is already in place. - [schema.]procedure_name: Indicates the procedure’s name, optionally qualified by the schema to which it belongs. Your current schema is used to generate the procedure if the schema is left out.
- parameter_name [IN | OUT | IN OUT] DATATYPE: Here, you specify the parameters that the process will take in and return. A datatype, a mode (
IN
,OUT
, orIN OUT
), and a name are assigned to each parameter. - AUTHID {CURRENT_USER | DEFINER}: The procedure’s “execution rights” are established by the AUTHID {CURRENT_USER | DEFINER} clause.
- DEFINER (default): The procedure runs with the owner’s (the definer’s) privileges. This is helpful when a user only has the ability to
EXECUTE
the procedure and not the underlying tables, allowing for regulated access to data. - CURRENT_USER: The user who calls the procedure (the invoker) has the privileges to carry it out.
- DEFINER (default): The procedure runs with the owner’s (the definer’s) privileges. This is helpful when a user only has the ability to
- IS | AS: These terms can be used interchangeably to introduce the procedure body’s PL/SQL block.
AS
essentially takes the role of theDECLARE
keyword that would be used in an anonymous block when constructing a standalone process. - <declarations>: This optional section specifies constants, local variables, and cursors that are only utilised inside the procedure.
- BEGIN … END: This is the required Executable Commands portion, which includes the PL/SQL and SQL statements that carry out the logic of the procedure. At least one executable statement must be present in a procedure.
- EXCEPTION …: This optional section outlines exception handlers for handling potential execution issues.
Parameter Modes: IN, OUT, and IN OUT
In order to transfer data between a calling application and a stored procedure, parameters are essential. Three parameter modes can be used with PL/SQL:
- IN Parameters
- The procedure receives values from the
IN
parameters. - Within the process, they function similarly to constants; their values cannot be assigned or altered.
- If no mode is given,
IN
is the default mode. - A literal, constant, variable, or expression can be the actual parameter that is provided.
- The procedure receives values from the
- OUT Parameters
OUT
parameters are used to return values to the calling environment from the method.- During the procedure, an
OUT
parameter functions similarly to an uninitialised variable; it is worthless until the procedure is successfully finished. Any assignments are made to a local copy, which, after successful completion, is moved to the actual parameter. - Oracle requires a receptacle to hold the outgoing value, hence the actual parameter that corresponds to an
OUT
formal parameter must be a variable rather than a constant, literal, or expression.
- IN OUT Parameters
- The
IN OUT
parameters enable you to return (perhaps altered) values from the procedure as well as send values into it. - An
IN OUT
parameter functions within the procedure like an initialised variable; its initial value is changeable and used. - For an
IN OUT
formal parameter, the actual parameter must likewise be a variable.
- The
NOCOPY Hint: Oracle usually creates two copies of the OUT
and IN OUT
parameters: one when the procedure is called and another when it returns. This is especially true when working with large data structures like collections or records. By asking the PL/SQL compiler to transmit the argument by reference rather than by value, the NOCOPY
hint can increase speed by preventing these copying processes.
Example: Employee Salary Adjustment Procedure
Let’s create a simple EMPLOYEES
table and then a stored procedure to adjust an employee’s salary based on an adjustment factor. This procedure will demonstrate the use of IN
, IN OUT
, and OUT
parameters. The IN OUT
parameter will also include a simple business rule to cap the adjustment factor.
First, we’ll create the EMPLOYEES
table and insert some sample data:
-- Create the EMPLOYEES table
CREATE TABLE EMPLOYEES (
EMPLOYEE_ID NUMBER(6) PRIMARY KEY,
FIRST_NAME VARCHAR2(20),
LAST_NAME VARCHAR2(25) NOT NULL,
EMAIL VARCHAR2(25) NOT NULL UNIQUE,
PHONE_NUMBER VARCHAR2(20),
HIRE_DATE DATE NOT NULL,
JOB_ID VARCHAR2(10) NOT NULL,
SALARY NUMBER(8,2) NOT NULL
);
-- Insert sample values
INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB_ID, SALARY)
VALUES (100, 'Steven', 'King', 'SKING', '515.123.4567', TO_DATE('17-JUN-2003', 'DD-MON-YYYY'), 'AD_PRES', 24000);
INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB_ID, SALARY)
VALUES (101, 'Neena', 'Kochhar', 'NKOCHHAR', '515.123.4568', TO_DATE('21-SEP-2005', 'DD-MON-YYYY'), 'AD_VP', 17000);
INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB_ID, SALARY)
VALUES (102, 'Lex', 'De Haan', 'LDEHAAN', '515.123.4569', TO_DATE('13-JAN-2001', 'DD-MON-YYYY'), 'AD_VP', 17000);
COMMIT;
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, SALARY FROM EMPLOYEES ORDER BY EMPLOYEE_ID;
Initial Table Data:
EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY
----------- ---------- -------------- ----------
100 Steven King 24000.00
101 Neena Kochhar 17000.00
102 Lex De Haan 17000.00
Now, let’s create the ADJUST_EMPLOYEE_SALARY
procedure:
CREATE OR REPLACE PROCEDURE ADJUST_EMPLOYEE_SALARY (
p_employee_id IN EMPLOYEES.EMPLOYEE_ID%TYPE,
p_adjustment_factor IN OUT NUMBER, -- Input factor, can be modified and returned
p_calculated_salary OUT EMPLOYEES.SALARY%TYPE -- Output new salary
)
AS
v_current_salary EMPLOYEES.SALARY%TYPE;
v_max_factor CONSTANT NUMBER := 1.10; -- Maximum allowed adjustment factor (10% increase)
BEGIN
-- Retrieve current salary for the employee
SELECT SALARY
INTO v_current_salary
FROM EMPLOYEES
WHERE EMPLOYEE_ID = p_employee_id;
-- Implement a business rule for the adjustment factor (IN OUT parameter)
-- If the requested factor is too high, cap it at v_max_factor
IF p_adjustment_factor > v_max_factor THEN
DBMS_OUTPUT.PUT_LINE('Warning: Requested adjustment factor ' || p_adjustment_factor || ' exceeds maximum allowed (' || v_max_factor || '). Capping at ' || v_max_factor);
p_adjustment_factor := v_max_factor; -- Modify the IN OUT parameter
END IF;
-- Calculate the new salary
p_calculated_salary := v_current_salary * p_adjustment_factor;
-- Update the employee's salary in the table
UPDATE EMPLOYEES
SET SALARY = p_calculated_salary
WHERE EMPLOYEE_ID = p_employee_id;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Employee ' || p_employee_id || ': Salary updated from ' || v_current_salary || ' to ' || p_calculated_salary || ' using actual factor ' || p_adjustment_factor);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Error: Employee ' || p_employee_id || ' not found.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An unexpected error occurred: ' || SQLERRM);
ROLLBACK;
END ADJUST_EMPLOYEE_SALARY;
/
Executing the Procedure and Viewing Output
To see the output from DBMS_OUTPUT.PUT_LINE
statements within the PL/SQL procedure, you must enable SERVEROUTPUT
in your SQL*Plus or SQL Developer session:
SET SERVEROUTPUT ON SIZE 1000000; -- Set buffer size to handle potentially large output
-- Declare variables to hold OUT and IN OUT parameter values
DECLARE
v_emp_id EMPLOYEES.EMPLOYEE_ID%TYPE := 100;
v_factor_in_out NUMBER := 1.15; -- Initial requested adjustment factor (15% increase)
v_new_salary EMPLOYEES.SALARY%TYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE('--- Before Procedure Call ---');
DBMS_OUTPUT.PUT_LINE('Initial requested factor: ' || v_factor_in_out);
-- Execute the procedure
ADJUST_EMPLOYEE_SALARY(
p_employee_id => v_emp_id,
p_adjustment_factor => v_factor_in_out,
p_calculated_salary => v_new_salary
);
DBMS_OUTPUT.PUT_LINE('--- After Procedure Call ---');
DBMS_OUTPUT.PUT_LINE('Final adjustment factor (returned by procedure): ' || v_factor_in_out);
DBMS_OUTPUT.PUT_LINE('Calculated new salary (returned by procedure): ' || v_new_salary);
END;
/
-- Verify the persistent change in the table
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, SALARY FROM EMPLOYEES WHERE EMPLOYEE_ID = 100;
-- Another call, with a factor within limits
DECLARE
v_emp_id EMPLOYEES.EMPLOYEE_ID%TYPE := 101;
v_factor_in_out NUMBER := 1.05; -- 5% increase
v_new_salary EMPLOYEES.SALARY%TYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE('--- Before Procedure Call (Employee 101) ---');
DBMS_OUTPUT.PUT_LINE('Initial requested factor: ' || v_factor_in_out);
ADJUST_EMPLOYEE_SALARY(
p_employee_id => v_emp_id,
p_adjustment_factor => v_factor_in_out,
p_calculated_salary => v_new_salary
);
DBMS_OUTPUT.PUT_LINE('--- After Procedure Call (Employee 101) ---');
DBMS_OUTPUT.PUT_LINE('Final adjustment factor (returned by procedure): ' || v_factor_in_out);
DBMS_OUTPUT.PUT_LINE('Calculated new salary (returned by procedure): ' || v_new_salary);
END;
/
-- Verify all salaries
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, SALARY FROM EMPLOYEES ORDER BY EMPLOYEE_ID;
Example Output:
--- Before Procedure Call ---
Initial requested factor: 1.15
Warning: Requested adjustment factor 1.15 exceeds maximum allowed (1.1). Capping at 1.1
Employee 100: Salary updated from 24000 to 26400 using actual factor 1.1
--- After Procedure Call ---
Final adjustment factor (returned by procedure): 1.1
Calculated new salary (returned by procedure): 26400
PL/SQL procedure successfully completed.
EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY
----------- ---------- -------------- ----------
100 Steven King 26400.00
--- Before Procedure Call (Employee 101) ---
Initial requested factor: 1.05
Employee 101: Salary updated from 17000 to 17850 using actual factor 1.05
--- After Procedure Call (Employee 101) ---
Final adjustment factor (returned by procedure): 1.05
Calculated new salary (returned by procedure): 17850
PL/SQL procedure successfully completed.
EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY
----------- ---------- -------------- ----------
100 Steven King 26400.00
101 Neena Kochhar 17850.00
102 Lex De Haan 17000.00
In this example, for EMPLOYEE_ID
100, we initially requested a 15% increase (v_factor_in_out = 1.15
). However, due to the business rule within the procedure, this factor was capped at 10% (v_max_factor = 1.10
), and the p_adjustment_factor
(an IN OUT
parameter) was updated to 1.10
before being used in the calculation and returned to the calling block. The p_calculated_salary
(an OUT
parameter) correctly received the new salary. For EMPLOYEE_ID
101, the requested factor was within limits, so it was used as is.
Stored procedures are a fundamental part of building robust, maintainable, and high-performance applications with Oracle Database, offering a modular approach to database programming.