2012-01-18 10 views
10

Sto provando a fare alcuni controlli su uno schema DB all'inizio di uno script PL/SQL.PL/SQL: esiste un'istruzione per interrompere completamente l'esecuzione dello script?

Se i controlli danno risultati non riusciti, voglio interrompere lo script, per impedire l'esecuzione delle prossime istruzioni.

ho avuto qualcosa di simile

-- 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 ... 

sto cercando per l'istruzione (s) che permette di fare il "STOP EXECUTION HERE".

+5

Stai davvero parlando di uno script PL/SQL? O uno script SQL * Plus? Non è possibile avere una dichiarazione DDL in PL/SQL (a meno che non la si inserisca in un 'ESEGUI IMMEDIATO'). Quindi mi sembra che tu stia parlando di uno script SQL * Plus. Se si sta parlando di uno script SQL * Plus, se il blocco PL/SQL si guasta, SQL * Plus continuerà per impostazione predefinita a eseguire la successiva istruzione SQL (o blocco PL/SQL) nello script. Dovresti utilizzare il comando SQL * Plus 'WHENEVER SQLERROR EXIT'. –

+0

Grazie per il tuo commento Justin. In realtà non sono un "Oracle Expert", anche se ho una buona conoscenza del DBMS in generale. Quindi non ho ancora compreso la differenza tra gli script PL/SQL o SQL * Plus (conosci qualche blog/doc/sito che spiega chiaramente questa differenza?). Tutto quello che posso dire è che sto usando ** Navicat **, usando il pannello "query" e caricando il mio file di script al suo interno. In quel contesto specifico, 'RAISE_APPLICATION_ERROR()' fa il lavoro. –

risposta

9

In base alla domanda, non sono d'accordo con la risposta accettata. La domanda mostra uno script batch con più istruzioni. RAISE_APPLICATION_ERROR() esce solo da un blocco PL/SQL (sottoprogramma), non dallo script generale (come indicato da Justin), quindi continuerà con le istruzioni che seguono.

Per gli script batch, è preferibile utilizzare WHENEVER SQLERROR EXIT. Sì, è una direttiva SQL * Plus, non SQL standard, ma è abbastanza portatile; i più diffusi strumenti Oracle che supportano gli script supportano questa direttiva, almeno in parte. Il seguente esempio funziona in SQL * Plus, SQL * Developer, Toad, SQLsmith e possibilmente altri, e dimostra il problema, se si commenta la line out.

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; 
/

Se si rimuove la QUANDO SQLERROR, lo script continuerà ed eseguire il 2 ° blocco, ecc, che è esattamente ciò che la domanda chiede di evitare.

Il vantaggio, in questo caso, degli strumenti grafici che emulano sqlplus, è che interrompono realmente lo script e non inviano il resto dello script alla shell dei comandi come comandi della shell, che è ciò che accade se si incolla script in SQL * Plus in esecuzione in una finestra della console. SQL * Plus può uscire in caso di errore, ma i restanti comandi bufferizzati saranno quindi gestiti dalla shell del sistema operativo, che è un po 'caotico e potenzialmente rischioso, se nei commenti sono presenti comandi di shell (che non è inaudito). Con SQLPlus, è sempre meglio connettersi, quindi eseguire lo script o passarlo nell'argomento < start> command line (sqlplus scott/tiger @ foo.sql) per evitare questo.

+0

Grazie per la tua risposta riflessiva. –

+0

+1 questo davvero aiutato. Sapevo di eccezioni e errori di applicazione, ma ho bisogno di fare un controllo di precondizione in uno script DDL che dovrebbe fermare lo script. L'alternativa (fare DDL in un'istruzione IF in uno script PL/SQL) non è molto allettante. –

5

qualche secondo di googling mi ha dato la risposta: la funzione RAISE_APPLICATION_ERROR()

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

Il codice di errore definito dall'utente deve essere compresa tra -20000 e -20.999.

dettagli su Oracle doc qui: http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/07_errs.htm#877 (sezione Definire i propri messaggi di errore: Procedura RAISE_APPLICATION_ERROR)

+2

Se si utilizza 'raise_application_error' nel codice che hai postato nella tua domanda, questo ti farà uscire dal blocco PL/SQL ma la sezione' ALTRE ISTRUZIONI SQL 'verrà comunque eseguita. E 'questo quello che stai cercando? –

7

Se non si vuole sollevare un'eccezione, si potrebbe provare qualcosa di simile (non testato):

Alcune persone odiano qualsiasi istruzione GOTO in quanto possono portare a codice spaghetti se abusato, ma in situazioni semplici come questa (anche in questo caso, assumendo che non si vuole sollevare un'eccezione) funzionano bene.

+1

Grazie, +1. L'unico problema che vedo è che ho un sacco di istruzioni DDL ('ALTER TABLE' ...) come' bunch of great code', che richiede di usare molto la soluzione 'EXECUTE IMMEDIATE', di conseguenza il codice dello script sarebbe essere meno leggibile/manutenibile –

+0

Sì, questo è un problema diverso dal tuo OP, ma sono d'accordo sul fatto che qualche codice là fuori è "fantastico" ;-) Questo commento è stato un po 'ironico, ma ancora una volta il punto era dare una soluzione alternativa alla tua domanda . – tbone

1

Anziché lanciare un errore dell'applicazione, è molto più semplice utilizzare lo RETURN keyword che chiude il blocco PL/SQL corrente in modo molto fluido.

Assicurati di fare uno DBMS_OUTPUT.PUT_LINE('Exited because <error') prima di fornire all'utente un messaggio piacevole del motivo per cui stai uscendo, naturalmente!

Problemi correlati