Использование курсоров в цикле в PL / SQL

#plsql #cursor

#plsql #курсор

Вопрос:

У меня есть таблица, которая содержит 3 столбца.Имя первого столбца — id , имя второго столбца — parent_id, а третье — выражение.Что я хочу сделать, так это выполнить поиск в столбце выражения для идентификатора.Например, я отправляю значение id, затем, если столбец parent_id имеет значение, я хочу отправить значение parent_id и хочу проверить, имеет столбец выражения ‘E’ или нет.Если он имеет нулевое значение, а результат имеет parent_id, тогда я хочу отправить значение parent_id и снова хочу проверить, имеет столбец выражения ‘E’ или нет.Если столбец выражения имеет значение, подобное ‘E’, я обновил переменную resultValue как 1 и завершил цикл.

моя таблица A: она должна возвращать resultValue =1

 id  |parent_id|expression
123 |null     | null
45  |123      | 'E'
22  |45       | null
  

моя таблица B: она должна возвращать resultValue = 0

 id  |parent_id|expression
30  |null     | null
20  |30       | null
10  |20       | null
  

моя таблица C: она должна возвращать resultValue = 0

 id  |parent_id|expression
30  |null     | null
20  |30       | null
10  |null     | null
  

Если первая отправка id(10) не содержит parent_id(таблица C), переменная resultValue должна быть равна 0. Если я нахожу выражение ‘E’, любая переменная результирующего значения родительской строки должна возвращать 1.

Я создал блок кода с курсором.Впервые я использовал курсор.Я не уверен, что использование курсора с такой проблемой — хорошая идея или нет.Мой код запущен, но открыть курсор, затем закрыть курсор, а затем снова открыть курсор, это хорошая идея?

 DECLARE
  resultValue NUMBER := 0;
  CURSOR c(v_id NUMBER )
  IS
    SELECT id_value, id_parent, expression FROM students WHERE id_value = v_id;
PROCEDURE print_overpaid
IS
  id_value   NUMBER;
  id_parent  NUMBER;
  expression VARCHAR2(20);
BEGIN
  LOOP
    FETCH c INTO id_value, id_parent, expression;
    EXIT
  WHEN c%NOTFOUND;
    IF id_parent IS NULL AND expression IS NULL THEN
      EXIT;
    END IF;
    IF id_parent IS NOT NULL THEN
      CLOSE c;
      OPEN c(id_parent);
    ELSIF id_parent <> NULL AND expression = 'X' OR id_parent IS NULL AND expression = 'X' THEN
      resultValue   := 1;
      EXIT;
    END IF;
   END LOOP;
END print_overpaid;
BEGIN
  OPEN c(22);
  print_overpaid;
  DBMS_OUTPUT.PUT_LINE('  My resultValue is : ' || resultValue);
  CLOSE c;
END;
  

Ответ №1:

Если я правильно понял ваше описание, вы хотите увидеть, что указанный идентификатор любой строки в родительском элементе содержит ‘E’ в выражении столбца. Вы правы, что закрытие и повторное открытие курсора на самом деле не очень хорошая идея. Хотя мне нравится, что вы используете вложенную процедуру. Однако на самом деле в этом нет необходимости, поскольку это можно решить с помощью одного запроса. Подход будет рекурсивным CTE, который проверяет целевую строку на ‘E’ до тех пор, пока строка не будет содержать ее или строка не будет иметь родительского элемента.

 with search_for_e(id, parent_id, e_cnt) as 
     ( select id, parent_id, case when expression = 'E' then 1 else 0 end 
         from exp_tbl
       where id = amp;id
       union all 
       select t.id,t.parent_id, case when t.expression = 'E' then 1 else 0 end
       from search_for_e s
       join exp_tbl t on (t.id = s.parent_id) 
       where t.parent_id is not null 
         and s.e_cnt = 0
   ) 
select max(e_cnt) 
  from search_for_e;
  

Смотрите fiddle здесь, он также содержит реализацию анонимного блока с вложенной функцией и с курсором.

Комментарии:

1. Добро пожаловать. Если ответ разрешил или существенно помог решить вашу проблему, пожалуйста, примите ответ. Это очень помогает другим, у которых может возникнуть такая же проблема в будущем. Пожалуйста, не оставляйте успешно отвеченные вопросы в статусе неотвеченные / неразрешенные.