我需要针对事务中的服务器运行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'已经是默认分隔符。
答案 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