【问题标题】:Running SQL batches separated by GO in transaction from Powershell在 Powershell 的事务中运行由 GO 分隔的 SQL 批处理
【发布时间】:2017-11-08 15:42:05
【问题描述】:

我需要针对服务器内部事务运行 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
}

当文件仅包含单行语句(我正在使用插入测试它)时,它可以正常工作,但是只要命令是多行的,它就会阻塞输出类似“')'附近的语法错误”。或其他东西,取决于上下文。

例如:

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

会抛出“必须声明标量变量“@msg”。”

但是当文件在一行中包含两个命令时,由 ';' 分隔它有效。

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

【问题讨论】:

    标签: sql-server powershell transactions


    【解决方案1】:

    我过去所做的是在事物的 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”语句拆分输入代码,并且由于拆分语句,拆分字符串将不包含“GO”语句。

    【讨论】:

    • 感谢您的回复。但是,我是否计划通过 GO 拆分,我会选择 System.Data.SqlClient.SqlConnection 和 System.Data.SqlClient.SqlCommand ,它们更流行和更强大。并且不要像这样被 GO 分割,字符串和变量名中可以有“GO”!至少使用 ^\sGO\s ($ | \-\- .*$) 之类的正则表达式(来源:stackoverflow.com/q/27301225/3922292
    【解决方案2】:

    问题是在没有 -Raw 标志的情况下使用的 cmdlet Get-Content 返回一个行数组。

    解决方案:

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

    【讨论】:

      猜你喜欢
      • 2021-10-31
      • 2016-01-09
      • 2014-04-20
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多