2012-06-25 20 views
8

Ho alcuni script che vengono eseguiti spesso, sempre da una sessione SQLPlus connessa.Come si esce da uno script in SQLPlus quando si verifica un errore e si torna al prompt di SQLPlus, senza disconnettere o uscire da SQLPlus?

Ho bisogno di un modo per uscire dallo script quando si verifica un errore, senza disconnettere o uscire da SQLPlus stesso. 100% del tempo, quando si verifica un errore, il DBA connesso dovrà emettere uno o più comandi nella sessione. 100% del tempo, quando si verifica un errore, ci sono altre dichiarazioni SQLPlus (e quindi deve esserefuori di un BEGIN..END;) successivamente nello script che non deve essere eseguito o potrebbero insorgere problemi gravi.

NOTA: Se si suggerisce WHENEVER SQLERROR EXIT, non è stato letto il testo precedente. Ciò si disconnetterà e uscirà SQLPlus oltre a lo script, che non è un comportamento accettabile.

+1

Di interesse perché non si suddividono gli script in uno script shell/batch e _use_ 'ogni volta che sqlerror esce? E quindi lo script di shell gestisce gli errori per decidere se continuare? – Ben

+0

Perché ci sono un sacco di cose manuali che vorranno fare prima e/o dopo l'esecuzione dello script, incluso l'esecuzione di altri script, specifici per la situazione/ambiente/dati/ecc. Coinvolti. Questo è principalmente per sistemare le cose in produzione, e costantemente essere cacciato/dover riconnettersi è peggio che fastidioso quando il tuo sito non funziona. Non possono essere suddivisi in più script poiché i comandi SQLPlus utilizzano l'output dei comandi PL/SQL. – Thought

risposta

7

Ho trovato un'idea interessante here che, se combinata con la risposta di spencer7593, mi consentirà di selezionare selettivamente il sub-script, al quale posso passare i valori di output PL/SQL. Vale a dire:

VAR continue number; 
EXEC :continue := 1; 
BEGIN 
    SELECT some_bool_test() INTO :continue FROM dual; 
END; 

SET termout OFF 
COLUMN script_name NEW_VALUE v_script_name 
SELECT decode(:continue, 1, 'run_stuff.sql', 'skip.sql') script_name FROM dual; 
SET termout ON 

@&v_script_name :some_other_values 

Dove skip.sql è un file di testo vuoto.
 

UPDATE: ho spostato la maggior parte di questo in un file RUN.SQL, dove passo nel booleano (0 o 1) come &1, il nome dello script di invitare il successo come &2, e quindi tutti gli altri parametri attesi passano allo script chiamato. Così, si finisce per guardare qualcosa di simile:

VAR continue number; 
EXEC :continue := 1; 
BEGIN 
    SELECT some_bool_test() INTO :continue FROM dual; 
END; 

@run.sql :continue 'run_stuff.sql' :some_other_values 
+2

Triste che un database che costa tanto quanto Oracle ti fa saltare attraverso così tanti cerchi. Non è vero? – jpmc26

+0

Scusate, downvoted per errore. Si prega di modificare in modo da poter ripristinare il mio voto. –

4

Non è possibile.

SQLPlus non fornisce quel livello di controllo sull'esecuzione di uno script.

Ovviamente, è necessario EVITARE di utilizzare il comando WHENEVER SQLERROR EXIT ....

È possibile ottenere il controllo condizionale su cui le istruzioni SQL vengono o non vengono eseguite come risultato di eccezioni (errori) con PL/SQL. Ma questo non affrontare i comandi sqlplus (che non possono essere eseguiti dall'interno di un blocco PL/SQL.)

DECLARE 
    lb_continue BOOLEAN; 
BEGIN 
    lb_continue := TRUE; 
    BEGIN 

    sql statement 

    EXCEPTION 
    WHEN OTHERS THEN 
     lb_continue = FALSE; 
    END; 
    IF lb_continue THEN 
    BEGIN 

    sql statements 

    EXCEPTION 
    WHEN OTHERS THEN 
     lb_continue := FALSE; 
    END; 
END; 

Naturalmente, questo approccio ha i suoi propri limiti e problemi. Qualsiasi istruzione DDL dovrebbe essere chiamata dinamicamente; il modo più semplice per farlo è un EXECUTE IMMEDIATE statement.

Il problema più grande (nel tuo caso) è che non è possibile eseguire comandi SQLPlus da un blocco PL/SQL.

+1

Sono solo confuso sul motivo per cui questo non è stato implementato come comportamento predefinito quando si esegue SQLPlus come riga di comando (piuttosto che come connessione one-shot connect-script_run-disconnect). Non riesco a pensare a nessuna situazione in cui vorrei un comportamento diverso dal semplice ritorno al prompt dei comandi di SQLPLus. – Thought

+0

Non sono sicuro di cosa intendi per comportamento predefinito. Intendi perché non c'è un comando "vai alla fine del corrente script" in SQL * Plus? –

1

Non è possibile uscire dallo script e rimanere in SQL * Plus, ma è possibile interrompere l'esecuzione. Non è bello, ma assumendo che tu possa modificare lo script per aggiungere il flusso di controllo, puoi farlo con la variabile bind.

set serveroutput on 

var flag char; 
exec :flag := 'Y'; 

begin 
    if :flag != 'Y' then 
     raise program_error; 
    end if; 
    dbms_output.put_line('Doing some work'); 
    /* Check for some error condition */ 
    if 0 != 1 then 
     raise program_error; 
    end if; 
    /* Only reach this if earlier statements didn't fail 
    * but could wrap in another flag check if needed */ 
    dbms_output.put_line('Doing some more work'); 
    exception 
     when program_error then 
      dbms_output.put_line(sqlerrm); 
      :flag := 'N'; 
     when others then 
      /* Real exception handling, obviously */ 
      dbms_output.put_line(sqlerrm);  
      :flag := 'N'; 
end; 
/

-- DML only does anything if flag stayed Y 
select sysdate from dual 
where :flag = 'Y'; 

-- Optional status message at the end of the script, for DBA info 
set feedback off 
set head off 
select 'Something went wrong' from dual where :flag != 'Y'; 
set feedback on 
set head on 

Quando eseguite:

SQL> @script 

PL/SQL procedure successfully completed. 

Doing some work 
ORA-06501: PL/SQL: program error 

PL/SQL procedure successfully completed. 


no rows selected 


Something went wrong 
SQL> 

eventuali blocchi PL/SQL nello script possono controllare lo stato della segnalazione alla partenza, e sollevare program_error (proprio come un pratico pre-definito eccezione) per tornare indietro su. Qualsiasi cosa che errori all'interno di un blocco PL/SQL può aggiornare il flag della variabile di binding, direttamente o in un gestore di eccezioni. E qualsiasi DML non PL/SQL può avere una clausola aggiuntiva where per controllare lo stato del flag, quindi se è stato impostato su N quando viene raggiunta tale istruzione, non viene eseguito alcun lavoro. (Per un insert immagino che significherebbe non usare il modulo values).

Ciò che questo non può fare è gestire eventuali errori da istruzioni SQL semplici, ma non sono sicuro se questo è un problema. Se è così, è possibile che debbano essere modificati in SQL dinamico all'interno di un blocco PL/SQL.

-1

So che la sua vecchia, ma queste due istruzioni al molto inizio dello script SQL fare il lavoro:

OGNI VOLTA SQLERROR EXIT MANCATA ROLLBACK

WHENEVER OSERROR EXIT FAILURE ROLLBACK

+0

Questi si disconnetteranno. – Thought

Problemi correlati