简体   繁体   中英

What's the point of parameterized cursors in PL/SQL?

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.

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, ie 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, eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM