SQL Server 迁移脚本中的多个批处理

Sea*_*ish 3 sql-server ssms sql-server-2016

我正在尝试提出一个数据库脚本,用于将应用程序数据库的早期版本迁移到更高版本。差异相当大,完成迁移将涉及创建新表、重命名表、添加函数、添加具有依赖于这些函数的计算列的视图等。脚本完成后,我将其交给其他人在目标环境上运行。

我希望能够在单个事务中运行整个迁移,这样如果出现问题,回滚就很容易了。

我遇到的问题是,当脚本尝试时CREATE FUNCTION,它会抱怨:

SQL80001:语法不正确:“CREATE FUNCTION”必须是批处理中的唯一语句。

我做了一些研究,发现 SSMS 允许使用GO关键字来分隔批次,但是每次我尝试将整个脚本包装在 a 中BEGIN TRANSACTION,然后包含 aGO以将 create 函数调用分离到自己的批次中时,我得到一个错误:

“GO”附近的语法不正确。

我不知道为什么,因为像这样的答案似乎适用于那里的 GO 语句。

我还假设(可能是错误的)我提供脚本的人将使用 SSMS。

我还发现了几篇提到 using 的文章,SET XACT_ABORT ON;我一开始就在交易之外尝试过。

所以我的脚本看起来像这样:

SET XACT_ABORT ON
GO
BEGIN TRY
BEGIN TRANSACTION
    -- Create some tables
    GO -- Error
    CREATE FUNCTION [...]
    GO -- Error
    -- Create some views that rely on the above function
    COMMIT TRANSACTION
END TRY -- With the GOs in there, this line also gives an error: Incorrect syntax near 'TRY'. Expecting CONVERSATION.
BEGIN CATCH
    -- Error handling, including transaction rollback
END CATCH
Run Code Online (Sandbox Code Playgroud)

关于如何在单个脚本中使用多个批次但一个事务迁移 SQL 数据库的任何建议?

Dav*_*oft 5

问题实际上只是关于错误处理,因为当您在 SSMS 查询窗口(以太正常或 SQLCMD 模式)中运行脚本时,SSMS 无法跨批次处理错误。因此,您的事务可能会中止,而 SSMS 将运行下一批。

如果您使用 SQLCMD 运行脚本,您可以在第一批中启动一个事务,并使用 -b 开关。任何错误都会中止脚本并回滚您的事务。

例如

use tempdb
go
begin transaction
-- be sure to run with sqlcmd -b
-- eg c:> sqlcmd -b -i c:\deploy\thisscript.sql
go

--. . . any number of batches here


go

commit transaction

go
Run Code Online (Sandbox Code Playgroud)

当然,您必须确保您的脚本不会提交或回滚事务、捕获错误或包含任何无法在事务中运行的语句(例如向数据库添加文件)。

类似地,您可以在 .NET 或 PowerShell 中自己分批批处理,启动事务,然后单独运行每个批处理,仅当所有批处理都没有错误运行时才提交。

处理整个场景的另一个好方法(如果您可以在中断期间进行升级)是使用数据库快照。万一发生故障,从数据库快照还原允许快速回滚所有升级操作,而无需事务。