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;