更新游标列,然后使用该值进行选择

Eos*_*rus 0 oracle plsql cursor

我有一个查询这样的表的游标

CURSOR Cur IS
       SELECT Emp_No,status
        from Employee
        FOR UPDATE OF status;
Run Code Online (Sandbox Code Playgroud)

现在我想使用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;
Run Code Online (Sandbox Code Playgroud)

什么是更好的方法来实现这一目标?

Jus*_*ave 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;
Run Code Online (Sandbox Code Playgroud)

如果是这样,您需要在单个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;
Run Code Online (Sandbox Code Playgroud)