我有这个程序:
create or replace PROCEDURE CONVERTE
IS
CURSOR oldemployees IS
SELECT *
FROM emp1
WHERE data_saida= NULL;
new_ndep emp1.num_dep%type;
bi_inexistente EXCEPTION;
dep_inexistente EXCEPTION;
employeeNr emp1.num_empregado%type;
BEGIN
FOR old_emp IN oldemployees
LOOP
employeeNr:= old_emp.num_empregado;
if (old_emp.bi = NULL) then
raise bi_inexistente;
else
IF (old_emp.num_dep>20) THEN
SELECT ndep_novo INTO new_ndep FROM Converte_dep WHERE ndep_antigo= old_emp.num_dep;
elsif (old_emp.num_dep = NULL) then
new_ndep:= 0;
raise dep_inexistente;
end if;
INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida, new_ndep);
COMMIT;
end if;
end loop;
EXCEPTION
when bi_inexistente then
INSERT INTO ERROS VALUES(employeeNr, 'BI Inexistente');
COMMIT;
when dep_inexistente then
INSERT INTO ERROS VALUES(employeeNr, 'Departamento Inexistente');
COMMIT;
end;
我想INSERT INTO EMP2 VALUES(old_emp.bi,old_emp.nome,old_emp.morada,old_emp.data_entrada,old_emp.data_saida,new_ndep);即使在提升dep_inexistente之后,但在阅读了oracle的参考之后,我有点困惑;基本上,当它为null时,我想不要插入,否则我想插入,即使部门号为空(我转向0)。
那么,代码是否正确,或者我应该如何提出异常或处理我案例的预定义异常?
答案 0 :(得分:3)
我想INSERT INTO EMP2 VALUES (old_emp.bi,old_emp.nome, old_emp.morada,old_emp.data_entrada, old_emp.data_saida,new_ndep);甚至 在提升dep_inexistente
之后
诀窍是在执行插入后引发异常。引发的异常是有效的GOTO
语句 - 控制流直接转到EXCEPTIONS块。在下面的重写中,我使用了new_dep的设置作为提升异常的信号。您可能知道一些其他业务逻辑使这种方法无效(即,有一些合理的理由说明为什么记录会使部门为零)。在这种情况下,您需要设置一个标志。
create or replace PROCEDURE CONVERTE IS
CURSOR oldemployees IS
SELECT *
FROM emp1
WHERE data_saida= NULL;
new_ndep emp1.num_dep%type;
bi_inexistente EXCEPTION;
dep_inexistente EXCEPTION;
employeeNr emp1.num_empregado%type;
BEGIN
FOR old_emp IN oldemployees
LOOP
employeeNr:= old_emp.num_empregado;
if (old_emp.bi is NULL) then
raise bi_inexistente;
else
if (old_emp.num_dep>20) THEN
SELECT ndep_novo INTO new_ndep FROM Converte_dep WHERE ndep_antigo= old_emp.num_dep;
elsif (old_emp.num_dep is NULL) then
new_ndep:= 0;
end if;
INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida, new_ndep);
COMMIT;
if new_ndep = 0 then
raise dep_inexistente;
end if;
end if;
end loop;
EXCEPTION
when bi_inexistente then
INSERT INTO ERROS VALUES(employeeNr, 'BI Inexistente');
COMMIT;
when dep_inexistente then
INSERT INTO ERROS VALUES(employeeNr, 'Departamento Inexistente');
COMMIT;
end;
关于你的一般方法的三件事:
修改强>
实际上,您的代码提出了许多关于程序逻辑的问题。远远超过我希望进入这里。我上面列出的三个是一般的“最佳实践”问题,但条件流的详细逻辑看起来不合适。但后来我不知道你正在实施的业务规则。
答案 1 :(得分:2)
我不认为例外应该被用作不优雅的GOTO声明。如果要构建代码,可以使用过程(和子过程)。如果在代码中的某个位置完成工作,只需使用RETURN语句。只有在有意义时才捕获异常。
答案 2 :(得分:1)
您的代码中存在错误:old_emp.num_dep = NULL
无效,始终为假。
假设它本来是old_emp.num_dep IS NULL
,那么我认为你的代码根据你的意图不起作用。绕过INSERT INTO EMP2会引发异常。
如果这是我的代码,并且逻辑是这样的,你可以决定在部门丢失的情况下插入EMP2不是真正的错误,我不会引发异常。你也没有失去那些信息,因为你总能看到有缺少的部门(即每个以0为部门的emp)
BTW是否有一个特殊的原因为部门使用0?为什么不使用NULL
?显然你已经决定让员工没有部门,NULL
是公平的代表。
如果你坚持认为emp错过了一个部门实际上是一个错误,但仍然认为无论如何都可以插入EMP,我会考虑这样写:
IF ... THEN
... -- ok
END IF;
INSERT INTO EMP2 VALUES (
old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida,
NVL(new_ndep, 0)
);
IF new_ndep IS NULL THEN
raise dep_inexistente;
END IF;
我建议你在代码中添加一些注释,因为如果我找到像上面所写的代码,我可能会怀疑是一个错误。
答案 3 :(得分:0)
所以,如果我保留例外,那就像这样:
create or replace PROCEDURE CONVERTE IS
CURSOR oldemployees IS
SELECT *
FROM emp1
WHERE data_saida= NULL;
new_ndep emp1.num_dep%type;
bi_inexistente EXCEPTION;
dep_inexistente EXCEPTION;
employeeNr emp1.num_empregado%type;
BEGIN
FOR old_emp IN oldemployees
LOOP
employeeNr:= old_emp.num_empregado;
if (old_emp.bi is NULL) then
raise bi_inexistente;
else
if (old_emp.num_dep>20) THEN
SELECT ndep_novo INTO new_ndep FROM Converte_dep WHERE ndep_antigo= old_emp.num_dep;
else
INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida,nvl(old_emp.num_dep,0));
end if;
if new_ndep is NULL then
raise dep_inexistente;
end if;
end if;
end loop;
EXCEPTION
when bi_inexistente then
INSERT INTO ERROS VALUES(employeeNr, 'BI Inexistente');
COMMIT;
when dep_inexistente then
INSERT INTO ERROS VALUES(employeeNr, 'Departamento Inexistente');
COMMIT;
end;
或者我可以做所说的事情而不会引发异常;但我仍然需要使用光标。
create or replace
PROCEDURE CONVERTE2 IS
CURSOR oldemployees IS
SELECT *
FROM emp1
WHERE data_saida= NULL;
new_ndep emp1.num_dep%type;
bi_inexistente EXCEPTION;
dep_inexistente EXCEPTION;
employeeNr emp1.num_empregado%type;
v_error_code NUMBER:=0;
v_error_message VARCHAR2(255);
BEGIN
FOR old_emp IN oldemployees
LOOP
employeeNr:= old_emp.num_empregado;
if (old_emp.bi is NULL) then
INSERT INTO ERROS VALUES(employeeNr, 'BI Inexistente');
else
if (old_emp.num_dep>20) THEN
SELECT ndep_novo INTO new_ndep FROM Converte_dep WHERE ndep_antigo= old_emp.num_dep;
else
INSERT INTO EMP2 VALUES (old_emp.bi, old_emp.nome, old_emp.morada, old_emp.data_entrada, old_emp.data_saida,nvl(old_emp.num_dep,0));
end if;
if new_ndep is NULL then
INSERT INTO ERROS VALUES(employeeNr, 'Departamento Inexistente');
end if;
end if;
end loop;
COMMIT;
EXCEPTION
When others Then
ROLLBACK;
/*eventually log something into erro table*/
end;
那你怎么改写呢,所以看起来不那么“不确定”?我不得不承认,这有点混乱。无论如何,至少你给了我非常实际的见解。 我想看看一些更好的方法,如果你愿意,我很感兴趣。