这似乎应该是我已经知道的东西。我们需要在事务中运行一堆sql更新,如果其中一个失败则回滚。我们还想打印状态消息,因为我们将运行大量这些消息。如果我使用通用编程语言,这将很简单。但我试图找到一个团队成员可以使用的解决方案,这只是SQL。她过去使用下面的模式在MS SQL Server中完成了这项工作。 Oracle有一个等效的简单模式吗?
DECLARE @ErrorVar INT;
BEGIN TRANSACTION;
UPDATE MyTable1 SET MyColumn1 = 'JSMITH' where MyColumn1 = 'JOHN';
SET @ErrorVar = @@ERROR;
UPDATE MyTable2 SET MyColumn2 = 'JSMITH' where MyColumn2 = 'JOHN';
SET @ErrorVar = @ErrorVar + @@ERROR;
UPDATE MyTable SET LoginID = 'JSMITH' where LoginID = 'JOHN';
SET @ErrorVar = @ErrorVar + @@ERROR;
IF @ErrorVar <> 0
BEGIN
ROLLBACK TRANSACTION;
PRINT 'We had a problem with JSMITH and rolled back *****';
END;
ELSE
BEGIN
COMMIT TRANSACTION;
PRINT 'JSMITH Updated ok';
END;
GO
答案 0 :(得分:7)
在SQLPlus中,使用WHENEVER命令控制发生错误时的行为。
WHERVER SQLERROR EXIT FAILURE ROLLBACK在我们的脚本中是相当标准的。
在SQLPlus提示符下键入HELP WHENEVER以获取更多信息。
答案 1 :(得分:2)
因为我对akf评论的回答太长而无法发表评论,所以我将其作为单独的答案发布。
这就是为什么它没有实现任何额外/有用的原因。
假设我们有Peter提到的三个表:
SQL> create table mytable1 (mycolumn1) as select cast('JOHN' as varchar2(6)) from dual
2 /
Tabel is aangemaakt.
SQL> create table mytable2 (mycolumn2) as select cast('JOHN' as varchar2(6)) from dual
2 /
Tabel is aangemaakt.
SQL> create table mytable (loginid) as select cast('JOHN' as varchar2(6)) from dual
2 /
Tabel is aangemaakt.
并添加一个检查约束以使第三个更新语句失败:
SQL> alter table mytable add constraint no_jsmith_ck1 check (loginid <> 'JSMITH')
2 /
Tabel is gewijzigd.
PL / SQL块可以像这样简单,但它失败了:
SQL> begin
2 update mytable1
3 set mycolumn1 = 'JSMITH'
4 where mycolumn1 = 'JOHN'
5 ;
6 update mytable2
7 set mycolumn2 = 'JSMITH'
8 where mycolumn2 = 'JOHN'
9 ;
10 update mytable
11 set loginid = 'JSMITH'
12 where loginid = 'JOHN'
13 ;
14 commit
15 ;
16 end;
17 /
begin
*
FOUT in regel 1:
.ORA-02290: check constraint (RWK.NO_JSMITH_CK1) violated
ORA-06512: at line 10
并显示所有内容都已回滚,而不发送回滚:
SQL> select * from mytable1
2 /
MYCOLU
------
JOHN
1 rij is geselecteerd.
SQL> select * from mytable2
2 /
MYCOLU
------
JOHN
1 rij is geselecteerd.
SQL> select * from mytable
2 /
LOGINI
------
JOHN
1 rij is geselecteerd.
因此这里不需要异常处理程序。您建议的异常处理程序执行此操作:
SQL> begin
2 update mytable1
3 set mycolumn1 = 'JSMITH'
4 where mycolumn1 = 'JOHN'
5 ;
6 update mytable2
7 set mycolumn2 = 'JSMITH'
8 where mycolumn2 = 'JOHN'
9 ;
10 update mytable
11 set loginid = 'JSMITH'
12 where loginid = 'JOHN'
13 ;
14 commit
15 ;
16 EXCEPTION
17 WHEN OTHERS THEN
18 ROLLBACK; --// Oracle will do this for you, but it doesnt hurt to be clear
19 DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_backtrace);
20 raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
21 END;
22 /
ORA-06512: at line 10
begin
*
FOUT in regel 1:
.ORA-20001: An error was encountered - -2290 -ERROR- ORA-02290: check constraint (RWK.NO_JSMITH_CK1) violated
ORA-06512: at line 20
虽然没有错,但我在这里看不出任何增值。
SQL> select * from mytable1
2 /
MYCOLU
------
JOHN
1 rij is geselecteerd.
SQL> select * from mytable2
2 /
MYCOLU
------
JOHN
1 rij is geselecteerd.
SQL> select * from mytable
2 /
LOGINI
------
JOHN
1 rij is geselecteerd.
为什么建议添加无效的代码?
此致 罗布。
答案 2 :(得分:1)
您可以在程序结束时添加EXCEPTION
块:
EXCEPTION
WHEN OTHERS THEN
ROLLBACK; --// Oracle will do this for you, but it doesnt hurt to be clear
DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_backtrace);
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END;
修改强> 我添加了一个调用来输出回溯以在错误报告中提供亚麻布。 (这是10克或更好)
答案 3 :(得分:1)
PL / SQL具有回滚和回滚到保存点命令。
您可以找到有关它的文档here。
答案 4 :(得分:1)
一个简单的SQL脚本可能看起来像这样:
set serveroutput on
DECLARE
BEGIN
dbms_output.enable(100000); -- overrides default 10000 byte limit
UPDATE MyTable1 SET MyColumn1 = 'JSMITH' where MyColumn1 = 'JOHN';
UPDATE MyTable2 SET MyColumn2 = 'JSMITH' where MyColumn2 = 'JOHN';
UPDATE MyTable SET LoginID = 'JSMITH' where LoginID = 'JOHN';
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
dbms_output.put_line('Error processing JSMITH');
END;
/
这在Oracle中称为匿名过程。您可以通过sqlplus轻松地将其提供给Oracle:
sqlplus user/pw@db @yourscript
当然,您可以通过脚本获得更好的功能(例如,使用BEGIN-EXCEPTION-END包围每个更新以确定哪个更新有问题)但这应该可以帮助您入门。
答案 5 :(得分:0)
如果存储过程是您的设计选择(我不确定),那么您可能希望执行类似下面的操作:
EXCEPTION
WHEN OTHERS
THEN
out_status := 1;
raise_application_error(-20001,SQLERRM);
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
如果您要查找的所有内容都是通过/失败布尔值,那么从存储过程中返回out状态将允许您做出相应的响应。
如果您选择直接SQL,那么在ORACLE中如果在sql语句更新期间遇到异常,它将抛出异常而不提交任何更改(我不确定当更新未成功时需要回滚一个例外,我相信Oracle会处理这个问题。)