Quando è necessario utilizzare Begin / End Blocks e la parola chiave Go in SQL Server?


103

Qualcuno può dirmi quando e dove devo usare begine endbloccare in SQL Server?
Inoltre, cosa fa esattamente la Goparola chiave?

Risposte:


116

GO è come la fine di un copione.

Potresti avere più istruzioni CREATE TABLE, separate da GO. È un modo per isolare una parte dello script da un'altra, ma inviarlo tutto in un blocco.


BEGIN e END sono proprio come {e} in C / ++ / #, Java, ecc.

Legavano un blocco logico di codice. Tendo a usare BEGIN e END all'inizio e alla fine di una stored procedure, ma non è strettamente necessario lì. Dove è necessario è per i cicli e le istruzioni IF, ecc., In cui è necessario più di un passaggio ...

IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
   INSERT INTO Log SELECT @id, 'deleted'
   DELETE my_table WHERE id = @id
END

Hai provato a creare un SP senza BEGIN e END? IIRC, solo la prima riga è inclusa
nell'SP

2
Questa non è certamente la mia esperienza da SQL Server 2000 in poi.
MatBailie

1
BEGIN e END definiscono anche un nuovo ambito?
samis

2
Sì. Qualsiasi cosa dichiarata all'esterno è visibile all'interno, ma qualsiasi cosa dichiarata all'interno uscirà dall'ambito alla FINE.
MatBailie

36

È necessario BEGIN ... END per creare un blocco su più di un'istruzione. Quindi, se volessi fare 2 cose in una 'gamba' di un'istruzione IF, o se volessi fare più di una cosa nel corpo di un ciclo WHILE, dovresti mettere queste istruzioni tra parentesi con BEGIN ... FINE.

La parola chiave GO non fa parte di SQL. Viene utilizzato solo da Query Analyzer per dividere gli script in "batch" che vengono eseguiti in modo indipendente.


28

GO non è una parola chiave in SQL Server; è un separatore di batch. GO conclude una serie di dichiarazioni. Ciò è particolarmente utile quando si utilizza qualcosa come SQLCMD. Immagina di inserire istruzioni SQL sulla riga di comando. Non si desidera necessariamente che la cosa venga eseguita ogni volta che si termina un'istruzione, quindi SQL Server non fa nulla finché non si immette "GO".

Allo stesso modo, prima dell'avvio del batch, è spesso necessario che alcuni oggetti siano visibili. Ad esempio, diciamo che stai creando un database e poi lo stai interrogando. Non puoi scrivere:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

perché foo non esiste per il batch che esegue CREATE TABLE. Dovresti fare questo:

CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;

13

BEGIN e END hanno ricevuto una buona risposta da altri.

Come sottolinea Gary, GO è un separatore di batch, utilizzato dalla maggior parte degli strumenti client forniti da Microsoft, come isql, sqlcmd, query analyzer e SQL Server Management Studio. (Almeno alcuni degli strumenti consentono di cambiare il separatore di batch. Non ho mai visto un uso per cambiare il separatore di batch.)

Per rispondere alla domanda su quando utilizzare GO, è necessario sapere quando l'SQL deve essere suddiviso in batch.

Alcune istruzioni devono essere la prima istruzione di un batch.

select 1
create procedure #Zero as
    return 0

Su SQL Server 2000 l'errore è:

Msg 111, Level 15, State 1, Line 3
'CREATE PROCEDURE' must be the first statement in a query batch.
Msg 178, Level 15, State 1, Line 4
A RETURN statement with a return value cannot be used in this context.

Su SQL Server 2005 l'errore è meno utile:

Msg 178, Level 15, State 1, Procedure #Zero, Line 5
A RETURN statement with a return value cannot be used in this context.

Quindi, usa GO per separare le istruzioni che devono essere l'inizio di un batch dalle istruzioni che lo precedono in uno script.

Quando si esegue uno script, molti errori causeranno l'interruzione dell'esecuzione del batch, ma poi il client invierà semplicemente il batch successivo, l'esecuzione dello script non verrà interrotta. Lo uso spesso durante i test. Inizierò lo script con inizio transazione e finirò con rollback, eseguendo tutti i test nel mezzo:

begin transaction
go
... test code here ...
go
rollback transaction

In questo modo torno sempre allo stato iniziale, anche se si è verificato un errore nel codice di test, le istruzioni di transazione di inizio e rollback che fanno parte di batch separati si verificano ancora. Se non fossero in batch separati, un errore di sintassi impedirebbe l'avvio della transazione, poiché un batch viene analizzato come un'unità. E un errore di runtime impedirebbe il rollback.

Inoltre, se stai eseguendo uno script di installazione e hai diversi batch in un file, un errore in un batch non impedirà allo script di continuare a essere eseguito, il che potrebbe lasciare un pasticcio. (Esegui sempre il backup prima dell'installazione.)

In relazione a quanto sottolineato da Dave Markel, in alcuni casi l'analisi non riesce perché SQL Server sta cercando nel dizionario dei dati gli oggetti creati in precedenza nel batch, ma l'analisi può avvenire prima dell'esecuzione di qualsiasi istruzione. A volte questo è un problema, a volte no. Non riesco a trovare un buon esempio. Ma se mai ottieni un errore "X non esiste", quando chiaramente esisterà da quella dichiarazione, spezzati in batch.

E una nota finale. La transazione può estendersi a batch. (Vedi sopra.) Le variabili non si estendono su batch.

declare @i int
set @i = 0
go
print @i

Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".

1
Questo è ciò di cui avevo bisogno, grazie: "La transazione può estendersi a batch. Le variabili non si estendono a batch".
Gary

3

GO termina un batch, è necessario utilizzarlo solo molto raramente nel codice. Tieni presente che se lo usi in una procedura memorizzata, nessun codice dopo il GO verrà eseguito quando esegui il processo.

BEGIN e END sono necessari per qualsiasi istruzione di tipo procedurale con righe di codice multiplo da elaborare. Ti serviranno per i cicli e i cursori WHILE (che eviterai se possibile ovviamente) e le istruzioni IF (beh tecnicamente non ne hai bisogno per un'istruzione IF che ha solo una riga di codice, ma è più facile da mantieni il codice se li inserisci sempre dopo un IF). Anche le istruzioni CASE usano un END ma non hanno un BEGIN.


Qualche codice dopo il GO verrebbe effettivamente memorizzato nel processo memorizzato? l'istruzione CREATE o ALTER non verrebbe elaborata come se il codice dopo il GO non esistesse? E POI il codice dopo il GO viene eseguito come se fosse il proprio script?
MatBailie

Cosa c'entrano i cursori?
Gary McGill

3

Dopo aver lottato con questo problema oggi, la mia opinione è questa: BEGIN ... END indica il codice tra parentesi proprio come {....} nei linguaggi C, ad esempio blocchi di codice per if ... else e loops

GO è (deve essere) utilizzato quando le istruzioni successive si basano su un oggetto definito da un'istruzione precedente. Il database USE è un buon esempio sopra, ma anche quanto segue ti morderà:

alter table foo add bar varchar(8);
-- if you don't put GO here then the following line will error as it doesn't know what bar is.
update foo set bar = 'bacon';
-- need a GO here to tell the interpreter to execute this statement, otherwise the Parser will lump it together with all successive statements.

Mi sembra che il problema sia questo: SQL Server SQL Parser, a differenza di Oracle, non è in grado di rendersi conto che stai definendo un nuovo simbolo sulla prima riga e che va bene fare riferimento nelle righe successive. Non "vede" il simbolo finché non incontra un token GO che gli dice di eseguire l'SQL precedente dall'ultimo GO, a quel punto il simbolo viene applicato al database e diventa visibile al parser.

Perché non tratta il punto e virgola solo come una rottura semantica e applica affermazioni individualmente non lo so e vorrei che fosse. L'unico vantaggio che posso vedere è che puoi inserire un'istruzione print () appena prima del GO e se una qualsiasi delle istruzioni fallisce, la stampa non verrà eseguita. Un sacco di guai per un guadagno minore però.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.