Oracle 发生异常时从游标获取值
我有一个游标用于循环,当col2为零时将失败:Oracle 发生异常时从游标获取值,oracle,plsql,cursor,Oracle,Plsql,Cursor,我有一个游标用于循环,当col2为零时将失败: declare cursor cur_data is select id, col1/col2 as mean from my_table; begin for rec_data in cur_data loop update my_table set col3=rec_data.mean where id=rec_data.id; end loop; exception when othe
declare
cursor cur_data is
select id, col1/col2 as mean
from my_table;
begin
for rec_data in cur_data loop
update my_table set col3=rec_data.mean where id=rec_data.id;
end loop;
exception when others then
insert into my_log (id, error_text) values (rec_data.id, SQLERRM);
end;
我想在发生此错误时获取id列的值。类似于exception部分中的insert语句,这当然会失败,因为游标已关闭。是否可能?否您需要声明一个变量:
declare
cursor cur_data is
select id, col1/col2 as mean
from my_table;
v_id my_table.id%type;
begin
for rec_data in cur_data loop
v_id := rec_data.id;
update my_table set col3=rec_data.mean where id=rec_data.id;
end loop;
exception when others then
insert into my_log (id, error_text) values (v_id, SQLERRM);
end;
如果在循环内处理错误,您可以使用rec_data.id:
declare
cursor cur_data is
select id, col1/col2 as mean
from my_table;
begin
for rec_data in cur_data loop
begin
update my_table set col3=rec_data.mean where id=rec_data.id;
exception when others then
insert into my_log (id, error_text) values (rec_data.id, SQLERRM);
end;
end loop;
end;
在这段代码中,处理将从光标的下一行继续,而不是中止。要使其停止循环,可以添加exit
语句:
declare
cursor cur_data is
select id, col1/col2 as mean
from my_table;
begin
for rec_data in cur_data loop
begin
update my_table set col3=rec_data.mean where id=rec_data.id;
exception when others then
insert into my_log (id, error_text) values (rec_data.id, SQLERRM);
exit;
end;
end loop;
end;
有两种方法不必首先面对这个问题 1) 在col2上定义不允许零值的检查约束 2) 如果零值因其他原因有效,只需在定义光标的查询中过滤掉零值:
cursor cur_data is
select id, col1/col2 as mean
from my_table
where col2 != 0; -- or "nvl( col2, 0 ) != 0" if nulls allowed
同时,如果您想查看发生这种情况的行,只需查询其为零的位置。当您从my_表中选择ID,1/0时无论您的表有多大,您始终不会选择任何内容,因此,您没有任何ID。异常
除数等于零
是在选择
时引发的,而不是在更新
时引发的
这个正在工作
CREATE TABLE my_table(
ID NUMBER,
nominator NUMBER,
denominator NUMBER,
ratio NUMBER CONSTRAINT ratio_check CHECK(ratio <= 1) );
CREATE TABLE my_log (
ID NUMBER,
error_text VARCHAR2(2000));
INSERT INTO my_table VALUES (400, 3, 5, NULL);
INSERT INTO my_table VALUES (500, 2, 5, NULL);
INSERT INTO my_table VALUES (300, 4, 5, NULL);
INSERT INTO my_table VALUES (100, 6, 5, NULL);
INSERT INTO my_table VALUES (200, 1, 5, NULL);
INSERT INTO my_table VALUES (600, 1, 0, NULL);
COMMIT;
DECLARE
CURSOR cur_data IS
SELECT ID, nominator/denominator AS ratio
FROM my_table;
BEGIN
FOR aRow IN cur_data LOOP
BEGIN
UPDATE my_table SET ratio = aRow.ratio WHERE ID = aRow.ID;
EXCEPTION
WHEN OTHERS THEN
INSERT INTO my_log VALUES (aRow.ID, DBMS_UTILITY.FORMAT_ERROR_STACK||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
INSERT INTO my_log VALUES (-1, DBMS_UTILITY.FORMAT_ERROR_STACK||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;
SELECT * FROM my_log;
ID ERROR_TEXT
--------------------------------------------------------------------------------
100 ORA-02290: check constraint (MY_USER.RATIO_CHECK) violated
ORA-06512: at line 11
-1 ORA-01476: divisor is equal to zero
ORA-06512: at line 9
2 rows selected.
但是,保存异常
提供了不太详细的错误消息,即
SELECT * FROM my_log;
ID ERROR_TEXT
--------------------------------------------------------------------------------
100 ORA-02290: check constraint (.) violated
ORA-06512: at line 19
为了获得所有记录,您也可以这样做:
DECLARE
CURSOR cur_data IS
SELECT ID, nominator, denominator
FROM my_table;
BEGIN
FOR aRow IN cur_data LOOP
BEGIN
UPDATE my_table SET ratio = aRow.nominator / aRow.denominator WHERE ID = aRow.ID;
...
当别人
本身就是一个bug时。先把它除掉。嗯,这对我有用。这些例子中有一个对我有用。我在屏幕上看到ORA错误,或者我的日志中的id列变为空。问题是异常发生在SELECT
时,而不是在处理异常的UPDATE
时。请看我的答案。这两种方法都没有给我id列的值,不过还是要谢谢你。我想这是不可能的,因为从我的表中选择ID,1/0
不返回任何内容。也许我必须将公式从选择移动到更新…我知道这一点,但代码是从最终用户放置公式的GUI生成的,最终用户会出错。因此,为了向他们澄清错误意味着什么,我们想给他们造成错误的记录的id。啊。那么我唯一能建议的就是删除“saveexceptions”子句,在循环中放置一个try块,并在有行数据可用的地方处理异常。
DECLARE
CURSOR cur_data IS
SELECT ID, nominator, denominator
FROM my_table;
BEGIN
FOR aRow IN cur_data LOOP
BEGIN
UPDATE my_table SET ratio = aRow.nominator / aRow.denominator WHERE ID = aRow.ID;
...