1. What is a Cursor FOR LOOP?
A Cursor FOR LOOP executes a block of code once for every row returned by a cursor or query.
Basic syntax:
FOR record_name IN cursor_name
LOOP
statements;
END LOOP;
Example:
DECLARE
CURSOR emp_cursor IS
SELECT employee_id, first_name, salary
FROM employees;
BEGIN
FOR emp IN emp_cursor
LOOP
DBMS_OUTPUT.PUT_LINE(
emp.employee_id || ' - ' ||
emp.first_name || ' - ' ||
emp.salary
);
END LOOP;
END;
/
2. Why use a Cursor FOR LOOP?
It simplifies cursor processing. With a traditional explicit cursor, you need DECLARE, OPEN, FETCH, LOOP, EXIT, and CLOSE. With a Cursor FOR LOOP, Oracle automatically handles the cursor lifecycle.
FOR emp IN emp_cursor
LOOP
...
END LOOP;
Main advantage: No explicit OPEN, FETCH, or CLOSE is required.
3. What happens internally in a Cursor FOR LOOP?
Conceptually, PL/SQL performs this sequence:
Open cursor
↓
Fetch row 1
↓
Execute loop body
↓
Fetch row 2
↓
Execute loop body
↓
Fetch row 3
↓
Execute loop body
↓
No more rows
↓
Close cursor
4. Do we need to OPEN the cursor?
No. The Cursor FOR LOOP automatically opens the cursor.
5. Do we need to FETCH the cursor?
No. The Cursor FOR LOOP automatically fetches each row.
6. Do we need to CLOSE the cursor?
No. Oracle automatically closes the cursor after the loop finishes.
7. What is the syntax using a declared cursor?
DECLARE
CURSOR emp_cursor IS
SELECT employee_id, first_name
FROM employees;
BEGIN
FOR emp IN emp_cursor
LOOP
DBMS_OUTPUT.PUT_LINE(emp.first_name);
END LOOP;
END;
/
Here, emp_cursor is the explicit cursor and emp is the loop record.
8. What is the loop record?
The variable after FOR is called the loop record. You can access the columns using emp.employee_id, emp.first_name, and emp.salary.
9. Do we need to declare the loop record?
No. PL/SQL automatically creates the loop record.
BEGIN
FOR emp IN (
SELECT employee_id, first_name, salary
FROM employees
)
LOOP
DBMS_OUTPUT.PUT_LINE(emp.first_name);
END LOOP;
END;
/
10. Can we use a query directly in a Cursor FOR LOOP?
Yes. This is called an implicit cursor FOR LOOP.
BEGIN
FOR emp IN (
SELECT employee_id, first_name, salary
FROM employees
WHERE department_id = 10
)
LOOP
DBMS_OUTPUT.PUT_LINE(
emp.employee_id || ' - ' ||
emp.first_name
);
END LOOP;
END;
/
11. Named cursor vs Inline query
| Named Cursor | Inline Query |
|---|---|
| Cursor declared separately | Query written directly |
| Can be reused | Usually used for one loop |
| More structured | Shorter and convenient |
12. Can a Cursor FOR LOOP process multiple rows?
Yes. If 100 rows are returned, the loop executes 100 times.
13. What if the query returns no rows?
The loop simply executes zero times. A Cursor FOR LOOP with zero rows does not raise NO_DATA_FOUND.
BEGIN
FOR emp IN (
SELECT employee_id, first_name
FROM employees
WHERE employee_id = 999999
)
LOOP
DBMS_OUTPUT.PUT_LINE(emp.first_name);
END LOOP;
DBMS_OUTPUT.PUT_LINE('Loop completed');
END;
/
14. Can we use WHERE conditions?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id, first_name, salary
FROM employees
WHERE salary > 50000
)
LOOP
DBMS_OUTPUT.PUT_LINE(
emp.first_name || ' earns ' ||
emp.salary
);
END LOOP;
END;
/
15. Can we use ORDER BY?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id, first_name, salary
FROM employees
ORDER BY salary DESC
)
LOOP
DBMS_OUTPUT.PUT_LINE(
emp.first_name || ' - ' || emp.salary
);
END LOOP;
END;
/
16. Can we use joins?
Yes.
BEGIN
FOR emp IN (
SELECT e.employee_id,
e.first_name,
d.department_name
FROM employees e
JOIN departments d
ON e.department_id = d.department_id
)
LOOP
DBMS_OUTPUT.PUT_LINE(
emp.first_name || ' - ' ||
emp.department_name
);
END LOOP;
END;
/
17. Can we use aggregate functions?
Yes.
BEGIN
FOR rec IN (
SELECT department_id,
COUNT(*) AS employee_count,
AVG(salary) AS average_salary
FROM employees
GROUP BY department_id
)
LOOP
DBMS_OUTPUT.PUT_LINE(
'Department: ' || rec.department_id ||
', Employees: ' || rec.employee_count ||
', Average: ' || rec.average_salary
);
END LOOP;
END;
/
18. Can we use IF inside a Cursor FOR LOOP?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id, first_name, salary
FROM employees
)
LOOP
IF emp.salary >= 100000 THEN
DBMS_OUTPUT.PUT_LINE(
emp.first_name || ' - High salary'
);
ELSE
DBMS_OUTPUT.PUT_LINE(
emp.first_name || ' - Regular salary'
);
END IF;
END LOOP;
END;
/
19. Can we use UPDATE inside a Cursor FOR LOOP?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id, salary
FROM employees
WHERE department_id = 10
)
LOOP
IF emp.salary < 50000 THEN
UPDATE employees
SET salary = salary + 5000
WHERE employee_id = emp.employee_id;
END IF;
END LOOP;
```
COMMIT;
```
END;
/
20. Can we use DELETE inside a Cursor FOR LOOP?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id
FROM employees
WHERE salary < 20000
)
LOOP
DELETE FROM employees
WHERE employee_id = emp.employee_id;
END LOOP;
```
COMMIT;
```
END;
/
21. What is FOR UPDATE in a Cursor FOR LOOP?
FOR UPDATE can be used when the selected rows are going to be updated or deleted.
DECLARE
CURSOR emp_cursor IS
SELECT employee_id, salary
FROM employees
WHERE department_id = 10
FOR UPDATE;
BEGIN
FOR emp IN emp_cursor
LOOP
IF emp.salary < 50000 THEN
UPDATE employees
SET salary = salary + 5000
WHERE CURRENT OF emp_cursor;
END IF;
END LOOP;
COMMIT;
END;
/
22. What is WHERE CURRENT OF?
WHERE CURRENT OF refers to the current row selected by a FOR UPDATE cursor.
UPDATE employees
SET salary = salary + 1000
WHERE CURRENT OF emp_cursor;
Remember:
FOR UPDATE
↓
Cursor identifies/locks rows for update
↓
WHERE CURRENT OF
↓
Update/delete current row
23. Can a parameterized cursor be used with a Cursor FOR LOOP?
Yes.
DECLARE
CURSOR emp_cursor(p_dept_id NUMBER) IS
SELECT employee_id, first_name, salary
FROM employees
WHERE department_id = p_dept_id;
BEGIN
FOR emp IN emp_cursor(10)
LOOP
DBMS_OUTPUT.PUT_LINE(
emp.employee_id || ' - ' ||
emp.first_name
);
END LOOP;
END;
/
24. Can we pass different parameters?
Yes.
DECLARE
CURSOR emp_cursor(p_dept_id NUMBER) IS
SELECT employee_id, first_name
FROM employees
WHERE department_id = p_dept_id;
BEGIN
FOR emp IN emp_cursor(10)
LOOP
DBMS_OUTPUT.PUT_LINE(emp.first_name);
END LOOP;
```
FOR emp IN emp_cursor(20)
LOOP
DBMS_OUTPUT.PUT_LINE(emp.first_name);
END LOOP;
```
END;
/
25. Can we use %ROWCOUNT with a Cursor FOR LOOP?
The loop itself automatically manages fetching, so you generally do not need cursor attributes for basic iteration. If you need a count of processed rows, maintain your own counter.
DECLARE
v_count NUMBER := 0;
BEGIN
FOR emp IN (
SELECT employee_id, first_name
FROM employees
)
LOOP
v_count := v_count + 1;
DBMS_OUTPUT.PUT_LINE(emp.first_name);
END LOOP;
DBMS_OUTPUT.PUT_LINE(
'Total rows processed: ' || v_count
);
END;
/
26. Can we use EXIT inside a Cursor FOR LOOP?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id, first_name
FROM employees
ORDER BY employee_id
)
LOOP
DBMS_OUTPUT.PUT_LINE(emp.first_name);
```
EXIT WHEN emp.employee_id = 105;
END LOOP;
```
END;
/
27. Can we use CONTINUE inside a Cursor FOR LOOP?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id, first_name, salary
FROM employees
)
LOOP
CONTINUE WHEN emp.salary < 30000;
```
DBMS_OUTPUT.PUT_LINE(
emp.first_name || ' - ' || emp.salary
);
END LOOP;
```
END;
/
28. EXIT vs CONTINUE
| EXIT | CONTINUE |
|---|---|
| Terminates the loop | Skips the current iteration |
| Stops processing completely | Moves to the next row |
29. Can we use an exception handler?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id, first_name
FROM employees
)
LOOP
DBMS_OUTPUT.PUT_LINE(emp.first_name);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;
/
30. What happens if an error occurs inside the loop?
Control transfers to the applicable exception handler. For a Cursor FOR LOOP, the cursor is automatically managed by PL/SQL.
31. Do we need to explicitly CLOSE the cursor in an exception?
No. For a Cursor FOR LOOP, no manual close is required.
32. Cursor FOR LOOP vs Traditional Explicit Cursor
Traditional explicit cursor:
DECLARE
CURSOR emp_cursor IS
SELECT employee_id, first_name
FROM employees;
```
v_id employees.employee_id%TYPE;
v_name employees.first_name%TYPE;
```
BEGIN
OPEN emp_cursor;
```
LOOP
FETCH emp_cursor INTO v_id, v_name;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_name);
END LOOP;
CLOSE emp_cursor;
```
END;
/
Cursor FOR LOOP:
DECLARE
CURSOR emp_cursor IS
SELECT employee_id, first_name
FROM employees;
BEGIN
FOR emp IN emp_cursor
LOOP
DBMS_OUTPUT.PUT_LINE(emp.first_name);
END LOOP;
END;
/
Key difference: the Cursor FOR LOOP eliminates manual OPEN, FETCH, EXIT WHEN %NOTFOUND, and CLOSE.
33. Cursor FOR LOOP vs Implicit Cursor
Implicit cursor is Oracle automatically managing a SQL statement, while the Cursor FOR LOOP processes rows using automatic cursor handling for iteration.
34. What happens if the query returns 1,000 rows?
The loop body executes once per row, so it runs 1,000 times.
35. Can the loop record be modified?
The loop record should be treated as a read-only representation of the current fetched row. To modify database data, use SQL such as UPDATE or DELETE.
36. Can we use aliases in a Cursor FOR LOOP?
Yes.
BEGIN
FOR emp IN (
SELECT employee_id AS id,
first_name AS name,
salary AS pay
FROM employees
)
LOOP
DBMS_OUTPUT.PUT_LINE(
emp.id || ' - ' ||
emp.name || ' - ' ||
emp.pay
);
END LOOP;
END;
/
37. Can we use expressions in the query?
Yes.
BEGIN
FOR emp IN (
SELECT first_name,
salary,
salary * 12 AS annual_salary
FROM employees
)
LOOP
DBMS_OUTPUT.PUT_LINE(
emp.first_name ||
' Annual Salary: ' ||
emp.annual_salary
);
END LOOP;
END;
/
38. Can we use nested Cursor FOR LOOPS?
Yes.
BEGIN
FOR dept IN (
SELECT department_id, department_name
FROM departments
)
LOOP
DBMS_OUTPUT.PUT_LINE(
'Department: ' || dept.department_name
);
```
FOR emp IN (
SELECT employee_id, first_name
FROM employees
WHERE department_id = dept.department_id
)
LOOP
DBMS_OUTPUT.PUT_LINE(
' Employee: ' || emp.first_name
);
END LOOP;
END LOOP;
```
END;
/
39. Advantages of Cursor FOR LOOP
- Simple syntax
- No explicit OPEN
- No explicit FETCH
- No explicit CLOSE
- No need to declare a loop record
- Automatically processes multiple rows
- Less code
- Lower chance of cursor-management mistakes
- Works with named cursors and inline queries
- Supports parameterized cursors
40. Disadvantages
For many straightforward row-processing tasks, there are not significant disadvantages compared with manually managed explicit cursors. However, a manually controlled explicit cursor may be preferable when you specifically need control over when the cursor is opened, fetched, or closed. For large-scale data manipulation, a set-based SQL statement is often more efficient than row-by-row processing.
41. Frequently Asked Questions
| Question | Answer |
|---|---|
| What is a Cursor FOR LOOP? | A PL/SQL loop that processes each row returned by a cursor or query. |
| Does it automatically open the cursor? | Yes. |
| Does it automatically fetch rows? | Yes. |
| Does it automatically close the cursor? | Yes. |
| Do we need EXIT WHEN cursor%NOTFOUND? | No. |
| Do we need to declare a loop variable? | No. |
| Can we use an inline SELECT? | Yes. |
| What happens if the query returns zero rows? | The loop body executes zero times. |
| Can a Cursor FOR LOOP process multiple rows? | Yes. |
| Can we use parameters? | Yes, with a parameterized cursor. |
Important Exam Points
- Cursor FOR LOOP processes rows one at a time.
- It automatically performs OPEN → FETCH → CLOSE.
- No explicit OPEN is required.
- No explicit FETCH is required.
- No explicit CLOSE is required.
- No EXIT WHEN %NOTFOUND is required.
- The loop variable is automatically created as a record.
- It can use a named cursor.
- It can use an inline query.
- Zero rows → loop body executes zero times.
- Multiple rows → loop body executes once per row.
- FOR UPDATE and WHERE CURRENT OF can be used for appropriate update scenarios.
- EXIT terminates the loop.
- CONTINUE skips the current iteration.
- Parameterized cursors can be used with Cursor FOR LOOP.
- For large set-based changes, prefer a single SQL statement when possible.
Quick Revision
CURSOR FOR LOOP
|
+-----+-----+
| |
Named Inline Query
Cursor (SELECT ...)
| |
+-----+-----+
|
Automatic
|
OPEN → FETCH → CLOSE
|
Process each row
One-line memory trick: Cursor FOR LOOP = process every returned row without manually OPENing, FETCHing, or CLOSEing the cursor.
No comments:
Post a Comment