2012-01-18 62 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')之前向用戶提供一個很好的信息,說明您爲什麼退出課程!