【问题标题】:Using SQLCMD in a batch file, how can I parse the response and check for an error?在批处理文件中使用 SQLCMD,如何解析响应并检查错误?
【发布时间】:2015-04-09 21:15:17
【问题描述】:

我正在使用 SQLCMD 来获取表中的行数,但我也想知道查询是否遇到错误。

我正在使用的 sqlcmd 如下所示:

sqlcmd -S %server% -U %user% -P %pass% -b -Q "select count(*) from %table%"

如果有效,它将返回:

-----------
      10205

(1 rows affected)

(请注意,我没有指定的列名--------上方有一个空行。)

如果我传入一个不存在的表,我会得到以下响应:

Msg 208, Level 16, State 1, Server devServer, Line 1
Invalid object name 'dbo.no_table'.

由于我有 -b 标志,我可以检查 ERRORLEVEL 的值(在本例中为 1)。

为了存储计数变量,我一直在使用以下行:

for /F %%i in ('sqlcmd -S %server% -U %user% -P %pass% -b -Q "select count(*) from %table%" ^| findstr /r "[^(][0-9]"') do SET /a rec_count=%%i

在for之后,%errorlevel%返回0。即使在do里面,errorlevel也是0。

有什么简单的方法可以运行sqlcmd,如果没有错误则存储计数,如果有错误则打印两行?

【问题讨论】:

  • 如果这是一个新项目,我完全同意。不幸的是,我只是想为现有的批处理文件添加一个计数。
  • 我假设您是说 errorlevel 没有被更改 - 即使表格无效?
  • 是的,没错。如果在 for 循环中运行,Errorlevel 不变,但如果在 for 之外运行,则它会更改。

标签: sql-server batch-file sqlcmd


【解决方案1】:

由 FOR /F 执行的命令通过新的 CMD 会话隐式执行。比如for /f %a in ('echo hello') do ...,执行的命令就变成C:\Windows\system32\cmd.exe /c echo hello。

您的命令正确设置了 ERRORLEVEL,但是一旦子 CMD 会话终止并且控制权返回到您的批处理脚本,该值就会丢失。

所以/b 选项对你没有任何好处,可以放弃。

您可以通过添加-h -1 选项来隐藏标题信息。

您可以通过在命令前加上set nocount on; 来抑制(1 rows affected) 消息

您可以添加-r 1 选项以使错误消息出现在stderr 而不是stdout 上。这将阻止 FOR /F 处理任何错误,而错误消息将出现在屏幕上。

您可以在执行命令之前清除 rec_count 变量。如果有错误,它将保持未定义,否则如果没有错误,它将包含计数。

set "rec_count="
for /f %%A in (
  'sqlcmd -S %server% -U %user% -P %pass% -h -1 -r 1 -Q "set nocount on;select count(*) from %table%"'
) do set "rec_count=%%A"
if not defined rec_count echo There was an error!

您可能会考虑的另一件事是将 SQLCMD 识别的环境变量用于您的服务器、用户名和密码。这样您就不必使用 -S、-U 或 -P 选项。如果您的批处理脚本运行许多 SQLCMD 命令,这将特别方便。

set "sqlcmdServer=YourServer"
set "sqlcmdUser=YourUserName"
set "sqlcmdPassword=YourPassword"

set "rec_count="
for /f %%A in (
  'sqlcmd -h -1 -r 1 -Q "set nocount on;select count(*) from %table%"'
) do set "rec_count=%%A"
if not defined rec_count echo There was an error!

【讨论】:

    【解决方案2】:

    errorlevel 似乎没有被设置的原因是因为for 命令正在成功执行,无论它循环执行的代码如何执行。因此,您只能与同一行(在 for 循环括号内)的 sqlcmd 命令设置的错误级别进行交互。

    您应该能够在 sqlcmd 命令之后使用||(双管道)。 || 之后的任何代码只有在前一个命令失败时才会运行。示例:

    notACommand || echo test
    

    将返回“test”。而以下将仅输出“a command”:

    echo a command || echo test
    

    我无法对其进行测试,但以下内容应该适合您:

    for /F "EOL=(" %%i in ('sqlcmd -S %server% -U %user% -P %pass% -b -Q "select count(*) from %table%" ^|^| echo fail') do (
        SET rec_count=%%i
    )
    if "%rec_count%"=="fail" echo SQL command failed
    

    如果输出与您所说的完全一样,那么您不需要 findstr 命令 - 只需在 for 循环中将 ( 左括号设置为 EOL 字符,这样您就可以有效地删除“(1 rows affected)”行。您可能希望以不同的方式使用变量,但这只是判断 sqlcmd 命令是否失败的一种方法。

    至于输出错误 - 一个不好的解决方案是再次运行相同的 sqlcmd 命令。类似于以下内容:

    set command=sqlcmd -S %server% -U %user% -P %pass% -b -Q "select count(*) from %table%"
    
    for /F "EOL=(" %%i in ('%command% ^|^| echo fail') do SET rec_count=%%i
    
    if "%rec_count%"=="fail" (%command%) else echo rec_count is %rec_count%
    

    请注意,我在设置 rec_count 变量时删除了 /a 开关,因为它现在可以设置为单词。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-24
      • 2018-12-18
      相关资源
      最近更新 更多