Sql ORA01400不工作的自定义异常
我正在做一个学校作业,我必须在所有PL/SQL中添加异常。由于我已经创建了一些序列和触发器来添加自动增量功能,这就是Oracle SQL,我想我应该为所有与ORA-01400有关的触发器添加一个例外:不能将NULL插入到 接下来,我创建了一个包来存储自定义异常,因此我可以在实现自动递增的所有触发器中使用它:Sql ORA01400不工作的自定义异常,sql,oracle,exception-handling,triggers,Sql,Oracle,Exception Handling,Triggers,我正在做一个学校作业,我必须在所有PL/SQL中添加异常。由于我已经创建了一些序列和触发器来添加自动增量功能,这就是Oracle SQL,我想我应该为所有与ORA-01400有关的触发器添加一个例外:不能将NULL插入到 接下来,我创建了一个包来存储自定义异常,因此我可以在实现自动递增的所有触发器中使用它: CREATE OR REPLACE PACKAGE my_exceptions AS insert_null_into_notnull EXCEPTION; PRAGMA E
CREATE OR REPLACE PACKAGE my_exceptions
AS
insert_null_into_notnull EXCEPTION;
PRAGMA EXCEPTION_INIT(insert_null_into_notnull, -1400);
END my_exceptions;
/
这是触发因素之一:
CREATE OR REPLACE TRIGGER update_cust_id
BEFORE INSERT ON CUSTOMER
FOR EACH ROW
BEGIN
SELECT pk_cust_seq.NEXTVAL INTO :NEW.CUST_ID FROM DUAL;
EXCEPTION
WHEN my_exceptions.insert_null_into_notnull THEN
DBMS_OUTPUT.PUT_LINE('Attempted to insert a null value into not nullable column.');
RAISE;
END;
/
问题是,当我试图故意添加一个失败的插入时,仍然会出现典型的Oracle错误:ORA-01400:Cannotesinsert NULL-into。。。而不是我想要的DBMS_输出
我已经在网站上看过这个例子好几次了,除了在过程中使用异常而不是触发器之外,我看不出有什么不同。这就是问题所在吗?如果是这样的话,我怎样才能使它在触发器中工作
OBS。这只是一个演示错误处理的学校练习;DBMS_输出在这种情况下可能没有用处,但这与本练习无关
应该是这样的:
CREATE OR REPLACE TRIGGER update_cust_id
BEFORE INSERT ON CUSTOMER
FOR EACH ROW
BEGIN
BEGIN
SELECT pk_cust_seq.NEXTVAL INTO :NEW.CUST_ID FROM DUAL;
EXCEPTION
WHEN OTHERS THEN
IF (SQLCODE=01040) THEN
RAISE my_exceptions.insert_null_into_notnull;
ELSE
RAISE;
END;
EXCEPTION
WHEN my_exceptions.insert_null_into_notnull THEN
DBMS_OUTPUT.PUT_LINE('Attempted to insert a null value into not nullable column.');
RAISE;
END;
这个问题正如你在评论中提到的。触发并完成before触发器后,插入将引发ORA-01400。如果不是这样,您将无法从触发器中自动设置不可为null的列—例如,从模拟自动增量ID的序列中设置主键值,就像您设置cust_ID一样。在附加到触发器的PL/SQL块中不会引发异常 您可以在触发器中手动显式地检查每个不可为null的列,如果有任何异常为null,则引发您自己的异常,但实际上您只是在复制内置功能。这假设您跟踪列定义—如果更改列的可空性,您必须记住更新触发器以匹配,除非您在运行时动态检查列—如果dbms_sql有可能的话,这最多也很棘手 如果您的任务实际上不需要这种定制处理,那么似乎需要付出大量的努力,却没有真正的收获。神谕我知道这是一种锻炼,但即便如此,你也不可能想去做 在显示的触发器中强制执行运行时错误的一种方法是操纵序列,以便尝试超过其最大值: 然后,前三个插入将起作用,第四个插入将失败:
set serveroutput on
insert into customer(name) values ('Customer 1')
1 rows inserted.
insert into customer(name) values ('Customer 2')
1 rows inserted.
insert into customer(name) values ('Customer 3')
1 rows inserted.
insert into customer(name) values ('Customer 4')
Error starting at line : 24 in command -
insert into customer(name) values ('Customer 4')
Error report -
SQL Error: ORA-08004: sequence PK_CUST_SEQ.NEXTVAL exceeds MAXVALUE and cannot be instantiated
ORA-06512: at "SCHEMA.UPDATE_CUST_ID", line 6
ORA-04088: error during execution of trigger 'SCHEMA.UPDATE_CUST_ID'
08004. 00000 - "sequence %s.NEXTVAL %s %sVALUE and cannot be instantiated"
*Cause: instantiating NEXTVAL would violate one of MAX/MINVALUE
*Action: alter the sequence so that a new value can be requested
Unable to create cust_id.
您已经有了序列,所以在您的例子中,您可以将序列更改为将maxvalue限制在当前最高值之上,并确保设置了nocycle;然后导致错误,并在完成测试后将其重置为高值
另外,顺便说一句,如果您在11g上,您有两种方法可以将序列号分配给列;在11g之前,您必须按照所示进行操作:
SELECT pk_cust_seq.NEXTVAL INTO :NEW.CUST_ID FROM DUAL;
。。。但现在你可以做到:
:NEW.CUST_ID := pk_cust_seq.NEXTVAL;
谢谢,但是不行。同样的问题也会发生。此外,您也没有结束if语句;-。我认为问题在于错误是由INSERT本身创建的,而不是由触发器执行的操作创建的,触发器本身不执行inserts感谢所有信息。事实上,分配只指定我的所有PL/SQL都应该进行错误处理。检查不正确的空值是我想到的与这些触发器相关的唯一事情。根据我们的结论,这里我能想到的唯一错误处理方法是从序列中获取一个值并将其插入cust_id字段,但是我想不出哪里会出错。我想我会为其他人添加一个通用的错误处理,它说“无法创建cust_id”。@Princeslilly-触发器中绝对可以有一个异常处理程序,但它只能捕获在该块中引发的异常或它调用的某个异常。您可以强制执行异常,但只能为此目的向触发器添加额外代码-尝试从字符串设置ID,伪造数字或日期问题,等等。当其他人普遍不赞成时捕获,但至少您正在引发错误;您仍然会丢失错误堆栈中的信息。是的,我同意捕获其他错误不是您所能想到的最佳错误处理方式,但故意向触发器添加代码也不会给我很多分数。错误处理应该按照我的看法解决由于块之外的情况而产生的问题,而不是我们故意造成的问题:我有另一个想法,也许我会处理由于某种原因,序列不存在的可能性可能被错误删除。这听起来比其他方法更酷,但如果序列不存在,那么触发器将无法编译;插入时会出现错误,但这不会来自异常块。除非您通过动态SQL分配它,否则这也是一种攻击。也许您可以设置seq的最大值
将值设置为较低的值,并且不设置循环-当您试图超过插入时的最大值时,应该会出现运行时异常?不,没有点以错误的方式设置序列。这样做的目的是,即使我们正确地设置了系统,也能够解释可能发生的实际错误。其他人也是如此:我相信这不会对我的分数有多大影响。感谢您指出以上关于触发器未编译的内容。
:NEW.CUST_ID := pk_cust_seq.NEXTVAL;