为什么我的保存点和回滚没有按预期工作?
Why aren't my save point and rollback work as expected?
所以我有两个相同的 table,分别称为 SRC 和 EMP,我在 emp table 的 ename 字段上创建了一个唯一索引。我想要做的是将员工从 src table 复制到 emp table 中,同时尊重员工姓名的唯一性条件。问题是它应该复制 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;
您应该在循环内处理 DUP_VAL_ON_INDEX 异常,以便循环可以简单地继续处理下一条记录。我还建议您使用游标 FOR 循环而不是显式游标 - 它可以缩短代码并允许 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;
分享和享受。
所以我有两个相同的 table,分别称为 SRC 和 EMP,我在 emp table 的 ename 字段上创建了一个唯一索引。我想要做的是将员工从 src table 复制到 emp table 中,同时尊重员工姓名的唯一性条件。问题是它应该复制 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;
您应该在循环内处理 DUP_VAL_ON_INDEX 异常,以便循环可以简单地继续处理下一条记录。我还建议您使用游标 FOR 循环而不是显式游标 - 它可以缩短代码并允许 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;
分享和享受。