Quando preciso usar Begin / End Blocks e a palavra-chave Go no SQL Server?

103

Alguém pode me dizer quando e onde preciso usar begine endblocos no SQL Server?
Além disso, o que exatamente a Gopalavra - chave faz?

Tarik
fonte

Respostas:

116

GO é como o fim de um script.

Você pode ter várias instruções CREATE TABLE, separadas por GO. É uma forma de isolar uma parte do script de outra, mas enviando tudo em um bloco.


BEGIN e END são como {and} em C / ++ / #, Java, etc.

Eles vinculam um bloco lógico de código. Costumo usar BEGIN e END no início e no final de um procedimento armazenado, mas não é estritamente necessário lá. Onde é necessário é para loops e declarações IF, etc, onde você precisa de mais de uma etapa ...

IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
   INSERT INTO Log SELECT @id, 'deleted'
   DELETE my_table WHERE id = @id
END
MatBailie
fonte
Você já tentou criar um SP sem BEGIN e END? IIRC, apenas a primeira linha está incluída no SP, o resto é executado lá e então ...
cjk
2
Essa certamente não é minha experiência do SQL Server 2000 em diante.
MatBailie
1
BEGIN e END também definem um novo escopo?
samis
2
Sim. Qualquer coisa declarada fora é visível dentro, mas qualquer coisa declarada dentro sairá do escopo no END.
MatBailie
36

Você precisa de BEGIN ... END para criar um bloco que abrange mais de uma instrução. Então, se você quiser fazer 2 coisas em uma 'perna' de uma instrução IF, ou se quiser fazer mais de uma coisa no corpo de um loop WHILE, você precisa colocar essas instruções entre BEGIN ... FIM.

A palavra-chave GO não faz parte do SQL. Só é usado pelo Query Analyzer para dividir scripts em "lotes" que são executados independentemente.

Gary McGill
fonte
28

GO não é uma palavra-chave no SQL Server; é um separador de lote. GO termina um lote de declarações. Isso é especialmente útil quando você está usando algo como SQLCMD. Imagine que você está inserindo instruções SQL na linha de comando. Você não deseja necessariamente que a coisa seja executada sempre que terminar uma instrução, portanto, o SQL Server não faz nada até que você insira "GO".

Da mesma forma, antes do início do lote, você geralmente precisa ter alguns objetos visíveis. Por exemplo, digamos que você esteja criando um banco de dados e, em seguida, consultando-o. Você não pode escrever:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

porque foo não existe para o lote que faz CREATE TABLE. Você precisaria fazer isso:

CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;
Dave Markle
fonte
13

BEGIN e END foram bem respondidos por outros.

Como Gary aponta, GO é um separador de lote, usado pela maioria das ferramentas de cliente fornecidas pela Microsoft, como isql, sqlcmd, analisador de consulta e SQL Server Management Studio. (Pelo menos algumas das ferramentas permitem que o separador de lote seja alterado. Nunca vi um uso para alterar o separador de lote.)

Para responder à pergunta de quando usar GO, é preciso saber quando o SQL deve ser separado em lotes.

Algumas instruções devem ser a primeira instrução de um lote.

select 1
create procedure #Zero as
    return 0

No SQL Server 2000, o erro é:

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.

No SQL Server 2005, o erro é menos útil:

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

Portanto, use GOpara separar as instruções que devem ser o início de um lote das instruções que o precedem em um script.

Ao executar um script, muitos erros farão com que a execução do lote pare, mas então o cliente simplesmente enviará o próximo lote, a execução do script não parará. Costumo usar isso em testes. Vou iniciar o script com begin transaction e terminar rollback, fazendo todos os testes no meio:

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

Dessa forma, eu sempre retorno ao estado inicial, mesmo se um erro acontecer no código de teste, as instruções de transação de início e rollback que fazem parte de lotes separados ainda acontecem. Se eles não estivessem em lotes separados, um erro de sintaxe impediria o início da transação, já que um lote é analisado como uma unidade. E um erro de tempo de execução impediria a reversão.

Além disso, se você estiver executando um script de instalação e tiver vários lotes em um arquivo, um erro em um lote não impedirá que o script continue a ser executado, o que pode causar uma confusão. (Sempre faça backup antes de instalar.)

Relacionado ao que Dave Markel apontou, há casos em que a análise falhará porque o SQL Server está procurando no dicionário de dados por objetos criados anteriormente no lote, mas a análise pode acontecer antes que qualquer instrução seja executada. Às vezes, isso é um problema, às vezes não. Não consigo dar um bom exemplo. Mas se você receber um erro 'X não existe', quando ele claramente existirá por meio dessa instrução, divida em lotes.

E uma nota final. A transação pode abranger lotes. (Veja acima.) Variáveis ​​não abrangem lotes.

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

Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".
Shannon Severance
fonte
1
Isso é o que eu precisava, obrigado: "A transação pode abranger lotes. Variáveis ​​não abrangem lotes."
Gary
3

GO termina um lote, você raramente precisará usá-lo no código. Esteja ciente de que se você usá-lo em um proc armazenado, nenhum código após o GO será executado quando você executar o proc.

BEGIN e END são necessários para qualquer instrução de tipo procedural com várias linhas de código para processar. Você vai precisar deles para loops e cursores WHILE (que você evitará se possível, é claro) e instruções IF (bem, tecnicamente, você não precisa deles para uma instrução IF que tem apenas uma linha de código, mas é mais fácil manter o código se você sempre colocá-los após um IF). As instruções CASE também usam END, mas não têm BEGIN.

HLGEM
fonte
Algum código após o GO seria realmente armazenado no proc armazenado? a instrução CREATE ou ALTER não seria processada como se não existisse código após GO? E ENTÃO o código após o GO é executado como se fosse o seu próprio script?
MatBailie
O que os cursores têm a ver com isso?
Gary McGill
3

Depois de lutar com esse problema hoje, minha opinião é a seguinte: BEGIN ... END código de colchetes assim como {....} faz em linguagens C, por exemplo, blocos de código para if ... else e loops

GO é (deve ser) usado quando as instruções subsequentes dependem de um objeto definido por uma instrução anterior. O banco de dados USE é um bom exemplo acima, mas o seguinte também vai incomodar você:

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.

Parece-me que o problema é o seguinte: o SQL Server SQL Parser, ao contrário do Oracle, não consegue perceber que você está definindo um novo símbolo na primeira linha e que não há problema em fazer referência nas linhas seguintes. Ele não "vê" o símbolo até encontrar um token GO que o informa para executar o SQL anterior desde o último GO, ponto no qual o símbolo é aplicado ao banco de dados e se torna visível para o analisador.

Por que ele não trata o ponto-e-vírgula apenas como uma quebra semântica e aplica declarações individualmente, não sei e gostaria que fizesse. O único bônus que vejo é que você pode colocar uma instrução print () logo antes de GO e se alguma das instruções falhar, o print não será executado. Muitos problemas para um ganho menor.

matao
fonte