【问题标题】:TSQL statement in OSQL fails when called from a batch file called from a batch file从批处理文件调用的批处理文件调用 OSQL 中的 TSQL 语句失败
【发布时间】:2013-06-26 16:08:15
【问题描述】:

我正在通过一个批处理文件自动化各种 EXE,包括调用一个现有的批处理文件,该批处理文件又通过 OSQL.exe 执行各种 TSQL 语句。

现有的批处理文件工作正常。但是,当我的批处理文件调用时,对 osql.exe 的调用失败,导致批处理文件自行退出。

:check_user_privs

%OSQLPATH% %CONNECTSTRING% -S "%SERVER_INSTANCE%" -d "%DBNAME%" -Q "DECLARE @userName varchar(100) ; set @userName = user_name() ; IF IS_SRVROLEMEMBER ('sysadmin') != 1 RAISERROR ('This user ''%s'' is not a member of the ''sysadmin'' group.' , 16 , 127 , @userName )"  > /nul
if errorlevel 1 (
    echo ** ERROR - The user is NOT a sysadmin member on "%SERVER_INSTANCE%" - Exiting ** 1
    echo.
    pause
    exit
)

可以说,错误发生了。启用 ECHO 后,第一行变为:

"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\OSQL.EXE" -U"ADMIN" -P"PASSWORD" -S "SQL_SRVR10" -d "DB01" -Q "DECLARE @userName varchar(100) ; set @userName = user_name() ; IF IS_SRVROLEMEMBER ('sysadmin') != 1 RAISERROR ('This user ''ADMIN'' is not a member of the ''sysadmin'' group.' , 16 , 127 , @userName )"  > /nul

当我直接从命令行或我自己的批处理文件调用脚本时,这一行是相同的。

我已经手动捕获了在从我的批处理文件中调用此批处理文件时设置的环境变量。然后我在命令行手动设置它们,然后手动运行批处理文件。没有复制。

我将 TSQL 语句更改为简单地输出函数 IS_SRVROLEMEMBER() 的返回值。从我的脚本和命令行调用,输出都是相同的 - “1”:

"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\OSQL.EXE" -U"ADMIN" -P"PASSWORD" -S "SQL_SRVR10" -d "DB01" -Q "SELECT IS_SRVROLEMEMBER ('sysadmin')"

【问题讨论】:

    标签: sql-server-2008 tsql batch-file osql


    【解决方案1】:

    好吧,我在这上面花了一些时间,我注意到如果我使用 CMD.EXE /C 或 START /B /WAIT 调用其他脚本,则不会出现错误。所以这肯定是导致问题的 CMD.EXE 进程的状态。

    另外,我决定将每一行 ECHO 到一个文本文件中。我注意到有一个细微的差别:

    ECHO "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\OSQL.EXE" -U"ADMIN" -P"PASSWORD" -S "SQL_SRVR10" -d "DB01" -Q "DECLARE @userName varchar(100) ; set @userName = user_name() ; IF IS_SRVROLEMEMBER ('sysadmin') != 1 RAISERROR ('This user ''ADMIN'' is not a member of the ''sysadmin'' group.' , 16 , 127 , @userName )"  > out.txt
    

    当你查看 out.txt 时,它包含:

    "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\OSQL.EXE" -U"ADMIN" -P"PASSWORD" -S "SQL_SRVR10" -d "DB01" -Q "DECLARE @userName varchar(100) ; set @userName = user_name() ; IF IS_SRVROLEMEMBER ('sysadmin') = 1 RAISERROR ('This user ''ADMIN'' is not a member of the ''sysadmin'' group.' , 16 , 127 , @userName )"
    

    不同之处在于感叹号 (!) 消失了。这解释了为什么比较总是评估为假,因为比较与您期望的完全相反。

    我最终发现,由于之前执行了 SETLOCAL ENABLEDELAYEDEXPANSION,调用此脚本的 CMD.EXE 当前处于延迟的环境变量扩展模式。当 CMD.EXE 处理该行时,!字符标记扩展的开始,因此它会自动将其剥离。但是,下一个字符是等号字符 (=),这在环境变量中是不允许的,因此处理会立即取消变量扩展,转而处理该字符。所以只有 = 字符被设置为 OSQL.EXE 的参数。

    正确的解决方案是在调用脚本之前立即执行 SETLOCAL DISABLEDELAYEDEXPANSION,然后执行 ENDLOCAL。

    【讨论】:

    • 我认为您对delayed expansion 的看法是正确的。由于副作用,不使用它总是一个好主意,我这样做了。
    • 但它如此很有用! :-)
    【解决方案2】:

    此外,在运行 osql/sqlcmd 的批处理中使用“LIKE '%mytext%'”可能会遇到语法问题,因为您需要加倍处理那些讨厌的百分号! 但是,当您在命令提示符下测试它时,它当然可以正常工作。 今天早些时候我花了大约一个小时试图调试 那个。 为什么我没有立即看到并理解这个问题? 不幸的是,我的记忆力越来越像我妈妈的每一天……痴呆症在家庭中蔓延;-(

    【讨论】:

      【解决方案3】:

      我会将EXIT 更改为EXIT /B

      EXIT 终止 CMD 会话。

      exit /b optionalerrorlevelnumber 终止当前批处理,可选择返回错误级别。

      【讨论】:

      • 彼得 - 你是对的。当错误发生时,它会降低整个过程。烦人的是,这是一个我无法直接控制的脚本。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 1970-01-01
      • 2014-06-14
      • 1970-01-01
      • 2015-06-21
      • 1970-01-01
      相关资源
      最近更新 更多