在Powershell的事务中运行由GO分隔的SQL批处理

时间:2017-11-08 15:42:06

标签: sql-server powershell transactions

我需要针对事务中的服务器运行sql文件的内容。该文件包含由GO语句分隔的批处理,因此T-SQL TRY-CATCH ROLLBACK不行。

Invoke-Sqlcmd -InputFile完美无缺,除非与System.Transactions.TransactionScope一起使用时,异常仅表示事务已中止,未输出有用信息(已检查内部异常,没有)。

所以我尝试将System.Data.SqlClient.SqlConnection事务与System.Data.SqlClient.SqlCommand结合使用,效果很好,但是对GO语句扼杀了。

最佳解决方案是使用Microsoft.SqlServer.Management.Smo.Server对象,但我有一个奇怪的问题,它将每一行视为单独的批处理。

代码:

$server = New-Object Microsoft.SqlServer.Management.Smo.Server($databaseServer)
$server.ConnectionContext.ConnectionString = $connectionString


$script = Get-Content "$sqlScriptsPath\$scriptName.sql"
try
{
   $server.ConnectionContext.BeginTransaction()
   $server.ConnectionContext.ExecuteNonQuery($script)
   $server.ConnectionContext.CommitTransaction()
}
catch
{
   $server.ConnectionContext.RollBackTransaction()
   throw
}

当文件只包含单行语句时(我用插件测试它),它可以正常工作,但每当命令是多行时,它就会输出类似"'&#39附近的语法错误;)'"或某事,取决于具体情况。

例如:

DECLARE @msg varchar(50) = 'test'
PRINT @msg

将抛出"必须声明标量变量" @ msg"。"

但是当文件中的两个命令都在一行中用';'它有效。

我尝试了显而易见的事:$server.ConnectionContext.BatchSeparator = 'GO'但它没有任何改变,因为' GO'已经是默认分隔符。

2 个答案:

答案 0 :(得分:0)

我过去所做的是将PowerShell方面的语句拆分出来并单独执行每个语句。我所做的简单方法是将语句拆分为“GO”关键字,例如:

$server = New-Object Microsoft.SqlServer.Management.Smo.Server($databaseServer)
$server.ConnectionContext.ConnectionString = $connectionString


$script = Get-Content "$sqlScriptsPath\$scriptName.sql"

$ScriptArr = $script -split "GO"

$ScriptArr | foreach {
   try
   {
      $server.ConnectionContext.BeginTransaction()
      $server.ConnectionContext.ExecuteNonQuery($_)
      $server.ConnectionContext.CommitTransaction()
   }
   catch
   {
      $server.ConnectionContext.RollBackTransaction()
      throw
   }
}

这将通过“GO”语句拆分输入代码,并且由于split语句,拆分字符串将不包含“GO”语句。

答案 1 :(得分:0)

问题是没有-Raw标志的cmdlet Get-Content返回一个行数组。

解决方案:

$script = Get-Content "$sqlScriptsPath\$scriptName.sql" -Raw