我有一个查询像这样的表
的游标CURSOR Cur IS
SELECT Emp_No,status
from Employee
FOR UPDATE OF status;
现在我想使用Emp_no从另一个表更新Employee表中的状态。完成此操作后,我需要使用此状态来调用自定义业务逻辑,而不是光标检索的原始状态。解决这个问题的最佳方式是什么?这是我写的。我通过
的方式声明了一个名为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;
实现这一目标的更好方法是什么?
答案 0 :(得分:5)
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 :(得分:1)
为什么不简单:
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;
答案 2 :(得分:1)
您可以使用RETURNING clause:
UPDATE employee
SET status = (SELECT a.status ...)
WHERE CURRENT OF Cur
RETURNING status INTO v_status;