Multi-file script execution from command line - batch-file

I have multiple .sql script files and want to execute them one by one in batch file with proper logging mechanism.
I wrote below batch command to solve the problem
#ECHO OFF
SET SQLCMD="C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\SQLCMD.EXE"
SET PATH="C:\Users\sql_scripts\"
SET SERVER="server_name"
SET DB="database"
SET LOGIN="user_name"
SET PASSWORD="password"
SET OUTPUT="C:\Users\sql_scripts\output\OutputLog.txt"
CD %PATH%
ECHO %date% %time% > %OUTPUT%
for %%f in (*.sql) do (
%SQLCMD% -S %SERVER% -d %DB% -U %LOGIN% -P %PASSWORD% -i %%~f -b >> %OUTPUT%
)
But it has few problems that I want to solve as listed below :
I want to create dynamic out put file names based on input file name. Example if input sql file
name is "test.sql" then I want to create output file in "output" folder with name "test.sql".
Currently It writes all the log to one file i.e. OutputLog.txt
I want to show output log with script of execution to identify which script produced what
output. Let's say in one script file 5 scripts present then in output file I want to show the
script and its output log.

Related

Run command with drag and drop onto batch file

I want to drag and drop a file onto a batch file in order to run the below command on it. How do I go about running the command on the dropped file?
PotreeConverter.exe <dropped file> -o C:/output -p index
The path of the file, when you drop it on the BATfile, will be returned as a normal %1 argument.
so :
#echo off
PotreeConverter.exe "%~1" -o C:/output -p index
You can use %* if you drop more then 1 file
Example :
#echo off
for %%a in (%*) do echo [%%a] was dropped on me
pause
Following this easy guide.
Create a batch file test.bat with the contents
#echo off
echo The full path of the file is: %1
pause
Drag any file onto it, you will see that %1 is replaced with the full path for that file in quotes.
Now you know how to execute some command that takes a path to a file as an argument:
#echo off
some_command_that_takes_a_path_to_a_file %1

User-specified scripts and output folders for sqlcmd in batch file

Currently, the below For/Do loop goes through all SQL files that are in the same folder as the batch file itself and outputs the CSVs to a user-specified folder (%OUTPUTFOLDER% is actually created earlier in the batch file as a subfolder of %SCRIPTFOLDER%, which is specified by the user):
FOR /F "tokens=*" %%S IN (
'DIR /B "%SCRIPTFOLDER%\*.sql" '
) DO (
echo Reading scripts from: %SCRIPTFOLDER%\*.sql
echo Script: %%~fS
echo Output: %OUTPUTFOLDER%\%%~nS.csv
sqlcmd -b -S %INSTANCE% -d %DATABASE% -i "%%~fS" -s "|" -o "%OUTPUTFOLDER%\%%~nS.csv" -W
IF ERRORLEVEL 1 GOTO errorhandling
ECHO %%~nS.csv successfully created
)
For a visual example, if I had the folder structure
C:\Extract\extract.bat
C:\Extract\Scripts\
C:\Extract\Output\
The variable %SCRIPTFOLDER% is set by the user and is the folder that, you guessed it, holds the scripts. But the batch file has to be in that folder, too. I need to change this so that the scripts do not have to be in the same folder as the batch file. I.e. the user can specify both %SCRIPTFOLDER% and %OUTPUTFOLDER%
Due to the output of echo Script: %%fS, I'm guessing that's what I need to change - possibly what's in the FOR line as well, but I'm not seeing how exactly to do that.

Sending sqlcmd output file to directory that is a variable

Currently, the following code in a batch file works: it runs all SQL scripts in %SCRIPTFOLDER% and sends each script's output to a CSV within the same folder as the scripts.
FOR /F "tokens=*" %%S IN (
'DIR /B "%SCRIPTFOLDER%\*.sql" '
) DO (
sqlcmd -b -S %INSTANCE% -d %DATABASE% -i "%%~fS" -s "|" -o "%%~dpnS.csv" -W
IF ERRORLEVEL 1 GOTO errorhandling
ECHO %%~nS.csv successfully created
)
What I'd like to do is allow the user to specify where the generated CSVs get sent to using a variable %OUTPUTFOLDER%.
I tried placing %OUTPUTFOLDER%, which is a full path, drive, and folders (e.g. D:\some folder\output) in various positions within %%~dpnS.csv. Specifically,
%%~dp%OUTPUTFOLDER%nS.csv
and
%%~dpn%OUTPUTFOLDER%S.csv
but they didn't work and I'm (probably obviously to you) woefully inept at batch file syntax!
I understand that dp is the drive and path and that S is the file name, but I'm not sure how to integrate that with a the variable that is the path.
The iterating variable is %%S, the modifier ~dpn forces an evaluation of drive path and name.
In this case you want to specify the drive and path yourself so depending on wether %OUTPUTFOLDER% has a trailing backslash
-o "%OUTPUTFOLDER%%%~nS"
or not use:
-o "%OUTPUTFOLDER%\%%~nS"

Specifying relative path to :r command in sqlcmd mode

A) Suppose you have four .sql files (script1.sql,script2.sql,script3.sql,script4.sql ) in say in a folder c:\scripts.
B) Create a main script file (Main.sql) with the following, please note I have given relative path for scripts.
:r script1.sql
:r script2.sql
:r script3.sql
:r script4.sql
Save the Main.sql in c:\scripts itself.
C) Create a batch file named "ExecuteScripts.bat" with the following:-
SQLCMD -E -d<YourDatabaseName> -ic:\Scripts\Main.sql
PAUSE
When I run the batch file, its unable to script1.sql file. When i give full path C:\scripts\script1.sql, it works fine but I don't want to hardcode the path here.
Is it possible to achieve this using sqlcmd?
#echo off
pushd "c:\scripts"
SQLCMD -E -d<YourDatabaseName> -iMain.sql
popd
PAUSE
Or if all the sql scripts are in the same folder as your batch script, then:
#echo off
pushd "%~dp0"
SQLCMD -E -d<YourDatabaseName> -iMain.sql
popd
PAUSE
The last version allows your scripts to run properly, no matter where they reside.
What about using complete paths, but creating file Main.sql dynamically?
Batch file which expects the 4 script files in folder of the batch file and creates there also Main.sql.
#echo off
set "BatchFolder=%~dp0"
( echo :r %BatchFolder%script1.sql
echo :r %BatchFolder%script2.sql
echo :r %BatchFolder%script3.sql
echo :r %BatchFolder%script4.sql
)>"%BatchFolder%Main.sql"
sqlcmd.exe -E -d "YourDatabaseName" -i "%BatchFolder%Main.sql"
set "BatchFolder="
pause
Open a command prompt window and run there call /?. The help of this command is output in the window explaining %~dp0 which means drive and path of argument 0 ending with a backslash without surrounding quotes. Argument 0 on running of a batch file is the name of the batch file.
Running in command prompt window set /? results in getting help of command set displayed, listing on last help page some special environment variables defined dynamic on running a batch file. The first one listed is %CD% which means current directory.
So instead of working with folder of batch file, it is also possible to work with current folder on batch execution.
#echo off
set "CurrentFolder=%CD%\"
( echo :r %CurrentFolder%script1.sql
echo :r %CurrentFolder%script2.sql
echo :r %CurrentFolder%script3.sql
echo :r %CurrentFolder%script4.sql
)>"%CurrentFolder%Main.sql"
sqlcmd.exe -E -d "YourDatabaseName" -i "%CurrentFolder%Main.sql"
set "CurrentFolder="
pause
The folder path referenced by %CD% does not end with a backslash like the folder path returned by %~dp0 which is the reason for backslash after %CD% on second line.

batch file for executing SQL scripts - no carriage returns

There are some script files in a folder that must be executed on a SQL Server database. Not all of the files in the folder, just a subset. The following command is in a batch file and it is working but the files are all on one line. It is very difficult to read (there are more files than the 3 shown in the example). Is there a way that the files can be listed on individual lines (for readability) and not lose the functionality? The goal is to perform this task using a batch file only - not a batch file + a SQL file that uses the :r command for each script to be executed.
sqlcmd -S ServerInstance -E -d DatabaseName -i .\Tables\stage.products.sql, .\Tables\dbo.products.sql, .\Sprocs\dbo.BuildProducts.sql
If it's a batch file you can add a ^ to the end of each line:
echo Line 1 ^
and line 2 ^
and line 3 will all echo in a single line.
When you run the above batch file the results are:
Line 1 and line 2 and line 3 will all echo in a single line.
#echo off
setlocal EnableDelayedExpansion
set "sqls="
for %%a in (
.\Tables\stage.products.sql
.\Tables\dbo.products.sql
.\Sprocs\dbo.BuildProducts.sql
) do set "sqls=!sqls!, %%a"
sqlcmd -S ServerInstance -E -d DatabaseName -i %sqls:~1%
Previous Batch file allows you to list files on individual lines for readability as you requested. It does NOT allows you to include more files than originally you could include in one line.

Resources