Welcome to IT Wallah – Learn Coding, Modern Technology, Computer Troubleshooting, and Explore Helpful Tech Blogs.

PL/SQL Tutorial

PL/SQL stands for Procedural Language extension to SQL. It is Oracle Corporation's standard data access language for relational databases.

Get Started

PL/SQL combines the data manipulation power of SQL with the processing power of procedural languages. Navigate through the chapters on the left to master PL/SQL!

PL/SQL Architecture

The PL/SQL engine handles the execution of PL/SQL blocks.

When a PL/SQL block is submitted, the engine separates SQL statements and procedural statements. It sends SQL statements to the SQL Engine, while it processes procedural statements itself.

  • PL/SQL Engine: Component that executes the procedural code.
  • SQL Engine: Component that executes the SQL queries inside the PL/SQL block.

Advantages of PL/SQL

Why use PL/SQL over standard SQL?

  • Block Structures: You can send a block of statements to the database at once, reducing network traffic.
  • Procedural Language Capabilities: Use IF-THEN, loops, variables, and exceptions.
  • High Performance: Because PL/SQL is integrated tightly with SQL, operations perform faster.
  • Error Handling: Robust exception handling blocks allow graceful error catching.

Block Structure

PL/SQL programs are structured into logical blocks.

The Anatomy of a Block

A basic PL/SQL block consists of three sections: Declarative, Executable, and Exception-handling.

DECLARE
   -- Declaration section (optional)
   message VARCHAR2(20) := 'Hello World!';
BEGIN
   -- Execution section (mandatory)
   DBMS_OUTPUT.PUT_LINE(message);
EXCEPTION
   -- Exception handling section (optional)
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('An error occurred');
END;
/

Comments

Comments clarify code and are ignored by the compiler.

Single-line Comments
-- This is a single line comment
v_name VARCHAR2(50);
Multi-line Comments
/* This is a multi-line comment
that spans multiple lines */
v_age NUMBER := 25;

Identifiers

Identifiers name PL/SQL objects like variables, constants, subprograms.

  • Maximum 30 characters long.
  • Must begin with a letter.
  • Can include letters, numbers, dollar signs ($), underscores (_), and number signs (#).
  • Not case-sensitive (e.g., `v_name` is the same as `V_NAME`).

Declaring Variables

Variables must be declared in the DECLARE section before use.

Syntax
variable_name [CONSTANT] datatype [NOT NULL] [:= | DEFAULT initial_value];
Example
DECLARE
   v_emp_name VARCHAR2(50) := 'John Doe';
   c_pi CONSTANT NUMBER := 3.14159;
BEGIN
   DBMS_OUTPUT.PUT_LINE('Name: ' || v_emp_name);
END;

Data Types

PL/SQL supports SQL data types and its own specific data types.

Type CategoryExamples
ScalarNUMBER, CHAR, VARCHAR2, DATE, BOOLEAN
Large Object (LOB)BFILE, BLOB, CLOB, NCLOB
CompositeRECORD, TABLE, VARRAY
ReferenceREF CURSOR, REF object_type

%TYPE and %ROWTYPE

Anchor variables to database columns or tables to make code dynamic and resilient.

%TYPE

Declares a variable to have the exact same data type as a database column.

DECLARE
   v_salary employees.salary%TYPE;
BEGIN
   SELECT salary INTO v_salary FROM employees WHERE employee_id = 100;
END;
%ROWTYPE

Declares a record that represents an entire row of a table.

DECLARE
   v_emp_rec employees%ROWTYPE;
BEGIN
   SELECT * INTO v_emp_rec FROM employees WHERE employee_id = 100;
   DBMS_OUTPUT.PUT_LINE(v_emp_rec.first_name);
END;

IF-THEN-ELSIF Statements

Used for conditional execution of code blocks.

DECLARE
   v_score NUMBER := 85;
BEGIN
   IF v_score >= 90 THEN
      DBMS_OUTPUT.PUT_LINE('Grade: A');
   ELSIF v_score >= 80 THEN
      DBMS_OUTPUT.PUT_LINE('Grade: B');
   ELSE
      DBMS_OUTPUT.PUT_LINE('Grade: C or below');
   END IF;
END;

CASE Statement

A cleaner alternative to multiple ELSIF blocks.

DECLARE
   v_grade CHAR(1) := 'B';
BEGIN
   CASE v_grade
      WHEN 'A' THEN DBMS_OUTPUT.PUT_LINE('Excellent');
      WHEN 'B' THEN DBMS_OUTPUT.PUT_LINE('Very Good');
      WHEN 'C' THEN DBMS_OUTPUT.PUT_LINE('Good');
      ELSE DBMS_OUTPUT.PUT_LINE('Needs Improvement');
   END CASE;
END;

Loops

Iteratively execute a block of code.

Basic Loop
DECLARE
   x NUMBER := 1;
BEGIN
   LOOP
      DBMS_OUTPUT.PUT_LINE(x);
      x := x + 1;
      EXIT WHEN x > 5;
   END LOOP;
END;
WHILE Loop
WHILE x <= 5 LOOP
   DBMS_OUTPUT.PUT_LINE(x);
   x := x + 1;
END LOOP;
FOR Loop
FOR i IN 1..5 LOOP
   DBMS_OUTPUT.PUT_LINE(i);
END LOOP;

Implicit Cursors

Oracle automatically creates an implicit cursor whenever an SQL statement is executed, if no explicit cursor exists for it.

Used mainly for single-row SELECT ... INTO statements and DML operations.

BEGIN
   UPDATE employees SET salary = salary * 1.10 WHERE department_id = 10;
   IF SQL%FOUND THEN
      DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' rows updated.');
   END IF;
END;

Explicit Cursors

Used to process queries that return multiple rows.

Steps to use: Declare -> Open -> Fetch -> Close
DECLARE
   CURSOR emp_cursor IS SELECT first_name FROM employees;
   v_name employees.first_name%TYPE;
BEGIN
   OPEN emp_cursor;
   LOOP
      FETCH emp_cursor INTO v_name;
      EXIT WHEN emp_cursor%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE(v_name);
   END LOOP;
   CLOSE emp_cursor;
END;

Cursor Attributes

Attributes provide information about the execution of a cursor.

  • %FOUND: Returns TRUE if a record was fetched successfully.
  • %NOTFOUND: Returns TRUE if a record was not fetched.
  • %ROWCOUNT: Returns the number of rows fetched so far (or affected by DML).
  • %ISOPEN: Returns TRUE if the cursor is open.

Creating Procedures

A procedure is a subprogram that performs a specific action.

CREATE OR REPLACE PROCEDURE give_raise (p_emp_id IN NUMBER, p_amount IN NUMBER) AS
BEGIN
   UPDATE employees
   SET salary = salary + p_amount
   WHERE employee_id = p_emp_id;
   COMMIT;
END give_raise;
/

Creating Functions

A function is a subprogram that computes and returns a single value.

CREATE OR REPLACE FUNCTION get_annual_salary (p_emp_id IN NUMBER) RETURN NUMBER IS
   v_annual_sal NUMBER;
BEGIN
   SELECT salary * 12 INTO v_annual_sal
   FROM employees
   WHERE employee_id = p_emp_id;
   
   RETURN v_annual_sal;
END get_annual_salary;
/

IN, OUT, IN OUT Parameters

Parameters determine how data is passed to and from subprograms.

  • IN (Default): Passes a value into the subprogram. Read-only inside.
  • OUT: Returns a value to the caller. Must be assigned a value inside.
  • IN OUT: Passes an initial value in and returns an updated value out.

Predefined Exceptions

Oracle provides several predefined exceptions for common error conditions.

  • NO_DATA_FOUND: A SELECT INTO returned no rows.
  • TOO_MANY_ROWS: A SELECT INTO returned more than one row.
  • ZERO_DIVIDE: Attempted to divide by zero.
EXCEPTION
   WHEN NO_DATA_FOUND THEN
      DBMS_OUTPUT.PUT_LINE('Employee does not exist.');
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('An unexpected error occurred: ' || SQLERRM);

User-Defined Exceptions

You can declare your own exceptions for application-specific errors.

DECLARE
   e_invalid_age EXCEPTION;
   v_age NUMBER := 15;
BEGIN
   IF v_age < 18 THEN
      RAISE e_invalid_age;
   END IF;
EXCEPTION
   WHEN e_invalid_age THEN
      DBMS_OUTPUT.PUT_LINE('Error: User must be at least 18.');
END;

What is a Trigger?

A trigger is a stored PL/SQL block that automatically executes (fires) when a specific event occurs on a table.

Events can be INSERT, UPDATE, or DELETE. Triggers can fire BEFORE or AFTER the event.

Row-Level Triggers

Fires once for each row affected by the triggering statement (using `FOR EACH ROW`).

Using :NEW and :OLD

You can access the column values before and after the change.

CREATE OR REPLACE TRIGGER trg_audit_salary
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
   IF :NEW.salary < :OLD.salary THEN
      RAISE_APPLICATION_ERROR(-20001, 'Salary cannot be decreased!');
   END IF;
END;
/