可以有多个 CREATETABLE 语句,用 GO 分隔。这是一种将脚本的一部分与另一部分隔离的方法,但是要在一个块中提交所有脚本。
BEGIN 和 END 就像 C/+ +/# 、 Java 等语言中的{ and }。
They bound a logical block of code. I tend to use BEGIN and END at the start and end of a stored procedure, but it's not strictly necessary there. Where it IS necessary is for loops, and IF statements, etc, where you need more then one step...
IF EXISTS (SELECT * FROM my_table WHERE id = @id)
BEGIN
INSERT INTO Log SELECT @id, 'deleted'
DELETE my_table WHERE id = @id
END
GO 结束一个批处理,你只需要很少在代码中使用它。请注意,如果在存储过程中使用它,那么在执行过程时将不会执行 GO 之后的代码。
对于任何要处理多行代码的过程类型语句,都需要 BEGIN 和 END。您将需要它们用于 WHILE 循环和游标(当然,如果可能的话,您将尽量避免使用它们)和 IF 语句(从技术上讲,您不需要它们用于只有一行代码的 IF 语句,但是如果您总是将它们放在 IF 之后,则更容易维护代码)。CASE 语句也使用 END,但没有 BEGIN。
正如 Gary 所指出的,GO 是一个批分隔符,被大多数 Microsoft 提供的客户端工具使用,如 isql、 sqlcmd、查询分析器和 SQL Server Management Studio。(至少有一些工具允许更改批分离器。我从未见过更换批分离器有什么用处。)
要回答何时使用 GO 的问题,需要知道 SQL 何时必须分成批。
Some statements must be the first statement of a batch.
select 1
create procedure #Zero as
return 0
在 SQLServer2000上,错误是:
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.
在 SQLServer2005上,该错误就没那么有用了:
Msg 178, Level 15, State 1, Procedure #Zero, Line 5
A RETURN statement with a return value cannot be used in this context.
begin transaction
go
... test code here ...
go
rollback transaction
That way I always return to the starting state, even if an error happened in the test code, the begin and rollback transaction statements being part of a separate batches still happens. If they weren't in separate batches, then a syntax error would keep begin transaction from happening, since a batch is parsed as a unit. And a runtime error would keep the rollback from happening.
Also, if you are doing an install script, and have several batches in one file, an error in one batch will not keep the script from continuing to run, which may leave a mess. (Always backup before installing.)
与 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".
经过今天与这个问题的斗争,我的观点是:
BEGIN... END 括号代码就像 C 语言中的{ ... . }一样,例如 if... else 和循环的代码块
GO is (must be) used when succeeding statements rely on an object defined by a previous statement. USE database is a good example above, but the following will also bite you:
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.
在我看来,问题在于: SQL Server SQL Parser 与 Oracle 不同,它无法意识到您在第一行定义了一个新的符号,并且可以在以下几行中引用。直到遇到 GO 令牌,它才“看到”这个符号,GO 令牌告诉它从上一个 GO 开始执行前面的 SQL,此时这个符号被应用到数据库,并且对解析器来说是可见的。
为什么它不仅仅把分号当作一个语义突破,然后单独应用语句呢? 我不知道,也希望它这样做。我看到的唯一好处是,您可以在 GO 之前放置一个 print ()语句,如果任何语句失败,print 将不会执行。不过为了一点小小的收获,麻烦可就大了。