Oracle
 sql >> Database >  >> RDS >> Oracle

Slash o non Slash?

Questa è la domanda.

Un recente post sui forum OTN chiedeva l'utilizzo di punti e virgola e barre come terminatori di istruzioni. Ho rispolverato un articolo che ho scritto per il nostro team di sviluppo oltre 4 anni fa su questo argomento. Questo articolo ha ricevuto buone recensioni ed è disponibile sui forum OTN, se lo si desidera. Ho pensato di pubblicarlo anche sul mio blog. Ecco l'articolo:

Barra o nessuna barra

di Brian Peasland

Nella nostra azienda, gli script SQL distribuiti vengono eseguiti nell'utilità della riga di comando SQL*Plus di Oracle, mentre molti sviluppatori utilizzano uno strumento GUI come PL/SQL Developer o SQL Developer. La barra indica qualcosa per SQL*Plus che non è necessario in PL/SQL Developer o SQL Developer. Pertanto, può essere fonte di confusione sapere se è necessario includere una barra negli script SQL o meno. Si spera che questa sezione faccia luce su cosa fa la barra in avanti, quando usarla e quando non usarla. Punto e virgola Per la maggior parte delle istruzioni SQL, il punto e virgola è il terminatore dell'istruzione. Ad esempio, considera questa semplice istruzione SQL eseguita in SQL*Plus:

SQL> seleziona sysdate da dual;

DATA DI SISTEMA

———

18-giu-12

Quando SQL*Plus vede il punto e virgola, sa che è stata raggiunta la fine dell'istruzione SQL e ora può eseguire il comando.

Buffer SQL*Plus

Potresti non essere a conoscenza del fatto che SQL*Plus ha un buffer per i suoi comandi. Se premo il tasto "l" per "lista", posso vedere il comando attualmente nel buffer della mia sessione.

SQL> l

1* seleziona sysdate da dual

Non sorprende che ci sia il comando che ho appena eseguito. Ho quindi eseguito un'altra istruzione SQL ed ecco come appare ora il mio buffer:

SQL> l

1 selezionare sysdate,utente

2* da doppia

Come puoi vedere, ora ho due righe nel buffer SQL*Plus della mia sessione.

Barra =Esegui buffer

La prima regola da comprendere sulla barra in avanti è che per SQL*Plus, la barra in avanti significa eseguire il contenuto del buffer. Per illustrare questo concetto, eseguirò un'istruzione SQL, attenderò alcuni secondi, quindi eseguirò di nuovo la stessa istruzione SQL ma semplicemente eseguendo il buffer.

SQL> seleziona to_char(sysdate,'MM/DD/YYYY HH24:MI:SS') from dual;

TO_CHAR(SYSDATE,'MM

——————-

18/06/2012 15:20:40

SQL> /
TO_CHAR(SYSDATE,'MM

——————-

18/06/2012 15:21:17

SQL> /

TO_CHAR(SYSDATE,'MM

——————-

18/06/2012 15:21:50

Puoi vedere che tutto ciò che ho fatto la seconda e la terza volta è stato semplicemente digitare "/" e premere invio e SQL*Plus ha eseguito ogni volta il contenuto del suo buffer dei comandi.

Blocchi PL/SQL

Il terminatore dell'istruzione punto e virgola ha funzionato bene da solo fino a quando Oracle non ha introdotto PL/SQL in Oracle versione 7. Il problema è che i blocchi PL/SQL possono avere più punti e virgola per terminare le singole istruzioni che compongono quel blocco. Considera questo blocco PL/SQL molto semplice che non fa nulla:

SQL> inizio

2 nullo;

3 nullo;

4 fine;

5

Le righe 2 e 3 contengono istruzioni perfettamente valide che terminano ciascuna con il punto e virgola. E nella riga 4, abbiamo la parola chiave END che indica la fine del blocco PL/SQL. Se non ci fossero consentite coppie nidificate BEGIN/END, ogni volta che SQL*Plus vede "END;" saprebbe che è stata raggiunta la fine del blocco PL/SQL, ma sono consentite coppie BEGIN/END nidificate, quindi quanto segue è perfettamente legale e valido:

SQL> inizio

2 iniziare

3 nullo;

4 fine;

5 nullo;

6 fine;

7

Puoi dire da quanto sopra che stai solo cercando "END;" non è sufficiente perché SQL*Plus avrebbe tentato di eseguire il blocco dopo la riga 4. Quindi, come ha fatto Oracle a decidere di indicare che il blocco PL/SQL era pronto per l'esecuzione? La risposta è usando la barra in avanti, come forse già saprai. La seconda regola da capire è che tutto ciò che fa la barra in avanti quando la usi per terminare un blocco PL/SQL è dire a SQL*Plus di eseguire ciò che è nel buffer! Questo non è cambiato da prima della creazione di PL/SQL per Oracle 7. Considera il seguente esempio:

SQL> inizio

2 nullo;

3 fine;

4 /

Procedura PL/SQL completata con successo.

SQL> l

1 inizio
2 nullo;

3* fine;

Alla riga 4, ho digitato la barra per eseguire il blocco PL/SQL. Puoi vedere che il mio blocco è stato completato con successo. Se torniamo indietro e osserviamo il contenuto del mio buffer dei comandi, puoi vedere che contiene tutto tranne la barra in avanti. La barra non fa parte del buffer dei comandi. Quindi ora eseguirò un blocco PL/SQL diverso:

SQL> inizio

2 dbms_output.put_line('Oggi è '||to_char(sysdate,'MM/GG/AAAA HH24:MI:SS'));

3 fine;

4 /

Oggi è il 18/06/2012 15:39:32

Procedura PL/SQL completata con successo.

La barra in avanti ha detto a SQL*Plus di eseguire ciò che è nel suo buffer e i risultati vengono visualizzati. Ora scriviamo di nuovo solo la barra e dovremmo vedere che il nostro blocco PL/SQL viene eseguito di nuovo.

SQL> /

Oggi è il 18/06/2012 15:40:42

Procedura PL/SQL completata con successo.

Non ho dovuto digitare nuovamente il mio blocco PL/SQL poiché è attualmente nel buffer dei comandi.

PL/SQL e SQL Developer e blocchi PL/SQL

Il problema più grande per la maggior parte degli sviluppatori è che PL/SQL Developer e SQL Developer non richiedono l'utilizzo della barra. Come mai? Perché puoi premere Esegui (F8) o Esegui script (F5) per eseguire il tuo blocco PL/SQL. Lo sviluppatore PL/SQL sa che nel momento in cui premi F8, intendi inviare il blocco PL/SQL da eseguire. In questo caso, F8 in PL/SQL Developer esegue lo stesso lavoro della barra in SQL*Plus. Allo stesso modo, per F5 in SQL Developer.

Il problema nella mia azienda è che il nostro team che distribuisce il codice alla produzione non distribuisce codice con PL/SQL Developer o SQL Developer. Usano SQL*Plus perché lo scripting di più esecuzioni è più semplice con uno strumento da riga di comando. Molti sviluppatori commettono l'errore di non includere la barra per i blocchi PL/SQL negli script perché non ne hanno bisogno, ma se si desidera distribuire quella sezione di codice in uno script SQL, è richiesta la barra alla fine di ogni PL /blocco SQL.

Quando non usare Slash

Quindi abbiamo visto quando e perché usiamo la barra in avanti, ma quando è sbagliato usarla? La terza regola da sapere è che è sbagliato usare la barra dopo una singola istruzione SQL (non in un blocco PL/SQL), specialmente quando quella barra segue immediatamente un'istruzione DML (INSERT, UPDATE o DELETE). Se il mio script contiene quanto segue:

seleziona sysdate da dual;

/

Quindi otterrò "doppio output" che non è ciò che normalmente intendo fare in uno script. Voglio davvero solo una riga restituita, non due come farebbe lo script sopra:

SQL> seleziona sysdate da dual;

DATA DI SISTEMA

———

18-JUN-12
SQL> /

DATA DI SISTEMA

———

18-giu-12

È anche peggio quando uso la barra in avanti dopo un'istruzione DML perché quell'istruzione verrà eseguita due volte. Considera il seguente script:

inserisci nei valori test_tab (10);

/

Ora sappiamo che quando eseguo le due righe precedenti in uno script, SQL*Plus lo eseguirà una volta a causa del terminatore dell'istruzione punto e virgola e quindi eseguirà una seconda volta perché la barra indica a SQL*Plus di eseguire ciò che è nel buffer dei comandi. Quando eseguo lo script a due righe sopra, ottengo il seguente output:

SQL> inserisci nei valori test_tab (10);

1 riga creata.

SQL>

/

inserisci nei valori test_tab (10) *

ERRORE alla riga 1:ORA-00001:vincolo univoco (PEASLAND.SYS_C00767176) violato

Ops! Il primo inserimento ha funzionato (1 riga creata.), ma quando è stata inserita la barra, SQL*Plus ha provato a inserire gli stessi dati e sono stato catturato da una violazione del vincolo univoco.

Conclusione

Si spera che questa pagina mostri perché è necessaria la barra, cosa fa e quando non usarla. Per ricapitolare:

  • Includi la barra alla fine di ogni blocco PL/SQL
  • Non includere la barra dopo le istruzioni SQL non in un blocco PL/SQL.
  • La barra dopo una singola istruzione SQL farà eseguire il comando SQL due volte.