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

时间:2009-07-24 21:36:00

标签: sql-server tsql language-features

有人能告诉我在SQL Server中使用beginend块的时间和地点吗?
另外,Go关键字到底有什么作用?

6 个答案:

答案 0 :(得分:101)

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

答案 1 :(得分:33)

你需要BEGIN ... END来创建一个跨越多个语句的块。所以,如果你想在IF语句的一个'leg'中做两件事,或者你想在WHILE循环的主体中做多件事,你需要用BEGIN括起那些语句...... END。

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

答案 2 :(得分:24)

GO不是SQL Server中的关键字;这是一个批处理分隔符。 GO结束了一批陈述。当您使用SQLCMD之类的东西时,这尤其有用。想象一下,您正在命令行中输入SQL语句。每次结束语句时都不一定要执行该操作,因此在您输入“GO”之前,SQL Server不执行任何操作。

同样,在批量启动之前,您经常需要显示一些对象。例如,假设您正在创建一个数据库,然后查询它。你不能写:

CREATE DATABASE foo;
USE foo;
CREATE TABLE bar;

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

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

答案 3 :(得分:10)

BEGIN和END已得到其他人的好评。

正如Gary所指出的,GO是一个批处理分隔符,由大多数Microsoft提供的客户端工具使用,例如isql,sqlcmd,查询分析器和SQL Server Management工作室。 (至少有一些工具允许更改批处理分隔符。我从未见过用于更改批处理分隔符的用途。)

要回答何时使用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

这样我总是返回到起始状态,即使测试代码中发生错误,开始和回滚事务语句仍然是单独批处理的一部分。如果它们不是分开的批处理,则语法错误会使开始事务不发生,因为批处理被解析为一个单元。并且运行时错误会阻止回滚发生。

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

与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".

答案 4 :(得分:2)

GO结束批处理,你很少需要在代码中使用它。请注意,如果您在存储过程中使用它,则在执行proc时将不执行GO之后的代码。

对于要处理多行代码的任何过程类型语句,需要

BEGIN和END。你需要它们用于WHILE循环和游标(当然,如果可能的话,你会避免)和IF语句(从技术上来说,你不需要它们来获得只有一行代码的IF语句,但它更容易如果你总是在IF之后把它们放进去,那就维护一下代码。 CASE语句也使用END但没有BEGIN。

答案 5 :(得分:2)

今天在遇到这个问题之后,我的意见是这样的: 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.

在我看来问题是这样的:SQL Server SQL Parser与Oracle不同,它无法意识到您在第一行定义了一个新符号,并且可以在以下行中引用它。它不会“看到”符号,直到遇到一个GO令牌,告诉它自上次执行GO以来执行前面的SQL,此时符号将应用于数据库并对解析器可见。

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