我正在完成学校作业,我必须在所有PL / SQL中添加例外。由于我已经创建了一些序列和触发器来添加自动增量功能(这是Oracle SQL),我想我会在ORA-01400: cannot insert NULL into(...)
的所有触发器上添加一个例外。
在example here之后,我创建了一个用于存储自定义异常的包,因此我可以在实现自动增量的所有触发器中使用它:
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: cannot insert NULL into (...)
而不是我想要的DBMS_OUTPUT。
我已经在网站上查看了几次示例并且看不出任何差异,除了在程序中使用异常而不是触发器。那是问题吗?如果是这样,我怎样才能在触发器中完成这项工作?
(OBS。这只是一个演示错误处理的学校练习; DBMS_OUTPUT在这种情况下可能没有用,但这与此练习无关)
答案 0 :(得分:0)
试试这个:
它应该是这样的:
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;
答案 1 :(得分:0)
问题与您在评论中提到的一样。在insert
触发器触发并完成后,ORA-01400由before
引发。如果不是这种情况,您将无法从触发器自动设置不可为空的列 - 例如,从序列设置主键值(模仿自动增量ID),就像设置{ {1}}。在附加到触发器的PL / SQL块中没有引发异常。
您可以在触发器中手动和显式地检查每个不可为空的列,并在任何为空时引发您自己的异常,但您实际上只是复制内置功能。并且假设您跟踪列定义 - 如果更改列的可为空性,则必须记住更新触发器以匹配,除非您想要在运行时动态检查列 - 这将是如果可能的话,最好是狡猾的(cust_id
)。
如果您的作业实际上并不需要这种自定义处理,那么似乎需要付出很多努力才能获得真正的收益。 Oracle recommend you don't use triggers when you can use constraints;我知道这是一个练习,但即便如此,这也不是你想要做的事情。
在您显示的触发器中强制运行时错误的一种方法是操纵序列,以便您尝试超过其dbms_sql
:
MAXVALUE
然后前三个插入将起作用,第四个插入将失败:
CREATE TABLE customer (cust_id NUMBER PRIMARY KEY, name VARCHAR2(20));
CREATE SEQUENCE pk_cust_seq MINVALUE 1 MAXVALUE 3 NOCYCLE;
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 OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Unable to create cust_id.');
RAISE;
END;
/
您已经拥有了序列,因此在您的情况下,您可以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.
将alter sequence
上限设置在当前最高值之上,并确保设置maxvalue
;然后导致错误,并在完成测试后将其重置为高值。
另外,另外,如果您使用11g,则有两种方法可以将序列号分配给列;在11g之前你必须按照你所示的那样去做:
nocycle
...但现在你可以这样做:
SELECT pk_cust_seq.NEXTVAL INTO :NEW.CUST_ID FROM DUAL;