PowerShell脚本:SQL脚本循环执行遇错如何跳过并续行?
实现单个SQL脚本执行失败后继续循环的方案
当然可以通过嵌套try/catch块来实现这个需求,这也是最直接可靠的方式。你的外层try/catch负责处理整个脚本的顶级错误,但要让单个SQL脚本执行失败不中断循环,必须把每个脚本的完整执行逻辑单独包裹在独立的try/catch块里。
核心思路
把处理单个SQL脚本的所有逻辑(读取文件、处理内容、执行SQL语句)放进try块中,当这个脚本的任何步骤抛出异常时,catch块会捕获错误、记录信息,然后循环会自动继续处理下一个脚本,不会中断整个循环流程。
修改后的代码示例
foreach ($sqlScript in Get-ChildItem -path "$pathToScripts" -Filter *.sql | Sort-Object) { Write-Host "Running Script " $sqlScript.Name try { # 执行当前SQL脚本的完整逻辑 switch ($removeComments) { $true { (Get-Content $sqlScript.FullName -Encoding UTF8 | Out-String) -replace '(?s)/\*.*?\*/', " " -split '\r?\n\s*go\s*\r\n?' -notmatch '^\s*$' | ForEach-Object { $SqlCmd.CommandText = $_.Trim() $reader = $SqlCmd.ExecuteNonQuery() } } $false { (Get-Content $sqlScript.FullName -Encoding UTF8 | Out-String) -split '\r?\n\s*go\s*\r\n?' -notmatch '^\s*$' | ForEach-Object { $SqlCmd.CommandText = $_.Trim() $reader = $SqlCmd.ExecuteNonQuery() } } } Write-Host "Successfully executed script: $($sqlScript.Name)" } catch { # 捕获当前脚本的执行错误,输出警告并继续 Write-Warning "Failed to execute script: $($sqlScript.Name). Error details: $_" # 可选:将错误写入日志文件,方便后续排查 # Add-Content -Path ".\sql_execution_errors.log" -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | Failed script: $($sqlScript.Name) | Error: $_" } }
额外优化:减少代码冗余
你会发现switch的两个分支逻辑高度重复,只有移除注释的步骤不同。可以把重复的SQL执行逻辑提取成一个函数,提升代码的可维护性:
# 定义复用的SQL批量执行函数 function Invoke-SqlBatch { param( [Parameter(Mandatory)] [string]$SqlContent, [Parameter(Mandatory)] [System.Data.SqlClient.SqlCommand]$SqlCmd ) # 按GO拆分语句并执行非空的SQL块 $SqlContent -split '\r?\n\s*go\s*\r\n?' -notmatch '^\s*$' | ForEach-Object { $SqlCmd.CommandText = $_.Trim() $SqlCmd.ExecuteNonQuery() } } # 主循环逻辑 foreach ($sqlScript in Get-ChildItem -path "$pathToScripts" -Filter *.sql | Sort-Object) { Write-Host "Running Script " $sqlScript.Name try { # 读取SQL文件内容 $sqlContent = Get-Content $sqlScript.FullName -Encoding UTF8 | Out-String # 根据需求移除注释 if ($removeComments) { $sqlContent = $sqlContent -replace '(?s)/\*.*?\*/', " " } # 执行SQL批量语句 Invoke-SqlBatch -SqlContent $sqlContent -SqlCmd $SqlCmd Write-Host "Successfully executed script: $($sqlScript.Name)" } catch { Write-Warning "Failed to execute script: $($sqlScript.Name). Error details: $_" # 可选:写入错误日志 # Add-Content -Path ".\sql_execution_errors.log" -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | Failed script: $($sqlScript.Name) | Error: $_" } }
关于其他方式的说明
有人可能会问能不能用ErrorAction参数来跳过错误?但要注意:SqlCmd.ExecuteNonQuery()是.NET方法,它抛出的是终止性异常,而ErrorAction只对PowerShell的原生命令(非.NET方法)的非终止错误有效。所以对于这种场景,嵌套try/catch是唯一可靠的处理方式。
内容的提问来源于stack exchange,提问作者Andrew Lackenby




