我什么时候需要在SQL Server中使用Begin / End Blocks和Go关键字?

有人可以告诉我何时何地需要在SQL Server中使用beginend块?
另外, Go关键字究竟干什么?

GO就像一个脚本的结尾。

您可以有多个由GO分隔的CREATE TABLE语句。 这是将脚本的一部分与另一部分隔离的一种方式,但是将其全部在一个块中提交。

BEGIN和END就像C / ++ /#,Java等中的{和}一样。

他们绑定了一个逻辑代码块。 我倾向于在存储过程的开始和结束时使用BEGIN和END,但这不是必须的。 哪里有必要的循环,IF语句等,你需要更多的一步…

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

您需要BEGIN … END来创build跨越多个语句的块。 所以,如果你想在IF语句的一条“腿”中做两件事情,或者如果你想在WHILE循环的主体中做多个事情,你需要用BEGIN括起这些语句。结束。

GO关键字不是SQL的一部分。 它只被查询分析器用来将脚本划分为独立执行的“批处理”。

GO不是SQL Server中的关键字; 这是一个批处理分隔符。 GO结束一批语句。 当你使用类似SQLCMD的东西时,这是特别有用的。 想象一下,你正在命令行inputSQL语句。 您不一定要每次结束语句时都要执行该操作,因此直到您input“GO”,SQL Server才会执行任何操作。

同样,在开始批处理之前,您经常需要看到一些对象。 例如,假设您正在创build一个数据库,然后查询它。 你不能写:

 CREATE DATABASE foo; USE foo; CREATE TABLE bar; 

因为foo对于执行CREATE TABLE的批处理不存在。 你需要这样做:

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

BEGIN和END已经被其他人很好的回答了。

正如Gary指出的那样,GO是批处理分隔符,由大多数Microsoft提供的客户端工具(如isql,sqlcmd,查询分析器和SQL Server Management Studio)使用。 (至less有一些工具允许更改批次分隔符,我从来没有看到用于更改批次分隔符的用法。)

要回答何时使用GO的问题,需要知道SQL何时必须分成批。

一些陈述必须是批次的第一个陈述。

 select 1 create procedure #Zero as return 0 

在SQL Server 2000上,错误是:

 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. 

在SQL Server 2005上,这个错误不太有用:

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

因此,使用GO来分隔从脚本中的语句开始的语句。

运行一个脚本时,很多错误都会导致批处理执行停止,但是客户端只会发送下一批,脚本的执行不会停止。 我经常在testing中使用这个。 我将以开始事务启动脚本,并以回滚结束,在中间进行所有testing:

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

这样,我总是返回到开始状态,即使在testing代码中发生错误,仍然会发生作为单独批处理的一部分的开始和回滚事务语句。 如果它们不是在单独的批处理中,那么语法错误会使开始事务不再发生,因为批处理被parsing为一个单元。 而运行时错误会阻止回滚的发生。

另外,如果您正在执行安装脚本,并且在一个文件中有多个批处理,则批处理中的错误不会使脚本继续运行,这可能会导致混乱。 (总是在安装之前备份。)

Dave Markel指出,有些情况下,parsing将会失败,因为SQL Server正在查看数据字典中是否有在批处理中创build的对象,但是parsing可能会在任何语句运行之前发生。 有时这是一个问题,有时候不是。 我不能拿出一个好榜样。 但是如果你得到一个'X不存在'的错误,那么当它清楚地将这个语句存在的时候就会闯入批量。

最后一个注意。 交易可以跨越批次。 (请参阅上文。)variables不会跨批次。

 declare @i int set @i = 0 go print @i Msg 137, Level 15, State 2, Line 1 Must declare the scalar variable "@i". 

GO结束一批,你只会很less需要在代码中使用它。 请注意,如果您在存储过程中使用它,执行过程时将不会执行GO之后的代码。

BEGIN和END对于任何具有多行代码处理的过程types语句都是必需的。 您将需要它们用于WHILE循环和游标(当然,如果可能的话,您将避免使用它们)和IF语句(技术上说,对于只有一行代码的IF语句,并不需要它们,但是更容易维护代码,如果你总是把它们放在IF之后)。 CASE语句也使用END,但没有BEGIN。

今天摔跤这个问题后,我的意见是这样的:BEGIN … END括号代码就像{….}在C语言中做的,例如if … else和loop的代码块

GO(必须)在成功的语句依赖于前一个语句定义的对象时使用。 上面的USE数据库就是一个很好的例子,但是下面也会咬你的:

 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. 

在我看来,问题是这样的:与Oracle不同,SQL Server SQLparsing器无法实现在第一行定义新符号,并且可以在以下行中引用。 它不会“看见”该符号,直到它遇到一个GO令牌,它告诉它从上一个GO开始执行前面的SQL,此时该符号将被应用到数据库并对parsing器可见。

为什么它不仅仅把分号当作语义中断,而是单独应用陈述我不知道也不希望这样做。 我能看到的唯一的好处是,你可以在GO之前放一个print()语句,如果有任何语句失败,打印将不会执行。 很多麻烦虽然有小的收获。