Introduction to PL/SQL — Oracle's Procedural SQL Extension
SQL is declarative — you describe what data you want and the database figures out how to get it. But real-world database logic often requires conditional branching, loops, error handling, and reusable procedures. That's what PL/SQL adds.
PL/SQL (Procedural Language extension to SQL) is Oracle's procedural extension to SQL. It runs inside the Oracle database engine itself, which means it avoids the round-trip overhead of sending individual SQL statements from an application. A loop that issues 1000 SQL statements from Java sends 1000 network requests. The same loop in PL/SQL sends one.
By the end of this article you'll understand the PL/SQL block structure, how to use variables, write conditionals and loops, and handle exceptions — the four pillars of every PL/SQL program.
The PL/SQL Block Structure
Every PL/SQL program is a block. Blocks have four sections: DECLARE (optional, for variables), BEGIN (required, the logic), EXCEPTION (optional, error handling), and END. Blocks can be anonymous (run once, not stored) or named (procedures and functions stored in the database). Understanding this structure is the foundation of everything else in PL/SQL.
-- Anonymous PL/SQL block — runs immediately, not stored DECLARE -- Variable declarations v_employee_name VARCHAR2(50); -- String up to 50 chars v_salary NUMBER(10, 2); -- Number with 2 decimal places v_department_id NUMBER := 10; -- Initialised to 10 BEGIN -- Query into variables using SELECT INTO SELECT first_name || ' ' || last_name, salary INTO v_employee_name, v_salary FROM employees WHERE department_id = v_department_id AND ROWNUM = 1; -- Output using DBMS_OUTPUT (enable with SET SERVEROUTPUT ON) DBMS_OUTPUT.PUT_LINE('Employee: ' || v_employee_name); DBMS_OUTPUT.PUT_LINE('Salary: $' || TO_CHAR(v_salary, '999,999.99')); EXCEPTION -- Handle the case where no rows are found WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('No employee found in department ' || v_department_id); END; / -- The slash executes the block in SQL*Plus and SQLDeveloper
Salary: $24,000.00
Variables, Conditions, and Loops
PL/SQL variables are strongly typed. The %TYPE attribute lets you declare a variable that automatically matches a table column's data type — if the column type changes, your variable adapts automatically. Conditionals use IF/ELSIF/ELSE. Loops come in three flavours: basic LOOP, WHILE, and the most common FOR loop.
DECLARE -- %TYPE anchors variable type to the actual column definition v_salary employees.salary%TYPE; v_grade VARCHAR2(10); v_counter NUMBER; BEGIN SELECT salary INTO v_salary FROM employees WHERE employee_id = 100; -- IF / ELSIF / ELSE IF v_salary > 20000 THEN v_grade := 'Executive'; ELSIF v_salary > 10000 THEN v_grade := 'Senior'; ELSIF v_salary > 5000 THEN v_grade := 'Mid-level'; ELSE v_grade := 'Junior'; END IF; DBMS_OUTPUT.PUT_LINE('Grade: ' || v_grade); -- FOR loop (most common) — implicit counter, no DECLARE needed FOR v_counter IN 1..5 LOOP DBMS_OUTPUT.PUT_LINE('Iteration: ' || v_counter); END LOOP; END; /
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5
| Feature | SQL | PL/SQL |
|---|---|---|
| Type | Declarative | Procedural |
| Execution | One statement at a time | Blocks of logic |
| Conditionals | CASE (limited) | IF/ELSIF/ELSE, CASE |
| Loops | Not supported | FOR, WHILE, LOOP |
| Error handling | None | EXCEPTION block |
| Reusability | Views | Procedures, functions, packages |
🎯 Key Takeaways
- PL/SQL extends SQL with variables, conditionals, loops, and exception handling
- Every PL/SQL program is a block: DECLARE / BEGIN / EXCEPTION / END
- %TYPE anchors variable types to table column definitions — use it always
- PL/SQL runs inside the database engine — eliminates application-to-database round trips
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Forgetting SET SERVEROUTPUT ON — DBMS_OUTPUT.PUT_LINE silently discards output if this is not set. Always run it at the start of your session.
- ✕Mistake 2: Using SELECT INTO when the query can return multiple rows — this raises TOO_MANY_ROWS exception. Use a cursor or aggregate function (MAX, MIN) when multiple rows are possible.
- ✕Mistake 3: Not ending the block with a forward slash (/) in SQL*Plus — without the slash the block is not submitted for execution. Nothing happens and no error appears.
Interview Questions on This Topic
- QWhat are the four sections of a PL/SQL block and which are optional?
- QWhat is the difference between %TYPE and %ROWTYPE?
- QWhen would you use a PL/SQL procedure vs a function?
Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.