SqlCmd command execution stops - sql

Iam new to sqlcmd and i'm trying to execute this sql cmd code:
:Connect SERVERNAME
!!if exist $(FullBackup) del $(FullBackup)
GO
!!if exist $(TransactionLog) del $(TransactionLog)
GO
I am passing variables $(FullBackup) and $(TransactionLog) through a powershell script:
& $app -i $syncFileLocal -E -b -v FullBackup=("""$fullbackup""") TransactionLog=("""$transactionLog""");
where syncFileLocal contains the above sqlcmd command.
Somehow the execution stops after the second :Connect PROD-SQLMASTER
UPDATE:
When i use harcorded values for $(FullBackup) and $(TransactionLog)
the script seems to work. Is there anyway i could do it by passing variables through powershell?

Instead of:
FullBackup=("""$fullbackup""") TransactionLog=("""$transactionLog""")
try:
FullBackup="""$fullbackup""" TransactionLog="""$transactionLog"""
If you use (), the grouping operator, its output is passed as a separate argument, which is not what you want.
Do note, however, that even the solution above relies on PowerShell's fundamentally broken argument-passing to external programs, as of v7.0 - see this answer.
If sqlcmd is implemented properly (I don't know if it is), the right way to pass the arguments is:
FullBackup=$fullbackup TransactionLog=$transactionLog
That way, you would rely on PowerShell's on-demand, behind-the-scenes re-quoting of arguments, where if $fullbackup or $translactionLog contained spaces, the arguments would be passed as, for instance, "FullBackup=c:\path\to\backup 1" and "TransactionLog=c:\path\to\log 1"

I found a solution. I recommend using this with appropriate validations
:Connect $(ServerMaster)
DECLARE #resultBkp INT
EXEC master.dbo.xp_fileexist N'$(FullBackup)', #resultBkp OUTPUT
IF (#resultBkp = 1)
BEGIN
DECLARE #resultDeleteBkp INT
EXECUTE master.sys.xp_cmdshell '$(FullBackup)'
EXEC master.dbo.xp_fileexist N'$(FullBackup)', #resultDeleteBkp OUTPUT
IF (#resultDeleteBkp = 0)
BEGIN
PRINT 'Backup Deleted'
END
ELSE
BEGIN
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
RETURN;
END
END
ELSE
BEGIN
PRINT 'Backup file not found'
END
I used the master.dbo.xp_fileexist to check whether the file exists and then used
master.sys.xp_cmdshell command to delete the file.
To enable master.sys.xp_cmdshell for the database server please use this solution:
Enable 'xp_cmdshell' SQL Server
I have tested it and it works fine when i pass the arguments via powershell.

Related

Forcing a sql script to be executed with result to text in SSMS

I usually need to send the result of my queries to "Grid" when using SSMS but I have a specific script the result of which i need to send "to text". Is there a way to script this at the beginning of my .sql file?
I imagine it is something that only SSMS could understand and it won't be a generic sql statement
You might find this Reddit thread helpful in your case:https://www.reddit.com/r/SQLServer/comments/1vrlx3/i_want_to_turn_on_text_output_via_sql_command/
Basically, if you have SQLCMD mode turned on, run the following to print to text:
:OUT STDOUT
SELECT * FROM TABLE
To issue a warning if the script is executed without SQLCMD mode turned on, you can use the check below:
SET NOEXEC OFF; -- previous execution may have toggled it
:setvar IsSqlCmdEnabled "True"
GO
IF ('$(IsSqlCmdEnabled)' = '$' + '(IsSqlCmdEnabled)')
BEGIN
PRINT('Use SqlCmd-mode!!');
SET NOEXEC ON;
-- RAISERROR ('This script must be run in SQLCMD mode.', 20, 1) WITH LOG
END
ELSE
BEGIN
PRINT('Using SqlCmd-mode')
-- insert the code you really want to execute:
-- ...
END
SET NOEXEC OFF; -- do not disable next execution in this session

SQL Server Calling a stored procedure from another stored procedure at the command line

I have been playing around with database backup automation scripts and in particular the one at this link:
http://support.microsoft.com/kb/2019698
I got everything working fine and even added automated compression using 7zip, logging, and with the help of vbscript an email scheduled notification. However, even without all that, you can see this is a bit heavy. Its now easily reaching 400 lines of code.
I am really not comfortable having all my stuff in one block like this and I want to separate it out. So I can have say a compression file called BackupCompress.sql, and an log file called BackupLogReport.sql all of which would be called from inside the main Backup.sql script.
The Backup.sql script is in turn run from a Backup.bat file which is set to run in the scheduler.
All of this works like a charm. But I am at a loss as to how to call BackupCompress.sql from within BackupLogReport.sql and pass in parameters and get a return value.
In the Backup.bat file I use this command to spin everything up and pass parameters to it:
SQLCMD -S %SQLDATABASE% -d master -i %BACKUP_FOLDER%\Backup.sql -v Pram1="%Pram1%"
In the Backup.sql file I get those parameters simply by:
DECLARE #Param1 NVARCHAR(256) = '$(Param)'
from then on as my script runs it uses whatever I want to pass in.
I tried using standard sql stored procedure logic to call another procedure like this:
EXEC BackupCompress.sql
#AnotherParam = #Param1
I also tried:
EXECUTE sp_executesql BackupCompress.sql #Param1
Finally I tried:
SET #cmd = 'SQLCMD -S ' + ##ServerName + ' -d master -i $(BACKUP_FOLDER)\BackupCompress.sql -v Param1 = ' + #Param1
EXEC xp_cmdshell #cmd, no_output
but it doesn't work and my files which were being compressed simply don't get compressed. I get no error message. everything else continues to work fine.
EDIT: I was getting an error message on the last one but I fixed it - however, I still don't get my little zip file. I even put print's into the file to see if it was actually be executed but it does not seem to be.
EDIT2: Another option I have tried, almost works, but cant figure out how to pass parameters from within the sql file to the other file... As a result it generates an error saying it cant find the file as it's treating the path as a literal string instead of the variable value I want to pass.
:!!SQLCMD -S ##ServerName -d master -i #CFG_BACKUP_PATH\BackupCompress.sql -v Param1 = #Param1
xp_cmdshell can return values. These values can be captured into a table variable that you could use to "see" the results, and perhaps determine where the problem lies:
DECLARE #cmd VARCHAR(255);
DECLARE #Param1 NVARCHAR(256) = '$(Param)';
DECLARE #Results TABLE
(
ResultsText NVARCHAR(MAX)
);
SET #cmd = 'SQLCMD -S ' + ##ServerName + '-d master -i $(BACKUP_FOLDER)\$(BackupCompress.sql) -v Param1 = ' + #Param1;
SET #cmd = 'DIR \';
INSERT INTO #Results (ResultsText)
EXEC xp_cmdshell #cmd;
SELECT *
FROM #Results;
You need to ensure xp_cmdshell is enabled for the instance, by executing:
EXEC sp_configure 'xp_cmdshell',1;

How to pass parameters to SQL script via Powershell

I have a Power-shell script that calls a SQL script. This is currently working, but inside my sql script I have some hard coded parameters that I would like to pass to the SQL script via the powershell.
So this is the snip-it from the Power-shell script
function ExecSqlScript([string] $scriptName)
{
$scriptFile = $script:currentDir + $scriptName
$sqlLog = $script:logFileDir + $scriptName + "_{0:yyyyMMdd_HHmmss}.log" -f (Get-Date)
$result = sqlcmd -S uk-ldn-dt270 -U sa -P passwordhere3! -i $scriptFile -b | Tee-Object - filepath $sqlLog
if ($result -like "*Msg *, Level *, State *" -Or $result -like "*Sqlcmd: Error:*")
{
throw "SQL script " + $scriptFile + " failed: " + $result
}
}
try
{
ExecSqlScript "restoreDatabase.sql"
}
catch
{
//Some Error handling here
}
And this is from the SQL
USE MASTER
GO
DECLARE #dbName varchar(255)
SET #dbName = 'HardCodedDatabaseName'
So I want to pass the value for dbName, any ideas?
You could take advantage of sqlcmd's scripting variables. Those can be used in script file and are marked with $(). Like so,
-- Sql script file
use $(db);
select someting from somewhere;
When calling sqlcmd, use the -v parameter to assign variables. Like so,
sqlcmd -S server\instance -E -v db ="MyDatabase" -i s.sql
Edit
Mind the Sql syntax when setting variables. Consider the following script:
DECLARE #dbName varchar(255)
SET #dbName = $(db)
select 'val' = #dbName
As passed to the Sql Server, it looks like so (Profiler helps here):
use master;
DECLARE #dbName varchar(255)
SET #dbName = foo
select 'val' = #dbName
This is, obviously invalid a syntax, as SET #dbName = foo won't make much sense. The value ought to be within single quotes like so,
sqlcmd -S server\instance -E -v db ="'foo'" -i s.sql
Just in case someone else needs to do this... here is a working example.
Power Shell Script:
sqlcmd -S uk-ldn-dt270 -U sa -P 1NetNasdf£! -v db = "'DatabaseNameHere'" -i $scriptFile -b | Tee-Object -filepath $sqlLog
Note the -v switch to assign the variables
And here is the MS SQL:
USE MASTER
GO
if db_id($(db)) is null
BEGIN
EXEC('
RESTORE DATABASE ' + $(db) + '
FROM DISK = ''D:\DB Backup\EmptyLiveV5.bak''
WITH MOVE ''LiveV5_Data'' TO ''C:\Program Files (x86)\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\LiveV5_' + $(db) + '.MDF'',
MOVE ''LiveV5_Log'' To ''C:\Program Files (x86)\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\LiveV5_' + $(db) + '_log.LDF'', REPLACE,
STATS =10')
END
Note: You do not have to assign the scripting varible to a normal sql varible like this.
SET #dbName = $(db)
you can just use it in your sql code. - Happy coding.
Here's a full example using a different PowerShell approach. Here I'm using a specific script to reset local databases for a clean development environment.
## Reset the Database
$resetScript= "C:\ResetSite\resetDatabases.sql"
Write-Host "Resetting the DB - Running $($resetScript)"
$connectionString = "Server = localhost; Database = 'master'; UID = myusername; PWD = mypassword"
# Create variables & params
$sqlCmdVariables = #(
"Database=$($siteConfig.db_name)",
"UserName=$($siteConfig.db_username)",
"UserPassword=$($siteConfig.db_user_password)"
)
$sqlCmdParameters = #{
InputFile = $resetScript
QueryTimeout = 1800
ConnectionString = $connectionString
Variable = $sqlCmdVariables
}
# Invoke
Invoke-SqlCmd #sqlCmdParameters
The .sql file then uses the parameters passed in, the same way #nmbell mentions.
-- Declare the vars
DECLARE #Database nvarchar(100), #UserName nvarchar(100), #UserPassword nvarchar(100)
-- Set the vars
SET #Database = '$(Database)' -- database name
SET #UserName = '$(UserName)' -- SQL login and database username
SET #UserPassword = '$(UserPassword)' -- login password
... more stuff here.. use the vars like normal
This is partly derived from this blog post but modified slightly to use a file rather than an inline query.
Adjusting vonPryz's answer to use:
SET #dbName = '$(db)'
means you can pass in the parameter from the command line in a more natural form as
sqlcmd -S server\instance -E -v db ="foo" -i s.sql
The SqlCmd variable still substitutes correctly.
I know this is an old answer but I do have a better way that is much easier if you only need a small amount of data from Powershell (or even a large amount as long as all you want is text), and you work mainly in SQL for your scripting like I do:
1: Start the PowerShell from SQL using xp_cmdshell, and insert the results to a one-column table which allows NULLs e.g:
DECLARE #Results (Line varchar(1000) NULL)
INSERT #Results
EXEC master.dbo.xp_cmdshell '"powershell.exe C:\PowershellScripts\MyScript.ps1 MyParams"'
2: During your PowerShell script, for anything you want to pass back to SQL, simply use "Write-Output", e.g:
Write-Output $returned_data
You can do this as many times as you want. If you have 10,000 values to pass back to SQL, then you could use write-output 10,000 times.
So in the above example once the "MyScript.ps1" PowerShell script finishes running, all of the output will be in the #Results table variable, ready to be used, queried, imported into individual variables, whatever you want really.

SQL Server Management Studio -- Script that executes other scripts?

So I have been looking around for a way to develop a script that will execute other scripts from within my project folder using SQL Server Management Studio and so far none of the other solutions have worked. I tried writing a script that had the sqlcommandline stuff in it:
sqlcmd -S.\SQLExpress -imyScript.sql;
and that didn't work and from my understanding using #\path\to\script.sql won't work either so any other ideas? Or should I start looking into writing a procedure? In which case, could anybody point me in the right direction?
Thank you in advance for any assistance.
Personally, I'd look into writing stored procedures. The MSDN documentation is good and there are lots of resources on line if you do a quick search.
Alternatively you could do something like this to MAKE it happen (you'll need to have permission to execute command shell, etc):
CREATE TABLE ##SQLFiles ( SQLFileName VARCHAR(2000))
GO
INSERT INTO ##SQLFiles
EXECUTE master.dbo.xp_cmdshell 'dir /b "C:\SQL Scripts\*.sql"'
GO
DECLARE cFiles CURSOR LOCAL FOR
SELECT DISTINCT [SQLFileName]
FROM ##SQLFiles
WHERE [SQLFileName] IS NOT NULL AND
[SQLFileName] != 'NULL'
ORDER BY [SQLFileName]
DECLARE #vFileName VARCHAR(200)
DECLARE #vSQLStmt VARCHAR(4000)
OPEN cFiles
FETCH NEXT FROM cFiles INTO #vFileName
WHILE ##FETCH_STATUS = 0
BEGIN
-- The following SET command must be on a single line or else an error will be generated.
-- It is split in this script for readability purposes.
SET #vSQLStmt = 'master.dbo.xp_cmdshell ''osql -S Server Name -U User Name -P Password
-d Database Name -i "C:\SQL Scripts\' + #vFileName + '"'''
EXECUTE (#vSQLStmt)
FETCH NEXT FROM cFiles INTO #vFileName
END
CLOSE cFiles
DEALLOCATE cFiles
GO
DROP TABLE ##SQLFiles
GO

Executing a stored proc inside a script file using the sqlcmd -i

Need some help with script files.
I have an SQL script file in the following format:
Begin tran
insert..
select..
update..
Commit
exec linked_server.db1.dbo.storedproc1
I am calling the above script file from within a .js file in the following manner:
var sCommand = "sqlcmd -i C:\\scriptfile1"
var WshShell = new ActiveXObject("WScript.Shell");
var oExec = WshShell.Exec(sCommand);
When I run the .js file, the code between tran-commit gets executed but the storeproc1 is never called. I know for sure that the storedproc1 is not called because it has a list of insert statements that never shows up in the table.
Have you tried running the exec storedproc1 alone? Maybe it throws an error.
Also you can try adding go like this:
commit
go
exec storedproc1
You can try this in the management studio first. After you are sure it works in the management studio, you can go on running it through sqlcmd.
Edit: next you can check the permission of the user running the script, whether it is allowed to run stored procedure.