Answers:
GO就像脚本的结尾。
您可能有多个CREATE TABLE语句,以GO分隔。这是一种将脚本的一部分与另一部分隔离开来的方法,但是将其全部提交到一个块中。
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
GO不是SQL Server中的关键字。这是一个批处理分隔符。GO结束了一批语句。当您使用类似SQLCMD的东西时,这特别有用。假设您在命令行中输入SQL语句。您不一定希望每次结束语句时都执行该操作,因此SQL Server在您输入“ GO”之前不会执行任何操作。
同样,在批处理开始之前,您通常需要使一些对象可见。例如,假设您正在创建一个数据库,然后对其进行查询。你不能写:
CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;
因为对于创建CREATE TABLE的批处理来说foo不存在。您需要这样做:
CREATE DATABASE foo;
GO
USE foo;
CREATE TABLE bar;
BEGIN和END得到了他人的良好回答。
正如Gary所指出的,GO是批处理分隔符,由Microsoft提供的大多数客户端工具(例如isql,sqlcmd,查询分析器和SQL Server Management Studio)使用。(至少某些工具允许更改批处理分隔符。我从未见过用于更改批处理分隔符的用法。)
为了回答何时使用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
将必须作为批处理开始的语句与脚本中位于其前的语句分开。
运行脚本时,许多错误将导致批处理的执行停止,但是客户端将仅发送下一个批处理,脚本的执行将不会停止。我经常在测试中使用它。我将以开始事务开始脚本并以回退结束脚本,并在中间进行所有测试:
begin transaction
go
... test code here ...
go
rollback transaction
这样,即使测试代码中发生错误,我也始终返回到起始状态,仍然会发生分别作为单独批处理的一部分的begin和rollback事务语句。如果它们不是分开的批次,则语法错误将阻止开始事务的发生,因为批次被解析为一个单元。并且运行时错误将阻止回滚的发生。
另外,如果您正在执行安装脚本,并且在一个文件中有多个批处理,则一个批处理中的错误将使脚本无法继续运行,这可能会造成混乱。(在安装前始终备份。)
与Dave Markel指出的有关,在某些情况下,解析将失败,因为SQL Server在数据字典中查找了在批处理中较早创建的对象,但是解析可以在运行任何语句之前进行。有时这是一个问题,有时不是。我无法提出一个很好的例子。但是,如果您遇到“ X不存在”错误,则该语句将明码存在时将分成几批。
最后一点。交易可以跨越批次。(请参见上文。)变量不跨批次。
declare @i int
set @i = 0
go
print @i
Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@i".
GO结束了一批,您只需要很少在代码中使用它。请注意,如果在存储的proc中使用它,则在执行proc时,GO之后的代码将不会执行。
对于需要处理多行代码的任何过程类型语句,都需要BEGIN和END。您将需要它们用于WHILE循环和游标(当然,尽可能避免使用)和IF语句(从技术上讲,对于仅包含一行代码的IF语句,您不需要它们),但更容易如果您总是将它们放在IF之后,请保留代码)。CASE语句也使用END,但没有BEGIN。
在解决了这个问题之后,今天我的看法是:BEGIN ... END括号中的代码就像{....}在C语言中一样,例如if ... else和loops的代码块
当后续语句依赖于前一个语句定义的对象时,将(必须)使用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 SQL Parser无法意识到您在第一行中定义了一个新符号,并且可以在以下几行中进行引用。它直到遇到GO令牌后才“看到”该符号,该令牌告诉该令牌自上一个GO以来执行先前的SQL,此时该符号已应用于数据库并对于解析器可见。
为什么它不只是将分号视为语义中断并单独应用语句,我不知道并且希望如此。我唯一能看到的好处是,您可以在GO之前放置一条print()语句,如果任何一条语句失败,将无法执行打印。虽然麻烦很多,但收获不大。