Почему результат вызова sqlcmd из моего командного файла ненадежен? - PullRequest
0 голосов
/ 26 февраля 2020

Ниже test.bat, который я ожидаю, чтобы вывести количество указанных c имен базы данных test в экземпляре.

SET DB_SERVER_NAME=localhost
SET DB_DB_NAME=test
SET DB_SYSADMIN_LOGIN_NAME=sa
SET DB_SYSADMIN_LOGIN_PWD=test_sysad_pwd
for /F %%A in ('sqlcmd -S %DB_SERVER_NAME% -U %DB_SYSADMIN_LOGIN_NAME% -P %DB_SYSADMIN_LOGIN_PWD% -b -Q "set nocount on;SELECT COUNT(NAME) FROM SYS.DATABASES WHERE NAME = '%DB_DB_NAME%'"') do set DBCNT=%%A
ECHO %DBCNT%  >> %~dp0\test.log 2>&1

%DBCNT% иногда 1 или 0 в test.log, что я ожидаю, но иногда %DBCNT% не содержит числа.

Что не так?


Джеб и Мофи. Большое спасибо. Но текущая ситуация более запутанная.

Ниже приведен результат sqlcmd, напрямую вызываемый из командной строки.

 "sqlcmd.exe" -S "{servername}" -U "sa" -P "{pwd}" -b -Q "set nocount on;SELECT COUNT(NAME) FROM SYS.DATABASES WHERE NAME = 'testdb'"

-----------
          1

Ниже приведены вопросы, на которые указывает моя программа. Я сомневаюсь, что путь sqlcmd можно указать в среде клиента. Я думаю, что sqlcmd.exe иногда находится вне папки Windows.

A) Переменная должна быть инициализирована. Б) Используйте синтаксис «usebackq», когда команда содержит «». C)% ~ dp0 заканчивается backsla sh. (Не полагайтесь на исправление ядра.) D) Echo никогда не пишет что-то для обработки STDERR (стандартная ошибка). Используйте перенаправление непосредственно в файл журнала.

Ниже приведен пример программы:

REM /****************************************************************************/
SET DB_SERVER_NAME={servername}
SET DB_DB_NAME=testdb
SET DB_SYSADMIN_LOGIN_NAME=sa
SET DB_SYSADMIN_LOGIN_PWD={pwd}

REM /****************************************************************************/

chcp 437

REM original command
for /F %%A in ('sqlcmd -S %DB_SERVER_NAME% -U %DB_SYSADMIN_LOGIN_NAME% -P %DB_SYSADMIN_LOGIN_PWD% -b -Q "set nocount on;SELECT COUNT(NAME) FROM SYS.DATABASES WHERE NAME = '%DB_DB_NAME%'"') do set DBCNT=%%A
>>"%~dp0test.log" echo(#A#%DBCNT%

REM only use usebackq
SET DBCNT=0
for /F "usebackq" %%I in (`'sqlcmd -S %DB_SERVER_NAME% -U %DB_SYSADMIN_LOGIN_NAME% -P %DB_SYSADMIN_LOGIN_PWD% -b -Q "set nocount on;SELECT COUNT(NAME) FROM SYS.DATABASES WHERE NAME = '%DB_DB_NAME%'"'`) do set DBCNT=%%I
>>"%~dp0test.log" echo(#B#%DBCNT%

REM using remove single quotes several double quotes with absolute path sqlcmd
SET DBCNT=0
(for /F "usebackq" %%I in (`"C:\Program Files\Microsoft SQL Server\110\Tools\Binn\sqlcmd.exe" -S "%DB_SERVER_NAME%" -U "%DB_SYSADMIN_LOGIN_NAME%" -P "%DB_SYSADMIN_LOGIN_PWD%" -b -Q "set nocount on;SELECT COUNT(NAME) FROM SYS.DATABASES WHERE NAME = '%DB_DB_NAME%'"`) do set DBCNT=%%I) 2>>"%~dp0test.log"
>>"%~dp0test.log" echo(#C#%DBCNT%

REM using remove single quotes several double quotes, removing double quotes
SET DBCNT=0
(for /F "usebackq" %%I in (`'sqlcmd.exe -S "%DB_SERVER_NAME%" -U "%DB_SYSADMIN_LOGIN_NAME%" -P "%DB_SYSADMIN_LOGIN_PWD%" -b -Q "set nocount on;SELECT COUNT(NAME) FROM SYS.DATABASES WHERE NAME = '%DB_DB_NAME%'"'`) do set DBCNT=%%I) 2>>"%~dp0test.log"
>>"%~dp0test.log" echo(#D#%DBCNT%

REM using remove single quotes several double quotes
SET DBCNT=0
(for /F "usebackq" %%I in (`sqlcmd.exe -S "%DB_SERVER_NAME%" -U "%DB_SYSADMIN_LOGIN_NAME%" -P "%DB_SYSADMIN_LOGIN_PWD%" -b -Q "set nocount on;SELECT COUNT(NAME) FROM SYS.DATABASES WHERE NAME = '%DB_DB_NAME%'`) do set DBCNT=%%I) 2>>"%~dp0test.log"
>>"%~dp0test.log" echo(#E#%DBCNT%

Ниже приведен результат:

#A#1
#B#0
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
#C#0
#D#0

1 Ответ

1 голос
/ 01 марта 2020

Спасибо, Мофи, я получил то, что ожидал.

REM /****************************************************************************/
SET DB_SERVER_NAME={servername}
SET DB_DB_NAME=testdb
SET DB_SYSADMIN_LOGIN_NAME=sa
SET DB_SYSADMIN_LOGIN_PWD={pwd}

REM /****************************************************************************/


chcp 437
set DBCNT=0

REM duplicate double quote for ComSpec
(for /F "usebackq" %%I in (`""%ProgramFiles%\Microsoft SQL Server\110\Tools\Binn\sqlcmd.exe" -S "%DB_SERVER_NAME%" -U "%DB_SYSADMIN_LOGIN_NAME%" -P "%DB_SYSADMIN_LOGIN_PWD%" -b -Q "set nocount on^;SELECT COUNT(NAME^) FROM SYS.DATABASES WHERE NAME ^= '%DB_DB_NAME%'""`) do set DBCNT=%%I)

>>"%~dp0test.log" echo(#E#%DBCNT%

set DBCNT=0

REM without absolute pass to sqlcmd
(for /F "usebackq" %%I in (`""sqlcmd.exe" -S "%DB_SERVER_NAME%" -U "%DB_SYSADMIN_LOGIN_NAME%" -P "%DB_SYSADMIN_LOGIN_PWD%" -b -Q "set nocount on^;SELECT COUNT(NAME^) FROM SYS.DATABASES WHERE NAME ^= '%DB_DB_NAME%'""`) do set DBCNT=%%I)

>>"%~dp0test.log" echo(#F#%DBCNT%

pause

Результат test.log ниже.

#E#1
#F#1
...