Streamlining a batch file calling a sql file - sql-server

We currently have a scheduler to run audits. This scheduler will call a batch file with a parameter, and the batch file calls a sql script (based on the parameter), which in turn calls a stored proc.
For each audit that runs, a separate batch file, and sql file. Best case I'd like to combine the two below files into 1 file that can be used for every new audit. Worst case I'd at least like to combine to get 1 file for each audit instead of two. Hopefully you all can help?
Batch File
#echo on
Echo Running SQL Command File for '%1' Data Audit Check
del "D:\Internal_Reports\%1\%1.txt"
sqlcmd -S localhost -d database -i "D:\DataAudit\%1.sql" -s "," > D:\Temp\%1.csv -I -W -k 1
if %ERRORLEVEL% GTR 0 COPY "D:\Temp\%1.csv" "D:\Internal_Reports\%1\%1.txt"
if %ERRORLEVEL% NEQ 0 goto Error_1
echo No Errors
goto end
:Error_1
if %ERRORLEVEL% NEQ 1 goto Error_2
echo No Errors
goto end
:Error_2
echo Errorlevel %ERRORLEVEL%
set FileName=%1%2
echo Filename %FileName%
echo %ERRORLEVEL% > D:\ErrorLevel\%FileName%
EXIT /B %ERRORLEVEL%
:end
SQL File
set NoCount on
DECLARE
#createdBy varchar(16),
#dataAuditBatchId int,
#createdDtTm datetime
select
#createdBy = 'AutomatedAudit'
exec CreateNewDataAuditBatch #createdBy, #dataAuditBatchId output
-- Content Scripts
exec specificAuditStoredProc #createdBy, #dataAuditBatchId
select * from vAuditErrors where JobName in ('specificAuditStoredProc')
:exit(select Case When Counter = 0 then 0 Else 1 End 'errorCode'
from (select CAST(Count(*) AS varchar(4)) AS Counter from vAuditErrors
where JobName in ('specificAuditStoredProc'))
CountTable
)

Your best bet would be PowerShell in this case. You can combine both worlds of Batch Scripting and direct access to SQL.
Copy the below code into a text file: Audit.ps1
Create a File called: AuditFile.txt, put your SpecificAuditProc names on each line.
Then in your batch scheduler run this: "powershell -command "& c:\Audit.ps1 -name 'ProcName'"
Heres the code [Untested]:
param([Parameter(Mandatory=$true)][String]$name="")
$createdBy = "AutomatedAudit"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=LOCALHOST;Database=HT;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandText = "[CreateNewDataAuditBatch]"
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure
$SqlCmd.Parameters.Add("#createdBy", $creadtedBy)
$SqlCmd.Parameters.Add("#dataAuditBatchId ")
$SqlCmd.Parameters["#dataAuditBatchId"].Direction = [system.Data.ParameterDirection]::Output
$SqlCmd.ExecuteNonQuery()
$dataAuditBatchId = $Command.Parameters["#dataAuditBatchId"].value
$SqlCmd.Dispose()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandText = "[$name]"
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure
$SqlCmd.Parameters.Add("#createdBy", $creadtedBy)
$SqlCmd.Parameters.Add("#dataAuditBatchId ", $dataAuditBatchId)
$SqlCmd.ExecuteNonQuery()
$SqlCmd.Dispose()
$sqlcheck = #(Invoke-Sqlcmd -Query "select * from vAuditErrors where JobName in ('$name')" -ServerInstance "LOCALHOST\HT")
if ($sqlcheck.Count -ne 0) {
$sqlcheck > D:\Internal_Reports\$name\$name.txt
$sqlcheck.Count >> D:\ErrorLevel\$name
}
$Connection.Close()
$Connection.Dispose()

This is a simple problem to solve in pure batch PROVIDED you clarify a few points.
What is "%1" here? The database name perhaps?
Do you have just one SQL file and if not, what elements in the sample you posted need to be replaced for different databases?
(sorry - this isn't really an answer per se, but I'll make some (i hope, useful) comments on your btch as posted. The SO comment facility really doesn't suit here...
#echo on
Echo Running SQL Command File for '%1' Data Audit Check
del "D:\Internal_Reports\%1\%1.txt"
sqlcmd -S localhost -d database -i "D:\DataAudit\%1.sql" -s "," > D:\Temp\%1.csv -I -W -k 1
OK: so in all probability, %1 id the database name. So - why -d database and not -d %1 ??
Why the > D:\... and not '-o D:...` ??
if %ERRORLEVEL% GTR 0 COPY "D:\Temp\%1.csv" "D:\Internal_Reports\%1\%1.txt"
Ack! The fail-to-fail scenario in all its glory! Most commonly, you'd get ERRORLEVEL 0 from the sqlcmd BUT COPY can change ERRORLEVEL. If the COPY succeeds, then ERRORLEVEL will be 0, but if COPY fails, ERRORLEVEL would be non-zero and that's the value that will be used by the steps following...
if %ERRORLEVEL% NEQ 0 goto Error_1
echo No Errors
goto end
:Error_1
if %ERRORLEVEL% NEQ 1 goto Error_2
echo No Errors
goto end
You could arrive at :error_2 by simply executing
if errorlevel 2 goto error2
directly after the SQLCMD is executed (means "If errorlevel is 2 OR GREATER")
:Error_2
echo Errorlevel %ERRORLEVEL%
set FileName=%1%2
echo Filename %FileName%
echo %ERRORLEVEL% > D:\ErrorLevel\%FileName%
EXIT /B %ERRORLEVEL%
:end
Suddenly an unexplained %2 appears...?

Related

Check with batch if the process is answering or not

:loop
>nul timeout /t 600 /nobreak
powershell -ExecutionPolicy Unrestricted -c "Get-Process -Name programm | Where-Object -FilterScript {$_.Responding -eq $false}"
if not errorlevel 1 goto loop
This is not working, I think the errorlevel is the problem, but I cant solve it.
I want to check if the process is answering or not. If not I want to check the process again after a timeout.
I thank you in advance for your help.
Read Errorlevel and Exit codes:
Almost all applications and utilities will set an Exit Code when
they complete/terminate. The exit codes that are set do vary, in
general a code of 0 (false) will indicate successful completion.
… When an external command is run by CMD.EXE, it will detect
the executable's Return or Exit Code and set the ERRORLEVEL to
match. In most cases the ERRORLEVEL will be the same as the Exit
code, but there are some cases where they can differ.
It's Exit Code for PowerShell as shown in the following examples:
Unsuccessful completion ( errorlevel 1 ):
==> powershell -noprofile -c "Get-Process -Name invalid_programm"
Get-Process : Cannot find a process with the name "invalid_programm". Verify the process name and call the cmdlet again.
At line:1 char:1
+ Get-Process -Name invalid_programm
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (invalid_programm:String) [Get-Process],ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
==> echo errorlevel=%errorlevel%
errorlevel=1
Successful completion ( errorlevel 0 )
==> powershell -noprofile -c "return 1"
1
==> echo errorlevel=%errorlevel%
errorlevel=0
Successful completion ( errorlevel set explicitly using the exit keyword)
==> powershell -noprofile -c "exit 2"
==> echo errorlevel=%errorlevel%
errorlevel=2
Hence, you could use the following code snippet (which should always successfully complete):
try {
$x = #(Get-Process -Name programm -ErrorAction Stop |
Where-Object -FilterScript {-not $_.Responding})
exit $x.Count
} catch {
exit 5000 # or other `absurd` value
}
Rewriting the above as an one-liner (using aliases), you could meet following scenarios:
A process with specified name not found
==> powershell -noprofile -c "try{$x=#(gps programm -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
==> echo errorlevel=%errorlevel%
errorlevel=5000
A process with specified name found & responding
==> powershell -noprofile -c "try{$x=#(gps cmd -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
==> echo errorlevel=%errorlevel%
errorlevel=0
One process with specified name found & NOT responding
==> powershell -noprofile -c "try{$x=#(gps HxOutlook -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
==> echo errorlevel=%errorlevel%
errorlevel=1
More processes with specified name found & NOT responding
==> powershell -noprofile -c "try{$x=#(gps -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
==> echo errorlevel=%errorlevel%
errorlevel=4
Please note incompleteness of above enumeration: we could imagine scenario where run more processes with specified name, some of them responding while other not-responding. (In other words, found & NOT responding does not imply that there does not exist another found & responding of the same name…)

How to add while loop in batch script to check status for given number of time attempts

I have a tabadmin refreshextract script which works fine but now we want to implement it from airflow, the only problem is if the session get re-connect then airflow gives error in log but eventually it success the refresh.
We added psql query to find once the refresh extract is done, it will pull the information whether it succeeds or fails.
tabcmd refreshextracts --url workbook_url -s https:// -t site -u tabadmin --password-file C:\Users\abc\Desktop\passwd.txt --no-certcheck
Pseudo code
cd c:\Program Files\PostgreSQL\11\bin
refresh_status='N'
retry_count = 0
while refresh_status = 'N' and retry_count < 20
retry_count++
refresh_status = $(psql -p 8060 -h servername -U readonly -d workgroup -c " select case when lower(notes) like '%finished%' == 'succeed' then 'Y' else 'N" as refresh_status from _background_tasks where Job_name = 'Refresh Extracts' and title = 'workbook_name' and created_at >=CURRENT_DATE ORDER BY created_at desc limit 1")
if refresh_status == 'Y'
EXIT Success
else
continue
continue
if refresh_status = 'N'
exit ERROR
this should work
#echo off
set attempts=0
:loop
set /a attempts+=1
if %attempts%==5 (echo %attempts%)
goto loop
or this
#echo off
set attempts=0
:loop
set /a attempts+=1
echo %attempts%
goto loop
these are examples btw.

Why errorlevel is still 0

I am trying to query each instance on my CMS. But why the errorlevel is still 0 when I tested the stopped instance? And how can I skip the last line in my Instance_list.txt (The %%a will be '(44')
:Start
REM get the full list of our instance from CMS to Instance_list.txt
"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\sqlcmd" -S cms_instance -e -d msdb -Q "SELECT DISTINCT server_name FROM sysmanagement_shared_registered_servers_internal" -o Instance_list.txt
:Run
REM Run query against all instances one by one.
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1,2 skip=3" %%a in (Instance_list.txt) do (
Set Intance_NAME=%%a
"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\sqlcmd" -S !Intance_NAME! -e -d master -Q "SELECT ##SERVERNAME" -o SQL_result.txt
TIMEOUT /T 2
FINDSTR "!Intance_NAME!" SQL_result.txt
IF %ERRORLEVEL% NEQ 0 (
ECHO SQL INSTANCE !Intance_NAME! HAS SOME ISSUE...
)
)
This is a SQLCMD FAQ. You need to set the -b switch for sqlcmd to set the ERRORLEVEL
-b Specifies that sqlcmd exits and returns a DOS ERRORLEVEL value when an error occurs. The value that is returned to the DOS ERRORLEVEL
variable is 1 when the SQL Server error message has a severity level
greater than 10; otherwise, the value returned is 0. If the -V option
has been set in addition to -b, sqlcmd will not report an error if the
severity level is lower than the values set using -V. Command prompt
batch files can test the value of ERRORLEVEL and handle the error
appropriately. sqlcmd does not report errors for severity level 10
(informational messages).
https://learn.microsoft.com/en-us/sql/tools/sqlcmd-utility?view=sql-server-2017

What am I doing wrong in this batch file?

When I run the below batch file code, it thinks that the server address is 'dbuser' and the Database is 'False'
What am I doing wrong?
Here is the code:
#echo off
set toolspath=C:\Program Files (x86)\Folder\Application
Set ApplicationServer=00.0.00.000
Set ApplicationDatabase=dbApplication
Set ApplicationUser=dbuser
Set ApplicationPassword=abcdefg
Set ApplicationUpgradeFromPre12_5=False
REM echo "Attaching dbApplication .. "
REM osql -S %ApplicationServer% -U %ApplicationUser% -P %ApplicationPassword% -i %ApplicationScriptsPath%\AttachApplicationDatabase.sql
REM osql -S %ApplicationServer% -U %ApplicationUser% -P %ApplicationPassword% -i %ApplicationScriptsPath%\SetDBVersion.sql
REM echo "Done."
call ApplicationUpgradeScripts.bat %%2 %ApplicationUser% %ApplicationPassword% %ApplicationDatabase% %ApplicationUpgradeFromPre12_5%
#if ERRORLEVEL 1 goto ERRORSEXIT
#Echo %ApplicationDatabase% Database Updated Successfully.
goto FINISH
:ERRORSEXIT
#Echo Error: Database Excecuted With Error. To Find out Exact Error see file ErrorLog.log
exit /B 1
goto ENDBUILD
:FINISH
#Echo All Databases Excecuted Successfully.
exit 0
:ENDBUILD
pause

windows batch file executing sql server query

I have a batch file that should execute a sql server query and check if count = 0 or more. if 0 exit if not I run another .exe program.
When I run this, the if statement "if ct EQU 0" is not working correctly. In my table count is zero.
#ECHO OFF
SET Header=-----------------------------------------------------
set ct=-1
sqlcmd -S OURDATA\DEVINSTANCE -E -q "SELECT ct=count(*) FROM [dbo].[Table] where Name like '%AMY%' and status=1"
if ct EQU 0 (
echo no count)
goto end
)
if ct GRT 0 (
start "" "C:\test.exe"
if %ERRORLEVEL% NEQ 0 (
echo %header%
Echo There has been an error.
pause
goto end)
)
:end
echo %header%
echo END
Thanks
R
Try replacing it with something like this:
for /F usebackq %%i in (`sqlcmd -E -S OURDATA\DEVINSTANCE -h-1 -Q "SELECT count(*) FROM [dbo].[Table] where Name like '%AMY%' and status=1"`) do (
set count=%%i
)
Hope this helps you.

Resources