Reputation: 13
Could someone explain what's the point of using a parameterized cursor in PL/SQL instead of just creating a variable and using that inside?
The following anonymous block shows what I mean:
DECLARE
num NUMBER := 1;
CURSOR d1 (p_num IN NUMBER) IS SELECT 'foo' FROM dual WHERE 1 = p_num;
CURSOR d2 IS SELECT 'foo' FROM dual WHERE 1 = num;
BEGIN
NULL;
END;
Is there any kind of difference in processing/performance/etc between cursors d1 and d2?
Thanks in advance.
Upvotes: 1
Views: 640
Reputation: 191275
You might not know your p_num
value until runtime. It might be something you get from other processing, or another table, or the client environment, or calculate somehow.
As a trivial example:
declare
cursor c1 is
select * from departments;
cursor c2 (p_department_id employees.department_id%type) is
select * from employees
where department_id = p_department_id;
begin
for r1 in c1 loop
-- do something with this department info
dbms_output.put_line(r1.department_name);
-- now loop through empoyees in that department
for r2 in c2 (r1.department_id) loop
-- do something with this employee info
dbms_output.put_line(' ' || r2.first_name);
end loop;
end loop;
end;
/
Administration
Jennifer
Marketing
Michael
Pat
Purchasing
Den
Alexander
...
The c2
cursor is looking for employees in a single department, but that can't be hard-coded.
You could do the same thing with the equivalent of your d2
construct, i.e. assigning a separate local variable which the inner cursor will still use - since it's being reopened and evaluates the variable at that point:
declare
l_department_id departments.department_id%type;
cursor c1 is
select * from departments;
cursor c2 is
select * from employees
where department_id = l_department_id;
begin
for r1 in c1 loop
-- do something with this department info
dbms_output.put_line(r1.department_name);
-- ...
-- now loop through empoyees in that department
l_department_id := r1.department_id;
for r2 in c2 loop
-- do something with this employee info
dbms_output.put_line(' ' || r2.first_name);
end loop;
end loop;
end;
/
... but having a parameter makes it clearer that the value is expected to change, and avoids the possibility of making two calls and forgetting to change the value in between.
In both cases the actual SQL of the cursor query will be treated as having a bind variable; the difference is just how that is populated.
Clearly you wouldn't really do this particular task with nested loops, or any PL/SQL; and in a lot of places this kind of construct is used the same applies, or the queries could at least be combined into a single cursor with a join.
It can still be useful for more complicated logic, e.g. where there are several paths the code could take and multiple optional secondary cursors, and all need information from the same (expensive) base query, and you don't want to repeatedly join to the base tables.
As with most row-by-row processing I suspect it's misused more often than it's genuinely necessary. It's still a useful tool to have available though.
Upvotes: 4