Обновление столбца курсора с последующим использованием этого значения для выбора - PullRequest
0 голосов
/ 13 декабря 2011

У меня есть курсор, который запрашивает таблицу, подобную этой

CURSOR Cur IS
       SELECT Emp_No,status
        from Employee
        FOR UPDATE OF status;

Теперь я хотел бы обновить свой статус в таблице Employee из другой таблицы, используя Emp_no.После этого мне нужно использовать этот статус для вызова пользовательской бизнес-логики, а не исходного состояния, полученного курсором.Каков наилучший способ сделать это?Вот что я написал.Я объявил переменную v_status следующим образом:

 FOR Rec IN Cur LOOP

           BEGIN

           UPDATE Employee           
SET status = (select a.status from Employee_Status  where a.Emp_No = rec.Emp_No)
           WHERE CURRENT OF Cur ;
           COMMIT;

           END;

           SELECT status INTO v_status 
           FROM  Employee
           where Emp_No = rec.Emp_No;

            IF(v_status = 'Active') THEN
                   -- Custom Business Logic
                  ELSE  
            -- Business logic

            END IF;    
END LOOP;

Что может быть лучше для достижения этой цели?

Ответы [ 3 ]

5 голосов
/ 13 декабря 2011

1) Я надеюсь, что в вашем реальном коде у вас нет COMMIT в середине цикла.Так как фиксация снимает блокировки, удерживаемые вашей транзакцией, блокировки на уровне строк, снятые с предложением FOR UPDATE, освобождаются, и другие сеансы могут обновлять те же строки.В более поздних версиях Oracle вы получите «ORA-01002: извлечение из последовательности», если вы сделаете это.В более ранних версиях Oracle эта ошибка игнорировалась, что иногда приводило к неверным результатам.

2) Нужно ли обновлять таблицу EMPLOYEE построчно?Я бы предпочел переместить обновление за пределы цикла, чтобы максимизировать SQL, поскольку это самый эффективный способ обработки данных.Если ваша бизнес-логика поддается ей, я бы также предложил выполнять массовые операции для извлечения данных в локальные коллекции, через которые ваша бизнес-логика может перебираться, чтобы минимизировать сдвиги контекста между SQL и PL / SQL.

Итак, исходя из ваших комментариев, в вашем примере в определении вашего курсора должен быть предикат, верно?Что-то вроде этого?

CURSOR Cur IS
  SELECT Emp_No,status
    from Employee
   WHERE status IS NULL
      FOR UPDATE OF status;

Если это так, вам понадобится тот же предикат в единственном операторе UPDATE (возможно, вместо предложения EXISTS).Но поскольку вы знаете, что хотите обрабатывать только те строки, на которые повлиял ваш оператор UPDATE, вы можете просто вернуть эти строки в локальную коллекцию

DECLARE
  CURSOR cur IS 
     SELECT emp_no, status
       FROM employee
      WHERE status IS NULL;
  TYPE l_employee_array IS
    TABLE OF cur%rowtype;
  l_modified_employees l_employee_array;
BEGIN
  UPDATE employee e
     SET status = (select es.status
                     from employee_status es
                    where es.emp_no = e.emp_no)
   WHERE status IS NULL
     AND EXISTS (SELECT 1
                   FROM employee_status es
                  WHERE es.emp_no = e.emp_no)
  RETURNING emp_no, status
       BULK COLLECT INTO l_modified_employees;
  FOR i IN l_modified_employees.FIRST .. l_modified_employees.LAST
  LOOP
    IF( l_modified_employees(i).status = 'Active' ) 
    THEN
      -- Custom logic 1
    ELSE
      -- Custom logic 2
    END IF;
  END LOOP;
END;
1 голос
/ 13 декабря 2011

Вы можете использовать предложение RETURNING :

UPDATE employee
   SET status = (SELECT a.status ...)
 WHERE CURRENT OF Cur
RETURNING status INTO v_status;
1 голос
/ 13 декабря 2011

Почему бы просто:

FOR Rec IN Cur LOOP

   SELECT a.status INTO v_status from Employee_Status a where a.Emp_No = rec.Emp_No;

           UPDATE Employee           
           SET status = v_status
           WHERE CURRENT OF Cur ;
           COMMIT;

            IF(v_status = 'Active') THEN
                   -- Custom Business Logic
                  ELSE  
            -- Business logic

            END IF;    
END LOOP;
...