PL SQL Key Concepts Examples
PL SQL Key Concepts 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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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.
RETURN CLOB
IS
c CLOB;
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);
END LOOP;
DBMS_LOB.CLOSE(c);
RETURN c;
END;
2.
pos PLS_INTEGER := 1;
next_pos PLS_INTEGER;
BEGIN
LOOP
IF next_pos = 0 THEN
EXIT;
END IF;
END LOOP;
RETURN;
END SPLIT_CLOB_TO_ROWS;