在批处理文件中使用SQLCMD,如何解析响应并检查错误?

时间:2015-04-09 21:15:17

标签: sql-server batch-file sqlcmd

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

我使用的sqlcmd看起来像这样:

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

如果有效,它将返回:

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

(1 rows affected)

(注意,-------上面有一个空白行,列名I我没有指定。)

如果我传入的表格不存在,我会收到以下回复:

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,如果没有错误则存储计数,如果有错误则打印两行?

2 个答案:

答案 0 :(得分:5)

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

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

所以/b选项对你没什么好处,可以放弃。

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

您可以通过在命令前添加(1 rows affected)

来取消set nocount on;消息

您可以添加-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!

答案 1 :(得分:1)

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

您应该能够在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开关,因为它现在可以设置为单词。