在TSQL错误消息中获取文件中的行号
考虑下面的sql脚本
:ON ERROR EXIT PRINT 'Line 3' GO PRINT 'Line 6' GO SELECT * FROM NonExistingTable GO PRINT 'Line 12' GO 使用SQLCMD运行时 > sqlcmd -i MyScript.sql Line 3 Line 6 Msg 208,Level 16,State 1,Server MyServer,Line 2 Invalid object name 'NonExistingTable'. 当您在启用了SQLCMD模式的SQL Server Management Studio中运行时,您可以获得 Line 3 Line 6 Msg 208,Line 2 Invalid object name 'NonExistingTable'. ** An error was encountered during execution of batch. Exiting. 但是当您双击错误行时,查询编辑器将跳转到有问题的行. 报告行2表示相对于批次的行号.批量由GO语句分隔.我们想要得到一个真正的第9行答案. 我也尝试过PowerShell的Invoke-Sqlcmd,但更糟糕的是,因为它根本没有检测到这样的错误(Error detection from Powershell Invoke-Sqlcmd not always working?). 有没有一个简单的方法来包装我们的sql脚本与一些帮助来获得所需的真正的错误行? UPD:我已经更改了错误脚本,以确保它会失败确定… 解决方法这是我想出的解决方案: https://github.com/mnaoumov/Invoke-SqlcmdEx现在 > .Invoke-SqlcmdEx.ps1 -InputFile .MyScript.sql Line 3 Line 6 Msg 208,Script .MyScript.ps1,Line 9 Invalid object name 'NonExistingTable'. sqlcmd failed for script .MyScript.ps1 with exit code 1 At C:DevInvoke-SqlcmdExInvoke-SqlcmdEx.ps1:77 char:18 + throw <<<< "sqlcmd failed for script $InputFile with exit code $LASTEXITCODE" + CategoryInfo : OperationStopped: (sqlcmd failed f...ith exit code 1:String) [],RuntimeException + FullyQualifiedErrorId : sqlcmd failed for script .MyScript.ps1 with exit code 1 它有一个正确的第9行输出 以防万一我也在这里列出了脚本.该脚本可能看起来像一个过分的,但它是这样写的,以便完全支持所有SQLCMD脚本功能并正确处理事务 调用-SqlcmdEx.ps1 #requires -version 2.0 [CmdletBinding()] param ( [string] $ServerInstance = ".",[string] $Database = "master",[string] $User,[string] $Password,[Parameter(Mandatory = $true)] [string] $InputFile ) $script:ErrorActionPreference = "Stop" Set-StrictMode -Version Latest function PSScriptRoot { $MyInvocation.ScriptName | Split-Path } trap { throw $Error[0] } function Main { if (-not (Get-Command -Name sqlcmd.exe -ErrorAction SilentlyContinue)) { throw "sqlcmd.exe not found" } $scriptLines = Get-Content -Path $InputFile $extendedLines = @() $offset = 0 foreach ($line in $scriptLines) { $offset++ if ($line -match "^s*GOs*$") { $extendedLines += ` @( "GO","PRINT '~~~ Invoke-SqlcmdEx Helper - Offset $offset'" ) } $extendedLines += $line } $tempFile = [System.IO.Path]::GetTempFileName() try { $extendedLines > $tempFile $sqlCmdArguments = Get-SqlCmdArguments $ErrorActionPreference = "Continue" $result = sqlcmd.exe $sqlCmdArguments -i $tempFile 2>&1 $ErrorActionPreference = "Stop" $offset = 0 $result | ForEach-Object -Process ` { $line = "$_" if ($line -match "~~~ Invoke-SqlcmdEx Helper - Offset (?<Offset>d+)") { $offset = [int] $Matches.Offset } elseif (($_ -is [System.Management.Automation.ErrorRecord]) -and ($line -match "Line (?<ErrorLine>d+)$")) { $errorLine = [int] $Matches.ErrorLine $realErrorLine = $offset + $errorLine $line -replace "Line d+$","Script $InputFile,Line $realErrorLine" } else { $line } } if ($LASTEXITCODE -ne 0) { throw "sqlcmd failed for script $InputFile with exit code $LASTEXITCODE" } } finally { Remove-Item -Path $tempFile -ErrorAction SilentlyContinue } } function Get-SqlCmdArguments { $sqlCmdArguments = ` @( "-S",$ServerInstance,"-d",$Database,"-b","-r",0 ) if ($User) { $sqlCmdArguments += ` @( "-U",$User,"-P",$Password ) } else { $sqlCmdArguments += "-E" } $sqlCmdArguments } Main UPD:@MartinSmith提供了一个整洁的想法,使用LINENO aproach. 这是使用这种方法的版本:https://github.com/mnaoumov/Invoke-SqlcmdEx/blob/LINENO/Invoke-SqlcmdEx.ps1它在每个GO语句之后基本上插入LINENO [对应行号]. 但是,如果我们考虑以下脚本 IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('dbo.MyFunction') AND type = 'FN') EXEC sp_executesql N'CREATE FUNCTION dbo.MyFunction() RETURNS int AS BEGIN RETURN 0 END' GO LINENO 3 ALTER FUNCTION dbo.MyFunction() RETURNS int AS BEGIN RETURN 42 END GO 它会失败 > sqlcmd -i MyScript.sql Msg 111,Level 15,Line 5 'ALTER FUNCTION' must be the first statement in a query batch. Msg 178,Line 9 A RETURN statement with a return value cannot be used in this context. 因此,LINENO方法对于在查询批次中必须是第一个的语句将不起作用.以下是此类语句的列表:http://msdn.microsoft.com/en-us/library/ms175502.aspx:CREATE DEFAULT,CREATE FUNCTION,CREATE PROCEDURE,CREATE RULE,CREATE SCHEMA,CREATE TRIGGER和CREATE VIEW.没有提到ALTER语句,但我认为规则也适用于它们 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |