0% found this document useful (0 votes)
4 views

PL SQL Key Concepts Examples

jio
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

PL SQL Key Concepts Examples

jio
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

PL/SQL Key Concepts and Examples

Collections (Arrays)
PL/SQL provides associative arrays, nested tables, and VARRAYs for collection handling.

Example:
DECLARE
TYPE num_table IS TABLE OF NUMBER;
numbers num_table := num_table(1, 2, 3, 4, 5);
BEGIN
FOR i IN 1..numbers.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Number: ' || numbers(i));
END LOOP;
END;

Dynamic SQL
Dynamic SQL allows you to execute SQL statements that are constructed at runtime.

Example:
DECLARE
table_name VARCHAR2(30) := 'employees';
column_name VARCHAR2(30) := 'salary';
new_value NUMBER := 1000;
BEGIN
EXECUTE IMMEDIATE 'UPDATE ' || table_name || ' SET ' || column_name || ' = :1 WHERE
employee_id = 101'
USING new_value;
DBMS_OUTPUT.PUT_LINE('Salary updated successfully.');
END;

Bulk Collect and FORALL


BULK COLLECT allows you to retrieve multiple rows into a collection at once, making it
faster for handling large data.
FORALL is used for bulk processing of SQL statements, improving performance for multiple
DML operations.

Example: Bulk Collect


DECLARE
TYPE num_table IS TABLE OF NUMBER;
salaries num_table;
BEGIN
SELECT salary BULK COLLECT INTO salaries FROM employees WHERE department_id =
10;
FOR i IN 1..salaries.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Salary: ' || salaries(i));
END LOOP;
END;

Example: FORALL
DECLARE
TYPE num_table IS TABLE OF NUMBER;
emp_ids num_table := num_table(101, 102, 103);
BEGIN
FORALL i IN emp_ids.FIRST..emp_ids.LAST
UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_ids(i);
DBMS_OUTPUT.PUT_LINE('Salaries updated.');
END;

Types of PL/SQL Collections


Associative Arrays: Indexed by strings or integers.

Example:
DECLARE
TYPE emp_name_type IS TABLE OF VARCHAR2(50) INDEX BY PLS_INTEGER;
emp_names emp_name_type;
BEGIN
emp_names(1) := 'Habib';
emp_names(2) := 'Himel';
FOR i IN 1..emp_names.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Employee ' || i || ': ' || emp_names(i));
END LOOP;
END;

Advanced Triggers
INSTEAD OF Trigger: Used on views to handle DML operations that aren't possible directly
on views.

Example:
CREATE OR REPLACE VIEW emp_view AS
SELECT employee_id, first_name, last_name FROM employees WHERE department_id =
10;

CREATE OR REPLACE TRIGGER trg_emp_view_insert


INSTEAD OF INSERT ON emp_view
FOR EACH ROW
BEGIN
INSERT INTO employees (employee_id, first_name, last_name, department_id)
VALUES (:NEW.employee_id, :NEW.first_name, :NEW.last_name, 10);
END;

Records and PL/SQL Tables


A record is a composite data structure that groups related data.
PL/SQL Tables (nested tables and associative arrays) can store records, providing a way to
handle complex data structures.

Example:
DECLARE
TYPE emp_record_type IS RECORD (
employee_id employees.employee_id%TYPE,
first_name employees.first_name%TYPE,
salary employees.salary%TYPE
);
emp_record emp_record_type;
BEGIN
SELECT employee_id, first_name, salary INTO emp_record
FROM employees WHERE employee_id = 101;
DBMS_OUTPUT.PUT_LINE('Employee ID: ' || emp_record.employee_id || ', Name: ' ||
emp_record.first_name || ', Salary: ' || emp_record.salary);
END;

Error Logging and Custom Error Messages


Use RAISE_APPLICATION_ERROR to throw custom error messages and SQLCODE and
SQLERRM to capture error information.

Example:
DECLARE
invalid_salary EXCEPTION;
salary NUMBER := -100;
BEGIN
IF salary < 0 THEN
RAISE invalid_salary;
END IF;
EXCEPTION
WHEN invalid_salary THEN
DBMS_OUTPUT.PUT_LINE('Error: Salary cannot be negative');
RAISE_APPLICATION_ERROR(-20001, 'Invalid salary detected: ' || salary);
END;
Pipelined Table Functions
Pipelined table functions return a set of rows as a table that can be queried directly using
SQL.

Example:
CREATE OR REPLACE TYPE number_list AS TABLE OF NUMBER;
CREATE OR REPLACE FUNCTION get_numbers (n IN NUMBER)
RETURN number_list PIPELINED IS
BEGIN
FOR i IN 1..n LOOP
PIPE ROW(i);
END LOOP;
RETURN;
END;

-- Using the pipelined function


SELECT * FROM TABLE(get_numbers(5));

PL/SQL Table Functions and Parallel Processing


It allows to use table functions in parallel to handle large datasets efficiently. By setting the
table function as parallel-enabled, it can process data in parallel threads.

Example:
CREATE OR REPLACE FUNCTION parallel_table_function(p_max NUMBER)
RETURN NUMBER_TABLE PIPELINED PARALLEL_ENABLE IS
BEGIN
FOR i IN 1..p_max LOOP
PIPE ROW(i);
END LOOP;
END;

SELECT * FROM TABLE(parallel_table_function(1000));

User-Defined Object Types


Object types allow defining complex data structures that can be stored as a single column in
a table or passed to PL/SQL procedures.

Example:
CREATE OR REPLACE TYPE person_type AS OBJECT (
first_name VARCHAR2(50),
last_name VARCHAR2(50),
birthdate DATE
);
DECLARE
person person_type := person_type('Habib', 'Himel', TO_DATE('1997-02-28', 'YYYY-MM-
DD'));
BEGIN
DBMS_OUTPUT.PUT_LINE('Name: ' || person.first_name || ' ' || person.last_name);
END;

PL/SQL Performance Optimization


NOCOPY Hint: Allows PL/SQL to pass large objects (like collections) by reference instead of
by value, saving memory and improving performance.

Example:
CREATE OR REPLACE PROCEDURE update_employee_salary (
emp_id IN NUMBER,
new_salary IN OUT NOCOPY NUMBER
) IS
BEGIN
UPDATE employees SET salary = new_salary WHERE employee_id = emp_id;
DBMS_OUTPUT.PUT_LINE('Salary updated for employee ' || emp_id);
END;

Using PRAGMA DIRECTIVES


Pragmas are compiler directives that optimize specific aspects of PL/SQL code.
PRAGMA EXCEPTION_INIT: Associates an exception with an Oracle error number.

Example:
DECLARE
insufficient_balance EXCEPTION;
PRAGMA EXCEPTION_INIT(insufficient_balance, -20000);
BEGIN
-- Attempt some operation that could trigger error -20000
EXCEPTION
WHEN insufficient_balance THEN
DBMS_OUTPUT.PUT_LINE('Error: Insufficient balance');
END;

Ref Cursors
Ref cursors (or cursor variables) define a cursor whose query is determined at runtime.

Example:
DECLARE
TYPE ref_cursor_type IS REF CURSOR;
emp_cursor ref_cursor_type;
emp_record employees%ROWTYPE;
BEGIN
OPEN emp_cursor FOR SELECT * FROM employees WHERE department_id = 10;
LOOP
FETCH emp_cursor INTO emp_record;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Employee: ' || emp_record.first_name || ' ' ||
emp_record.last_name);
END LOOP;
CLOSE emp_cursor;
END;

Using SYS_REFCURSOR for Dynamic Queries


SYS_REFCURSOR is a predefined ref cursor type in PL/SQL, simplifying the code by not
requiring explicit type declarations.

Example:
DECLARE
cur SYS_REFCURSOR;
emp_name VARCHAR2(50);
BEGIN
OPEN cur FOR 'SELECT first_name FROM employees WHERE employee_id = :id' USING
101;
FETCH cur INTO emp_name;
DBMS_OUTPUT.PUT_LINE('Employee Name: ' || emp_name);
CLOSE cur;
END;

Fine-Grained Auditing (FGA)


Fine-grained auditing enables capturing specific query information based on a particular
condition, such as capturing sensitive data access.

Example:
BEGIN
DBMS_FGA.ADD_POLICY(
object_schema => 'CBS',
object_name => 'employees',
policy_name => 'sensitive_data_access',
audit_condition => 'salary > 50000',
audit_column => 'salary'
);
END;
More Example:
1.

create or replace FUNCTION VC2CLOB_FROM_BLOB(B BLOB)

RETURN CLOB

IS

c CLOB;

chunk_size CONSTANT NUMBER := 32767; -- chunk size for reading

start_pos NUMBER := 1;

bytes_read NUMBER;

buffer VARCHAR2(32767);

BEGIN

IF (B IS NULL) THEN

RETURN NULL;

END IF;

IF (DBMS_LOB.GETLENGTH(B) = 0) THEN

RETURN EMPTY_CLOB();

END IF;

DBMS_LOB.CREATETEMPORARY(c, TRUE);

DBMS_LOB.OPEN(c, DBMS_LOB.LOB_READWRITE);

WHILE start_pos <= DBMS_LOB.GETLENGTH(B) LOOP

bytes_read := LEAST(chunk_size, DBMS_LOB.GETLENGTH(B) - start_pos + 1);

buffer := UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR(B, bytes_read,


start_pos));
DBMS_LOB.WRITEAPPEND(c, LENGTH(buffer), buffer);

start_pos := start_pos + bytes_read;

END LOOP;

DBMS_LOB.CLOSE(c);

RETURN c;

END;

2.

create or replace FUNCTION SPLIT_CLOB_TO_ROWS(clob_data CLOB, delimiter VARCHAR2)


RETURN SYS.ODCIVARCHAR2LIST PIPELINED IS

pos PLS_INTEGER := 1;

next_pos PLS_INTEGER;

BEGIN

LOOP

next_pos := INSTR(clob_data, delimiter, pos);

IF next_pos = 0 THEN

PIPE ROW (TRIM(SUBSTR(clob_data,pos)));

EXIT;

END IF;

PIPE ROW (TRIM(SUBSTR(clob_data, pos,next_pos - pos)));

pos := next_pos + LENGTH(delimiter);

END LOOP;

RETURN;

END SPLIT_CLOB_TO_ROWS;

You might also like