¿Cuándo necesito usar los bloques Begin / End y la palabra clave Go en SQL Server?

103

¿Alguien puede decirme cuándo y dónde necesito usar beginy endbloques en SQL Server?
Además, ¿qué hace exactamente la Gopalabra clave?

Tarik
fuente

Respuestas:

116

GO es como el final de un guión.

Puede tener varias declaraciones CREATE TABLE, separadas por GO. Es una forma de aislar una parte del script de otra, pero enviarlo todo en un bloque.


BEGIN y END son como {y} en C / ++ / #, Java, etc.

Unieron un bloque lógico de código. Tiendo a usar BEGIN y END al principio y al final de un procedimiento almacenado, pero no es estrictamente necesario allí. Donde ES necesario es para bucles y declaraciones IF, etc., donde necesita más de un paso ...

IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
   INSERT INTO Log SELECT @id, 'deleted'
   DELETE my_table WHERE id = @id
END
MatBailie
fuente
¿Ha intentado crear un SP sin BEGIN y END? IIRC, solo la primera línea está incluida en el SP, el resto simplemente se ejecuta allí y luego ...
cjk
2
Ciertamente, esa no es mi experiencia desde SQL Server 2000 en adelante.
MatBailie
1
¿BEGIN y END también definen un nuevo alcance?
samis
2
Si. Todo lo que se declare en el exterior es visible en el interior, pero todo lo que se declara en el interior saldrá del alcance en el FIN.
MatBailie
36

Necesita BEGIN ... END para crear un bloque que abarque más de una declaración. Entonces, si quisiera hacer 2 cosas en un 'tramo' de una declaración IF, o si quisiera hacer más de una cosa en el cuerpo de un bucle WHILE, necesitaría poner esas declaraciones entre corchetes con BEGIN ... FINAL.

La palabra clave GO no forma parte de SQL. Solo lo utiliza el Analizador de consultas para dividir los scripts en "lotes" que se ejecutan de forma independiente.

Gary McGill
fuente
28

GO no es una palabra clave en SQL Server; es un separador de lotes. GO finaliza un lote de declaraciones. Esto es especialmente útil cuando está utilizando algo como SQLCMD. Imagine que está ingresando sentencias SQL en la línea de comando. No necesariamente desea que la cosa se ejecute cada vez que finaliza una declaración, por lo que SQL Server no hace nada hasta que ingresa "GO".

Del mismo modo, antes de que comience su lote, a menudo necesita tener algunos objetos visibles. Por ejemplo, digamos que está creando una base de datos y luego la está consultando. No puedes escribir:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

porque foo no existe para el lote que hace CREATE TABLE. Necesitarías hacer esto:

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

BEGIN y END han sido bien respondidos por otros.

Como señala Gary, GO es un separador de lotes, utilizado por la mayoría de las herramientas de cliente suministradas por Microsoft, como isql, sqlcmd, analizador de consultas y SQL Server Management Studio. (Al menos algunas de las herramientas permiten cambiar el separador de lotes. Nunca he visto un uso para cambiar el separador de lotes).

Para responder a la pregunta de cuándo utilizar GO, es necesario saber cuándo debe separarse el SQL en lotes.

Algunas declaraciones deben ser la primera declaración de un lote.

select 1
create procedure #Zero as
    return 0

En SQL Server 2000, el error es:

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.

En SQL Server 2005, el error es 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.

Por lo tanto, use GOpara separar las declaraciones que tienen que ser el comienzo de un lote de las declaraciones que lo preceden en un script.

Al ejecutar un script, muchos errores harán que la ejecución del lote se detenga, pero luego el cliente simplemente enviará el siguiente lote, la ejecución del script no se detendrá. A menudo uso esto en las pruebas. Comenzaré el script con begin transaction y terminaré con rollback, haciendo todas las pruebas en el medio:

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

De esa manera, siempre regreso al estado inicial, incluso si ocurrió un error en el código de prueba, las declaraciones de transacción de inicio y reversión que forman parte de lotes separados todavía ocurren. Si no estuvieran en lotes separados, entonces un error de sintaxis evitaría que se iniciara la transacción, ya que un lote se analiza como una unidad. Y un error de tiempo de ejecución evitaría que se produjera la reversión.

Además, si está instalando un script y tiene varios lotes en un archivo, un error en un lote no evitará que el script continúe ejecutándose, lo que puede causar un desastre. (Siempre haga una copia de seguridad antes de instalar).

En relación con lo que señaló Dave Markel, hay casos en los que el análisis fallará porque SQL Server busca en el diccionario de datos los objetos que se crearon anteriormente en el lote, pero el análisis puede ocurrir antes de que se ejecute cualquier declaración. A veces, esto es un problema, a veces no. No puedo dar un buen ejemplo. Pero si alguna vez obtiene un error 'X no existe', cuando claramente existirá por esa declaración, divídalo en lotes.

Y una nota final. La transacción puede abarcar lotes. (Consulte más arriba). Las variables no abarcan lotes.

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

Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".
Despido de Shannon
fuente
1
Esto es lo que necesitaba, gracias: "La transacción puede abarcar lotes. Las variables no abarcan lotes".
Gary
3

GO finaliza un lote, solo en muy raras ocasiones necesitaría usarlo en el código. Tenga en cuenta que si lo usa en un proceso almacenado, no se ejecutará ningún código después de GO cuando ejecute el proceso.

BEGIN y END son necesarios para procesar cualquier instrucción de tipo de procedimiento con varias líneas de código. Los necesitará para los bucles y cursores MIENTRAS (que evitará si es posible, por supuesto) y las instrucciones IF (bueno, técnicamente no los necesita para una instrucción IF que solo tiene una línea de código, pero es más fácil mantenga el código si siempre los coloca después de un IF). Las sentencias CASE también usan un END pero no tienen un BEGIN.

HLGEM
fuente
¿Algún código después del GO se almacenaría realmente en el proceso almacenado? ¿No se procesaría la instrucción CREATE o ALTER como si el código después de GO no existiera? ¿Y ENTONCES el código después de que el GO se ejecute como si fuera su propio script?
MatBailie
¿Qué tienen que ver los cursores con eso?
Gary McGill
3

Después de luchar con este problema hoy, mi opinión es la siguiente: BEGIN ... END código de corchetes tal como lo hace {....} en lenguajes C, por ejemplo, bloques de código para if ... else y bucles

GO se usa (debe ser) usado cuando las declaraciones subsiguientes se basan en un objeto definido por una declaración anterior. USE database es un buen ejemplo anterior, pero lo siguiente también lo 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.

Me parece que el problema es este: SQL Server SQL Parser, a diferencia del Oracle, no puede darse cuenta de que está definiendo un nuevo símbolo en la primera línea y que está bien hacer referencia en las siguientes líneas. No "ve" el símbolo hasta que encuentra un token GO que le dice que ejecute el SQL anterior desde el último GO, momento en el que el símbolo se aplica a la base de datos y se vuelve visible para el analizador.

Por qué no trata el punto y coma como una ruptura semántica y aplica declaraciones individualmente, no lo sé y desearía que lo hiciera. La única ventaja que puedo ver es que puede poner una declaración print () justo antes de GO y si alguna de las declaraciones falla, la impresión no se ejecutará. Sin embargo, muchos problemas por una pequeña ganancia.

matao
fuente