Loop over SQLCMD results on batch file - sql-server

I'm using the folling .cmd to get the values returned by one sql sentence.
#echo off
SET SERVER=.\SQLExpress
SET SQLCMD="C:\Program Files\Microsoft SQL Server\110\Tools\Binn\sqlcmd.exe"
for %%f in (%SQLCMD%) do set alternatepath=%%~sf
SET EXEC_LINE=%alternatepath% -S %SERVER% -d SkpMaster -h-1 -Q "set nocount on; select distinct id from sometable "
for /F "usebackq delims=" %%i in (`%EXEC_LINE%`) do (
set count=%%i
echo %count%
)
if not defined count (
echo Failed to execute SQL statement 1>&2
)
The SQL return 4 occurrences, but the echo print 4 times the 1ยบ ocurrence.
Maybe I'm not using correctly the "delims=" option, I have also tested with "tokens=*" with the same result.
Any idea?

Fixed after handle the parameter %%i in a different way.
#echo off
SET SERVER=.\SQLExpress
SET SQLCMD="C:\Program Files\Microsoft SQL Server\110\Tools\Binn\sqlcmd.exe"
for %%f in (%SQLCMD%) do set alternatepath=%%~sf
SET EXEC_LINE=%alternatepath% -S %SERVER% -d SkpMaster -h-1 -Q "set nocount on; select distinct id from sometable "
for /F "usebackq delims=" %%i in (`%EXEC_LINE%`) do call :processline %%i
if not defined count (
echo Failed to execute SQL statement 1>&2
)
pause
goto :eof
:processline
echo line=%*
goto :eof
:eof

Related

Could not open a connection to SQL server with batch file

i'm getting this error while trying to run some sql query via a batch file.
The program works fine on its own, i think the problem is due to the fact that now i created a batch file that picks variables and commands from 2 separate files and the %istance% variable does not get recognised.
The code looks something like this:
set i=0
for /f "delims=" %%c in ('findstr /v /c:"::" var.txt') do (
set /a i+=1
set "var[!i!]=%%c"
)
set "hostname=%var[1]%"
set "istance=%var[2]%"
set "folder=%var[3]%"
set "program=%var[4]%"
set "printer=%var[5]%"
set "activation=%var[6]%"
set "customer=%var[7]%"
set i=0
for /f "delims=" %%c in ('findstr /v /c:"::" command.txt') do (
set /a i+=1
set "command[!i!]=%%c"
)
for /l %%L in (1 1 7) do (
set "command=!command[%%L]!"
!command!
)
goto :eof
the second line in the var.txt file is the SQL istance (MYPC\SQLEXPRESS) and this is an example of a command:
sqlcmd -Q "ALTER DATABASE MYDB SET MULTI_USER" -S %istance% -d master -U user -P pwd
As i said if i set the istance directly on the batch it seems to work fine.
Any advice?

parallel processing in bat file for loop

I want a batch file to do parallel processing. I have a storedprocedure which returns 1000+ records(has unique rowid column along with other info). Iterating though each row works fine. However, it takes long time to complete 1000 loops. Is there a way to run two loops parallel without overlapping or having to maintain separate batch files. Can this be accomplished by having one .bat file.
WORKING CODE:
#echo off
setlocal EnableExtensions
set ListFile=%TEMP%\StudentList.tmp
Set varServerPath=http://xyz/ReportServer
sqlcmd -Q "exec dbo.Storedproc_StudentList" -S ServerName -d DatabaseName >"%ListFile%" 2>nul
if exist "%ListFile%" (
for /F "usebackq tokens=1,2,3,4 skip=2 delims=', " %%A in ("%ListFile%") do (
echo Processing StudentID %%A and SubjectID %%B ...
if not exist "%%D" mkdir "%%D"
rs -i C:\ReportRender\Student.rss -s%varServerPath% -e Exec2005 -v StudentID="%%A" -v SubjectID="%%B" -v vOutputFilePath="%%C" -v vReportPath="/Student Reports/ReportName.rdl" -l 900
)
del "%ListFile%"
)
exit
I tried doing something like having two for loops one from 1 to 200 and other from 201 to 400 and so on....but seems like i'm on the wrong track. It doesn't work, Please suggest.
#echo off
setlocal EnableExtensions
set ListFile=%TEMP%\StudentList.tmp
Set varServerPath=http://xyz/ReportServer
sqlcmd -Q "exec dbo.Storedproc_StudentList" -S ServerName -d DatabaseName >"%ListFile%" 2>nul
if exist "%ListFile%" (
for /F "usebackq tokens=1,2,3,4 skip=2 delims=', " %%A in ("%ListFile%") do (
for /L %%A in(1,1,200) do (
echo Processing StudentID %%A and SubjectID %%B ...
if not exist "%%D" mkdir "%%D"
rs -i C:\ReportRender\Student.rss -s%varServerPath% -e Exec2005 -v StudentID="%%A" -v SubjectID="%%B" -v vOutputFilePath="%%C" -v vReportPath="/Student Reports/ReportName.rdl" -l 900
)
for /L %%A in(201,1,400) do (
echo Processing StudentID %%A and SubjectID %%B ...
if not exist "%%D" mkdir "%%D"
rs -i C:\ReportRender\Student.rss -s%varServerPath% -e Exec2005 -v StudentID="%%A" -v SubjectID="%%B" -v vOutputFilePath="%%C" -v vReportPath="/Student Reports/ReportName.rdl" -l 900
)
)
del "%ListFile%"
)
exit
Thanks,
Your approach is wrong. You are executing a for /L %%A in (1,1,200) ... and a for /L %%A in (201,1,400) ... for each record in the %ListFile%. You need to distribute the records in the %ListFile% into the two parallel processes. Although this can be done in groups of 200 records, it is much simpler to do that one-by-one. Also, the only way to have parallel processes in a Batch file is via start command or using a | pipe. In this case you want to distribute several input records that will be read (and processed) by two "output processes", so the pipe approach is simpler.
#echo off
setlocal EnableDelayedExpansion
if "%1" neq "" goto %1
set ListFile=%TEMP%\StudentList.tmp
Set varServerPath=http://xyz/ReportServer
sqlcmd -Q "exec dbo.Storedproc_StudentList" -S ServerName -d DatabaseName >"%ListFile%" 2>nul
if not exist "%ListFile%" exit
set numProcs=2
( "%~F0" Input | "%~F0" Output ) 2>&1 | "%~F0" Output
del "%ListFile%"
exit
:Input
set i=0
for /F "usebackq tokens=1,2,3,4 skip=2 delims=', " %%A in ("%ListFile%") do (
set /A i+=1, proc=i%%numProcs
if !proc! equ 1 (
echo %%A %%B %%C %%D
) else (
>&2 echo %%A %%B %%C %%D
)
)
exit /B
:Output
for /F "tokens=1-4" %%A in ('findstr "^"') do (
echo Processing StudentID %%A and SubjectID %%B ...
if not exist "%%D" mkdir "%%D"
rs -i C:\ReportRender\Student.rss -s%varServerPath% -e Exec2005 -v StudentID="%%A" -v SubjectID="%%B" -v vOutputFilePath="%%C" -v vReportPath="/Student Reports/ReportName.rdl" -l 900
)
exit /B
The :Input part just distribute the "%ListFile%" records to Stdout (channel 1) and Stderr (channel 2), one by one.
The :Output part just take the %%A %%B %%C %%D values sent by :Input part and process they in the usual way; the input data is read from Stdin via findstr command.
The :Input and :Output parts could be in separate Batch files, but they are included in the same file and selected via a parameter and the if "%1" neq "" goto %1 command placed at beginning.
The most interesting code is the pipeline that run the 3 processes in parallel. The :Input part run and its Stdout output is feed into the first :Output process. The Stderr output (channel 2) of :Input part is redirected into Stdin via the 2>&1, so this output is feed into the second :Output process.
This method may also be used for more than two output parallel processes; you just need to add more similar parts changing the number 2 for 3, etc. For example, with three output processes the pipeline should be this one:
( ( "%~F0" Input | "%~F0" Output ) 2>&1 | "%~F0" Output ) 3>&1 | "%~F0" Output
However, it is very important that you note that this method does NOT necessarily imply that the whole process will run faster! This point depends on several factors, like the number of CPU cores and the speed/buffers of the disk drive. Just a test can answer this question...
Post the result, please.

Batch Script How to Set Variabes into another variable

i asked a question but it was not fully Explained so that is my Question.
i got settings.ini inside it There is sections with variables
[HideAndSeekEvent]
EventRunning=[Hide And Seek Event] Has started at [ %placenameHS% ].
and got another batch file called ini.bat
#setlocal enableextensions enabledelayedexpansion
#echo off
set file=%~1
set area=[%~2]
set key=%~3
set currarea=
for /f "usebackq delims=" %%a in ("!file!") do (
set ln=%%a
if "x!ln:~0,1!"=="x[" (
set currarea=!ln!
) else (
for /f "tokens=1,2 delims==" %%b in ("!ln!") do (
set currkey=%%b
set currval=%%c
if "x!area!"=="x!currarea!" if "x!key!"=="x!currkey!" (
echo !currval!
)
)
)
)
endlocal
and another bat file called Getdata.bat to call variables from .ini file and for this section there is
for /f "delims=" %%a in ('call ini.cmd settings.ini HideAndSeekEvent EventRunning') do (
set EventRunningeHS=%%a
)
in my main .bat file iam calling the Getdata.bat file
in my main .bat i got some thing like this
SET placenameHS=Hotan
echo %EventRunningeHS%
it should show
[Hide And Seek Event] Has started at [ Hotan ].
But it show :
[Hide And Seek Event] Has started at [ %placenameHS% ].
[NOTICE] i do not SET The Place name i got it by SQLCMD Query
osql -S %Server% -U %SQLUser% -P %SQLPass% -d Dother_Events -Q "SET NOCOUNT ON; SELECT Place_Name FROM _HideANDSeek_Map WHERE ID = %IDHS%" %osqluser% -b -w 9999 -h-1 -o .\Logs_in_use\HSLN7.txt
set /p HSLN7=<.\Logs_in_use\HSLN7.txt
I tested the code and data you posted, and the proposed solution. These are the files I used in the test.
settings.ini:
[HideAndSeekEvent]
EventRunning=[Hide And Seek Event] Has started at [ %placenameHS% ].
ini.cmd:
#setlocal enableextensions enabledelayedexpansion
#echo off
set file=%~1
set area=[%~2]
set key=%~3
set currarea=
for /f "usebackq delims=" %%a in ("!file!") do (
set ln=%%a
if "x!ln:~0,1!"=="x[" (
set currarea=!ln!
) else (
for /f "tokens=1,2 delims==" %%b in ("!ln!") do (
set currkey=%%b
set currval=%%c
if "x!area!"=="x!currarea!" if "x!key!"=="x!currkey!" (
echo !currval!
)
)
)
)
endlocal
Getdata.bat:
#echo off
for /f "delims=" %%a in ('call ini.cmd settings.ini HideAndSeekEvent EventRunning') do (
set EventRunningeHS=%%a
)
main.bat:
#echo off
call Getdata.bat
SET placenameHS=Hotan
echo Original output:
echo %EventRunningeHS%
echo Proposed solution:
call echo %EventRunningeHS%
This is the output when I run main.bat:
Original output:
[Hide And Seek Event] Has started at [ %placenameHS% ].
Proposed solution:
[Hide And Seek Event] Has started at [ Hotan ].

batch script - comparing two arrays

I am trying to compare two arrays and if any array element is same then I am printing. I am not getting the proper output. Only one element is displaying (rm.war). See the below batch file and the output.
Code:
#echo off
setlocal EnableDelayedExpansion
echo "Application list"
set all_apps=(jts.war rm.war ccm.war dm.war relm.war qm.war)
set apps_len=0
for %%b in %all_apps% do (
set /A apps_len=apps_len+1
set apps[!apps_len!]=%%b
echo %%b
)
echo "Installed Applications"
cd /d D:\IBM\WebSphere\AppServer\profiles\AppSrv01\bin
set cmd=call wsadmin.bat -lang jython -f C:/temp/tt.py -user wsadmin -password wsadmin
set insapps_len=0
for /f %%a in ('%cmd%') do (
set /A insapps_len=insapps_len+1
set inslist[!insapps_len!]=%%a
echo %%a
)
echo "Compare arrays"
for /l %%i in (1,+1,%apps_len%) do (
for /l %%j in (%insapps_len%,-1,1) do (
if !apps[%%i]!==!inslist[%%j]! echo !inslist[%%j]!
)
)
Output:
"Application list"
jts.war
rm.war
ccm.war
dm.war
relm.war
qm.war
"Installed Applications"
WASX7209I:
DefaultApplication
admin.war
ccm.war
clmhelp.war
converter.war
ivtApp
jts.war
qm.war
query
rm.war
"Compare arrays"
rm.war
Test this to see if it functions:
#echo off
set all_apps="jts.war" "rm.war" "ccm.war" "dm.war" "relm.war" "qm.war"
set "installed="
cd /d "D:\IBM\WebSphere\AppServer\profiles\AppSrv01\bin"
set cmd=call wsadmin.bat -lang jython -f C:/temp/tt.py -user wsadmin -password wsadmin
for /f %%a in ('%cmd%') do call set installed="%%a" %%installed%%
echo duplicates:
for %%a in (%all_apps%) do (
for %%b in (%installed%) do (
if "%%~a"=="%%~b" echo %%~a
)
)
pause

Set a return value as variable in window batch

How can I use if else statement to echo if value more than 1?
#echo off
setlocal
set "sql=c:\xampp\mysql\bin\mysql.exe"
for /f "usebackq" %%a in (`%sql% -u root -ss -e "select COUNT(*) FROM mytable" mydatabase`) do set TESTVAR=%%a
if %TESTVAR% GEQ 1 (echo Database has already existed.) else echo import
pause
Kind of like this:
#echo off
setlocal
set "sql=c:\xampp\mysql\bin\mysql.exe"
for /f "usebackq" %%a in (`%sql% -u root -ss -e "select COUNT^(*^) FROM browser" form_generator`) do set TESTVAR=%%a
if %TESTVAR% LSS 1 echo whatever
pause

Resources