在 SQL Server 中,何时使用 BEGIN
和 END
关键字的准则是什么?
此外,GO
关键字具体是做什么用的?
在 SQL Server 中,何时使用 BEGIN
和 END
关键字的准则是什么?
此外,GO
关键字具体是做什么用的?
GO就像脚本的结尾。
你可以有多个CREATE TABLE语句,它们之间用GO分隔。这是一种将脚本的不同部分隔离开来但又可以作为一个块提交的方法。
BEGIN和END就像C / ++ / #、Java等中的{和}一样。
它们将一段逻辑代码绑定在一起。我倾向于在存储过程的开头和结尾使用BEGIN和END,但在那里并非严格必要。在需要循环,IF语句等多步操作时,则必须使用BEGIN和END。
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
来创建跨越多个语句的块。因此,如果您想在IF
语句的一个“段”中执行2个操作,或者如果您想在WHILE
循环的主体中执行多个操作,则需要用BEGIN
...END
括起这些语句。
GO
关键字不是SQL的一部分。它仅由查询分析器用于将脚本划分为独立执行的“批次”。在SQL Server中,GO不是一个关键字,而是批处理分隔符。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是一个批处理分隔符,由大多数微软提供的客户端工具使用,比如isql、sqlcmd、查询分析器和SQL Server管理工作室。(至少一些工具允许更改批处理分隔符。我从未见过更改批处理分隔符的用途。)
要回答何时使用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开始脚本,以rollback结束脚本,在中间进行所有测试:
begin transaction
go
... test code here ...
go
rollback transaction
那样做的好处是,即使测试代码中发生错误,事务的开始和回滚语句仍然会在单独的批次中发生,使我始终返回到起始状态。如果它们不在单独的批次中,则语法错误将阻止“begin transaction”发生,因为一个批次被解析为一个单位。而运行时错误会防止回滚发生。此外,如果您正在执行安装脚本,并且在一个文件中有多个批次,一个批次中的错误不会阻止脚本继续运行,这可能会留下混乱(安装之前始终备份)。与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用于结束一批操作,通常情况下你不需要在代码中使用它。请注意,如果你在存储过程中使用它,在执行存储过程时,GO之后的代码将不会被执行。
BEGIN和END用于处理有多行代码的过程类型语句。你需要它们来处理WHILE循环和游标(当然,如果可能的话,你会尽量避免使用游标),以及IF语句(严格地说,如果IF语句只有一行代码,你不需要它们,但是如果你在IF之后总是加上它们,那么代码更容易维护)。CASE语句也使用END,但没有BEGIN。
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.