为什么我的保存点和回滚没有按预期工作?

时间:2015-03-26 11:56:54

标签: plsql

所以我有两个相同的表,叫做SRC和EMP,我在emp表的ename字段上创建了一个唯一的索引。我想要做的是将员工从src表复制到emp表中,同时尊重员工姓名的唯一性条件。问题是它应该复制NIKON和两个CANON家伙中的一个......但它只复制NIKON。我被迫使用预先定义的例外,但我不知道该缺陷在哪里。我需要类似goto的东西,但有人建议使用异常。

Create Unique Index EIndex ON emp (ename)
Drop table SRC;
Create table SRC (EMPNO NUMBER(4) NOT NULL, ENAME CHAR(10), JOB CHAR(9), MGR NUMBER(4), COPIED NUMBER(1));
Insert into SRC (EMPNO, ENAME, JOB, MGR, COPIED) Values(9001,'NIKON','ANALYST',7902,null);
Insert into SRC (EMPNO, ENAME, JOB, MGR, COPIED) Values (9002,'FORD','ANALYST',7902,null);
Insert into SRC (EMPNO, ENAME, JOB, MGR, COPIED) Values (9003,'CANON','ANALYST',7902,null);
Insert into SRC (EMPNO, ENAME, JOB, MGR, COPIED) Values (9004,'CANON','ANALYST',7902,null);

DECLARE
   Cursor copy_emp_cursor IS
   Select empno, ename, job, mgr from SRC;
   v_record copy_emp_cursor%ROWTYPE;
BEGIN   
OPEN copy_emp_cursor;
LOOP
    Fetch copy_emp_cursor INTO v_record;
    EXIT WHEN copy_emp_cursor%NOTFOUND;
    Savepoint do_insert;
    INSERT INTO emp (empno, ename, job, mgr) values(v_record.empno, v_record.ename, v_record.job, v_record.mgr);
    UPDATE SRC set COPIED = 1 where empno=v_record.empno;
END LOOP;
CLOSE copy_emp_cursor;
EXCEPTION
    WHEN DUP_VAL_ON_INDEX THEN
    ROLLBACK TO do_insert;
    UPDATE SRC set copied = 0 where ename=v_record.ename;
END;

1 个答案:

答案 0 :(得分:1)

您应该在循环内处理DUP_VAL_ON_INDEX异常,以便循环可以继续使用下一条记录。我还建议您使用游标FOR-loop而不是显式游标 - 它会缩短代码并允许PL / SQL执行某些优化,如果您使用显式游标则无法执行这些优化:

BEGIN   
  FOR v_record IN (Select empno, ename, job, mgr from SRC)
  LOOP
    BEGIN
      INSERT INTO emp (empno, ename, job, mgr)
        values(v_record.empno, v_record.ename, v_record.job, v_record.mgr);

      UPDATE SRC set COPIED = 1 where empno=v_record.empno;
    EXCEPTION
      WHEN DUP_VAL_ON_INDEX THEN
        UPDATE SRC set copied = 0 where ename=v_record.ename;
    END;
  END LOOP;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Exception: ' || SQLCODE || ' - ' || SQLERRM);
    ROLLBACK;
END;

分享并享受。