Какой смысл в параметризованных курсорах в PL / SQL? - PullRequest
0 голосов
/ 04 марта 2020

Может ли кто-нибудь объяснить, какой смысл использовать параметризованный курсор в PL / SQL вместо простого создания переменной и ее использования внутри?

Следующий анонимный блок показывает, что я имею в виду:

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;

Есть ли какая-либо разница в обработке / производительности / et c между курсорами d1 и d2?

Заранее спасибо.

1 Ответ

3 голосов
/ 04 марта 2020

Возможно, вы не знаете ваше значение p_num до времени выполнения. Это может быть что-то, что вы получаете из другой обработки, или из другой таблицы, или из клиентской среды, или вычисляете как-то.

В качестве тривиального примера:

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
...

Курсор c2 ищет для сотрудников в одном отделе, но это не может быть жестко запрограммировано.

Вы можете сделать то же самое с эквивалентом вашей конструкции d2, то есть назначить отдельную локальную переменную, которую будет использовать внутренний курсор по-прежнему используется - поскольку он открывается и оценивает переменную в этот момент:

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;
/

... но наличие параметра делает более понятным, что значение должно измениться, и исключает возможность двух вызовов и забыв изменить значение между ними.

В обоих случаях фактический SQL запроса курсора будет обрабатываться как имеющий переменную связывания; разница заключается только в том, как это заполнено.


Очевидно, что вы бы на самом деле не выполняли эту конкретную задачу с помощью вложенных циклов или любого PL / SQL; и во многих местах этот вид конструкции применяется так же, или запросы могут быть по крайней мере объединены в один курсор с объединением.

Это может быть полезно для более сложных логик c Например, если существует несколько путей, по которым может идти код, и несколько необязательных вторичных курсоров, и все нуждаются в информации из одного и того же (дорогого) базового запроса, и вы не хотите повторно присоединяться к базовым таблицам.

Как и в большинстве построчных обработок, я подозреваю, что они используются чаще, чем это действительно необходимо. Это все еще полезный инструмент для доступа.

...