PL/SQL COLLECTIONS NOTES
-------------------------
1. ASSOCIATIVE ARRAYS (INDEX-BY TABLES)
----------------------------------------
- Key-value pairs, indexed by PLS_INTEGER or VARCHAR2.
- Used for in-memory data like lookup tables.
Syntax:
--------
DECLARE
TYPE t_array IS TABLE OF <datatype> INDEX BY PLS_INTEGER or VARCHAR2(n);
v_array t_array;
BEGIN
v_array(key) := value;
...
END;
Example 1: Integer Keys
------------------------
DECLARE
TYPE t_names IS TABLE OF VARCHAR2(50) INDEX BY PLS_INTEGER;
names t_names;
BEGIN
names(1) := 'Alice';
names(2) := 'Bob';
FOR i IN names.FIRST .. names.LAST LOOP
IF names.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE('Name ' || i || ': ' || names(i));
END IF;
END LOOP;
END;
Example 2: String Keys
------------------------
DECLARE
TYPE t_dept IS TABLE OF VARCHAR2(30) INDEX BY VARCHAR2(10);
emp_dept t_dept;
BEGIN
emp_dept('E101') := 'HR';
emp_dept('E102') := 'Finance';
-- Loop through keys
DECLARE
k VARCHAR2(10);
BEGIN
k := emp_dept.FIRST;
WHILE k IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(k || ' works in ' || emp_dept(k));
k := emp_dept.NEXT(k);
END LOOP;
END;
END;
Example 3: Student Marks Analysis
---------------------------------
DECLARE
TYPE t_marks IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
marks t_marks;
total NUMBER := 0;
count_above_75 NUMBER := 0;
avg NUMBER;
name VARCHAR2(20);
total_students NUMBER := 0;
BEGIN
marks('Ravi') := 82;
marks('Anita') := 91;
marks('Sunil') := 68;
marks('Meena') := 77;
marks('Vikas') := 55;
name := marks.FIRST;
WHILE name IS NOT NULL LOOP
total := total + marks(name);
total_students := total_students + 1;
IF marks(name) > 75 THEN
count_above_75 := count_above_75 + 1;
END IF;
name := marks.NEXT(name);
END LOOP;
avg := total / total_students;
DBMS_OUTPUT.PUT_LINE('Total: ' || total);
DBMS_OUTPUT.PUT_LINE('Average: ' || ROUND(avg, 2));
DBMS_OUTPUT.PUT_LINE('Above 75: ' || count_above_75);
END;
2. NESTED TABLES
-----------------
- One-dimensional collections.
- Can be sparse (gaps).
- Use EXTEND to add elements.
Syntax:
--------
DECLARE
TYPE t_table IS TABLE OF <datatype>;
v_table t_table := t_table();
BEGIN
v_table.EXTEND;
v_table(index) := value;
END;
Example: Nested Table of Numbers
--------------------------------
DECLARE
TYPE t_numbers IS TABLE OF NUMBER;
numbers t_numbers := t_numbers();
BEGIN
numbers.EXTEND(3);
numbers(1) := 10;
numbers(2) := 20;
numbers(3) := 30;
FOR i IN 1 .. numbers.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Value: ' || numbers(i));
END LOOP;
END;
Practice Task Example: Delete Element
-------------------------------------
DECLARE
TYPE t_numbers IS TABLE OF NUMBER;
numbers t_numbers := t_numbers();
BEGIN
numbers.EXTEND(5);
numbers(1) := 10;
numbers(2) := 20;
numbers(3) := 30;
numbers(4) := 40;
numbers(5) := 50;
numbers.DELETE(3);
FOR i IN 1 .. numbers.COUNT LOOP
IF numbers.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE('Index ' || i || ': ' || numbers(i));
END IF;
END LOOP;
END;
--- END OF NOTES ---
3. VARRAYs (Variable-Size Arrays)
---------------------------------
- Bounded one-dimensional collection (fixed max size).
- Elements are stored in order.
- Useful when the number of elements is known and limited.
Syntax:
--------
DECLARE
TYPE t_array IS VARRAY(n) OF <datatype>;
v_array t_array := t_array();
Example: VARRAY of Bonuses
----------------------------
DECLARE
TYPE t_bonus IS VARRAY(5) OF NUMBER(8,2);
emp_bonus t_bonus := t_bonus();
BEGIN
emp_bonus.EXTEND(3);
emp_bonus(1) := 5000.50;
emp_bonus(2) := 3200.75;
emp_bonus(3) := 4500.00;
FOR i IN 1 .. emp_bonus.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Bonus ' || i || ': ₹' || emp_bonus(i));
END LOOP;
END;
Example: Trim in VARRAY
------------------------
DECLARE
TYPE t_numbers IS VARRAY(4) OF NUMBER;
nums t_numbers := t_numbers();
BEGIN
nums.EXTEND(4);
nums(1) := 10;
nums(2) := 20;
nums(3) := 30;
nums(4) := 40;
nums.TRIM(1); -- removes last element (40)
FOR i IN 1 .. nums.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Index ' || i || ': ' || nums(i));
END LOOP;
END;
Comparison Summary
-------------------
| Collection Type | Index Type | Can Store in Table? | Gaps Allowed? | Use
Case |
|--------------------|----------------|----------------------|---------------|-----
------------------------------|
| Associative Array | Integer/String | ❌ | ✅ |
Lookups, temporary in-memory data |
| Nested Table | Integer | ✅ | ✅ |
Dynamic-sized lists |
| VARRAY | Integer | ✅ | ❌ |
Fixed-size ordered data |
--- END OF NOTES ---
4. EXCEPTION HANDLING IN PL/SQL
-------------------------------
What is Exception Handling?
----------------------------
Exception handling lets you catch and manage errors in your PL/SQL programs during
runtime.
Basic Syntax:
-------------
BEGIN
-- Code that might cause error
EXCEPTION
WHEN exception_name THEN
-- Error handling code
END;
Types of Exceptions:
---------------------
1. Predefined Exceptions: Built-in (e.g., ZERO_DIVIDE, NO_DATA_FOUND)
2. User-defined Exceptions: Declared by the programmer
3. Unnamed/Internal Exceptions: Caught using WHEN OTHERS
Predefined Exception Examples:
-------------------------------
| Exception | Triggered When... |
|-----------------|--------------------------------------------|
| NO_DATA_FOUND | SELECT INTO returns no rows |
| TOO_MANY_ROWS | SELECT INTO returns more than one row |
| ZERO_DIVIDE | Division by zero |
| VALUE_ERROR | Data type mismatch |
Example: ZERO_DIVIDE
---------------------
DECLARE
num1 NUMBER := 10;
num2 NUMBER := 0;
result NUMBER;
BEGIN
result := num1 / num2;
DBMS_OUTPUT.PUT_LINE('Result is: ' || result);
EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE('Cannot divide by zero!');
END;
User-Defined Exception Example:
-------------------------------
DECLARE
e_invalid_salary EXCEPTION;
salary NUMBER := 1000;
BEGIN
IF salary < 5000 THEN
RAISE e_invalid_salary;
END IF;
EXCEPTION
WHEN e_invalid_salary THEN
DBMS_OUTPUT.PUT_LINE('Salary too low!');
END;
WHEN OTHERS (Catch-All):
-------------------------
BEGIN
-- Some risky operation
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An unexpected error occurred!');
END;
SQLERRM and SQLCODE:
---------------------
BEGIN
-- Error-prone code
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('Error Code: ' || SQLCODE);
END;
Practice Task:
---------------
- Accept a number from user.
- Divide 100 by the number.
- Catch ZERO_DIVIDE and OTHERS.
(Solution can be added later.)
--- END OF EXCEPTION HANDLING SECTION ---