2012-01-18 209 views
10

我试图在PL/SQL脚本的开头对数据库模式进行一些检查。PL/SQL:是否有一条指令可以完全停止脚本执行?

如果检查结果不成功,我想停止脚本,以防止执行下一条指令。

我有这样的事情

-- 1st line of PL/SQL script 

DECLARE 
    SOME_COUNT INTEGER; 
BEGIN 
    SELECT COUNT(*) INTO SOME_COUNT FROM SOME_TABLE WHERE <SOME_CONDITIONS>; 
    IF (SOME_COUNT > 0) THEN 
    DBMS_OUTPUT.PUT_LINE('Test failed, I don''want the rest of the script' 
     || ' to be executed.'); 
    --EXIT or something like that?... <= STOP EXECUTION HERE 
    END IF; 
END; 
/

-- OTHER SQL INSTRUCTIONS... 
ALTER TABLE SOME_TABLE ... 

我在寻找让做 “STOP EXECUTION HERE” 指令(S)。

+5

你真的在谈论PL/SQL脚本吗?或者一个SQL * Plus脚本?你不能在PL/SQL中有一个DDL语句(除非你把它放在'EXECUTE IMMEDIATE'中)。所以在我看来你正在谈论一个SQL * Plus脚本。如果你正在谈论一个SQL * Plus脚本,如果PL/SQL块出错,SQL * Plus将默认继续执行脚本中的下一个SQL语句(或PL/SQL块)。您需要使用SQL * Plus命令“WHENEVER SQLERROR EXIT”。 – 2012-01-18 10:10:53

+0

感谢您对贾斯汀的评论。事实上,即使我对DBMS有一般的了解,我也不是“Oracle专家”。因此,我还没有把握PL/SQL或SQL * Plus脚本之间的区别(你知道一些博客/ doc /网站清楚地说明了这种差异吗?)。我可以告诉的是,我正在使用** Navicat **,使用“查询”窗格并加载我的脚本文件。在那个特定的上下文中,'RAISE_APPLICATION_ERROR()'完成这项工作。 – 2012-01-18 10:40:47

回答

9

基于这个问题,我不同意接受的答案。该问题显示了一个多语句批处理脚本。 RAISE_APPLICATION_ERROR()只能从PL/SQL块(子程序)中退出,而不是在整个脚本之外(正如Justin所指出的那样),所以它将继续使用后面的语句。

对于批处理脚本,最好使用WHENEVER SQLERROR EXIT。是的,这是一个SQL * Plus指令,不是标准的SQL,但相当便于使用;最受欢迎的支持脚本的Oracle工具至少部分支持该指令。以下示例适用于SQL * Plus,SQL * Developer,Toad,SQLsmith以及其他可能的应用程序,并且如果您将该行注释掉,则会演示此问题。

set serveroutput on 

-- Without this line, things keep going 
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK; 

BEGIN 
    IF (1 > 0) THEN 
    DBMS_OUTPUT.PUT_LINE('First thing'); 
    RAISE_APPLICATION_ERROR(-20000, 'Test failed'); -- not enough 
    END IF; 
END; 
/

-- This will execute if you remove WHEN SQLERROR.., so RAISE_APPLICATION_ERROR is not enough 
BEGIN 
    DBMS_OUTPUT.PUT_LINE('Second thing - Executes anyway'); 
END; 
/

如果删除WHEN SQLERROR,脚本会继续并执行2号地块等,这是个问题问,避免什么。

在这种情况下,模拟sqlplus的图形工具的优点是它们确实会停止脚本,并且不会将其余脚本作为shell命令提交到命令shell,这会发生如果粘贴脚本导入运行在控制台窗口中的SQL * Plus。 SQL * Plus可能会在出错时退出,但是其余缓冲的命令将由OS shell处理,如果在注释中有shell命令(这是前所未闻),这有点麻烦并且可能存在风险。对于SQLPlus,最好是连接,然后执行脚本,或者通过< start>命令行参数(sqlplus scott/tiger @ foo.sql)传递它以避免这种情况。

+0

感谢您的深思熟虑的答案。 – 2014-05-17 14:30:31

+0

+1这确实有帮助。我知道异常和应用程序错误,但是我需要在应该停止脚本的DDL脚本中执行一个前提条件检查。另一种方法(在PL/SQL脚本中的IF语句中执行DDL)不是很诱人。 – 2014-10-03 07:57:41

5

一些更多的谷歌搜索秒给我的回答:功能RAISE_APPLICATION_ERROR()

IF (SOME_COUNT > 0) THEN 
    RAISE_APPLICATION_ERROR(-20000, 'Test failed'); 
    END IF; 

用户定义的错误代码应该是-20000和-20999之间。

详细放在这里的Oracle文档:http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/07_errs.htm#877(部分定义自己的出错信息:过程RAISE_APPLICATION_ERROR

+2

如果您在问题中发布的代码中使用'raise_application_error',它会将您从PL/SQL块中分离出来,但'OTHER SQL INSTRUCTIONS'部分仍将被执行。这是你在追求什么? – 2012-01-19 09:30:39

7

如果你不想抛出异常,你可以尝试像(未经测试):

declare 
    SOME_COUNT INTEGER; 
begin 
    SELECT COUNT(*) INTO SOME_COUNT FROM SOME_TABLE WHERE <SOME_CONDITIONS>; 
    IF (SOME_COUNT > 0) THEN 
    DBMS_OUTPUT.PUT_LINE('Test failed, I don''want the rest of the script' 
     || ' to be executed.'); 

    goto end_proc; 
    END IF; 

    -- A bunch of great code here 

    <<end_proc>> 
    null; -- this could be a commit or other lines of code 
end; 

有些人讨厌任何GOTO语句,因为他们可能导致意大利面代码被滥用,但在这样的简单情况下(再次假设您不想引发异常),他们工作得很好。

+1

谢谢,+1。我看到的唯一问题是,我有很多DDL语句('ALTER TABLE' ...)作为'一堆优秀的代码',需要使用很多'EXECUTE IMMEDIATE'解决方法,因此脚本代码会不易读/可维护。 – 2012-01-18 12:51:24

+0

是啊,这就是比你的OP不同的问题,但我同意一些代码在那里是远离“伟大” ;-)这评论是在脸颊有点舌头,但同样的点是给你的问题的替代解决方案。 – tbone 2012-01-18 13:18:09

1

与使用应用程序错误相比,使用RETURN keyword非常顺利地退出当前PL/SQL块要简单得多。

只要确保在执行DBMS_OUTPUT.PUT_LINE('Exited because <error')之前向用户提供一个很好的信息,说明您为什么退出课程!

相关问题