我们可以在SQL Transaction中多次使用'GO'吗?

时间:2015-12-09 11:57:30

标签: sql sql-server tsql

我们可以在GO中多次使用SQL Transaction语句。我有一个很长的T-SQL脚本,我想在SQL Transaction中运行它。如果一切顺利,那么我将提交否则将回滚。

但是,在运行该查询时,我收到了'create function must be the only statement in the batch'之类的错误。因为我在创建和删除许多功能和程序。

我没有在脚本中的任何位置使用GO。我的问题是 - 我可以在那个长脚本中多次使用GO语句。因为,GO创建了一个批处理,如果批处理第一次成功执行但下次失败,那么rollback transaction语句是否能够实际回滚已经执行的那些?

我的脚本结构如下:

PRINT 'Transaction Started'
BEGIN TRY
    BEGIN TRAN

    Drop Function 
    ....
    ....
    Create Function
    ....
    ....
    Drop Procedure
    ....
    ....
    Lots of statements
    ....
    ....

    COMMIT TRAN
    PRINT 'Transaction Succeeded'
END TRY
BEGIN CATCH
    PRINT 'Transaction Failed'
    IF(@@TRANCOUNT > 0)
        ROLLBACK TRAN
END CATCH

我正在创建此脚本,以便在单个脚本中将一些更改从newDB迁移到oldDB。

3 个答案:

答案 0 :(得分:26)

你正在混合概念。 geocoder.geocode不是Transact-SQL概念,不是语言的一部分,并且不被SQL Server理解。 GO是工具批处理分隔符。默认情况下,GO和SSMS都使用sqlcmd.exe作为批处理分隔符。批处理分隔符用于标识SQL源文件中的各个批处理。客户端工具一次向服务器发送一批(当然,省略分隔符)。

交易可以跨越批次。 TRY / CATCH块不能。 CREATE / ALTER语句必须是批处理中的唯一语句(注释不是语句,并且函数过程体中包含的语句包含在内)。

可以通过启动事务并在第一个错误(GO开始-bsqlcmd.exe开始时)中止执行来实现类似于您想要执行的操作。

但是在长事务中执行DDL是行不通的。特别是如果你打算将它与DML混合使用。 我必须调查的大多数损坏来自这种组合(Xact,DDL + DML,回滚)。我强烈建议不要这样做。

安全部署架构更新的唯一方法是在出现问题时从备份进行备份,部署和还原。

请注意Dan推荐的内容(动态SQL)有效,因为sp_executesql启动了一个新的内部批处理。该批次将满足CREATE / ALTER限制。

答案 1 :(得分:3)

请注意GO is not a SQL keyword。它是SQL Server Management Studio和其他客户端工具使用的客户端批处理分隔符。

GO对交易范围没有影响。 BEGIN TRAN将在当前连接上启动一个事务。 COMMIT和ROLLBACK将结束交易。您可以根据需要执行任意数量的语句。 GO将分别执行这些陈述。

MSDN指定:

  

TRY ... CATCH构造不能跨越多个批次。

因此,GO分隔符无法将BEGIN TRY,END TRY,BEGIN CATCH和END CATCH分成单独的批次。它们必须出现在同一个查询中。

如果您尝试在TRY / CATCH语句中包含批处理分隔符,如下面的无效SQL:

begin try
    go
end try
begin catch
    go
end catch

这将执行3个返回语法错误的不同查询:

1)begin try

Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'begin'.

2)end try begin catch

Msg 102, Level 15, State 1, Line 3
Incorrect syntax near 'try'.

3)end catch

Msg 102, Level 15, State 1, Line 6
Incorrect syntax near 'catch'.

答案 2 :(得分:1)

GO是一个很好用的关键字。 GO将完成最后一个代码块并继续到下一个块。是的,您可以在语句中使用多个GO将其分解为多个批次。但是,由于您正在执行基于事务的逻辑,因此将try / catch逻辑与GO组合使用会更好。 https://msdn.microsoft.com/en-us/library/ms175976.aspx这个网站给你一些关于使用它的锄头的例子,如果你遇到麻烦,你可以输出该错误并继续,如果你选择。