Set variable in SQL equal to database name - sql-server

I want to execute a .sql file by .bat file (where db=input name in cmd)
The top of the .sql file looks like this:
USE $(db)
DECLARE #Database varchar(500)
SET #Database = $(db)
But after executing the .bat file, an error occurs at line 4 of the .sql file
Apparently, variable = $(db) does not work.
Is there another way in order to do something like this?

Use SQLCMD variables, so change your batch file to call SQLCMD rather than ISQL
#echo off
sqlcmd -E -S myserver -i sample.sql -v db=YourDBName
sample.sql content would be like this
USE $(db)
DECLARE #Database varchar(500)
SET #Database = $(db)

Related

Windows batch file executes only the first line

I have created a batch with the following. ( Batch file name is BACKUP_TASK.bat )
SQLCMD -E -S SQLEXPRESS
DECLARE #DatabaseName sysname = N'DEMO_DB',
#DatabaseBackupFileName varchar(255);
SET #DatabaseBackupFileName = 'C:\sql\' + #DatabaseName + '_' + REPLACE(replace(convert(varchar(40),getdate()),' ','_'),':','_') + '.bak';
BACKUP DATABASE #DatabaseName TO DISK = #DatabaseBackupFileName;
GO
exit
exit
If I copy paste this code directly to Command Prompt it Executes as Expected.But if I double click on the batch file then the Command Prompt opens up and only the first line is compiled and nothing happen further more.
So what I am doing here wrong ? Please help me solve this.

Trying to spin up a database from the command line if it doesn't exist

I'm trying to feed in a variable name from the command line and create a database if it does not exist. My command line is below:
sqlcmd -S localhost -i 00_SpinUp.sql -v DBName = TEST -o Script00.txt -b
where 00_SpinUp.sql is as follows:
DECLARE #DBNAME VARCHAR(MAX);
SET NOCOUNT ON
GO
IF DB_ID('$(DBNAME)') IS NULL
BEGIN
CREATE DATABASE #DBNAME
END
Yet I'm getting a syntax error. What have I done wrong?
With SQLCMD variables, reference the variable in the script with $(VariableName) rather than as T-SQL variables. No declaration is needed in the script.
SET NOCOUNT ON;
GO
IF DB_ID('$(DBNAME)') IS NULL
BEGIN
CREATE DATABASE [$(DBNAME)];
END;

Running .sql file within a SQL query

I have a SQL script I need to run on about 20 different databases.
I basically just need to be able to run some SQL, then have it load and run a file from the disk, do more SQL, run that same script again, etc.
I was hoping to make a SQL script that would basically look something like this:
use database1
go
exec c:\release.sql
go
use database2
go
exec c:\release.sql
go
use database3
go
exec c:\release.sql
go
--etc....
I've looked online a bunch and found a way to do something similar in a batch file with sqlcmd but it isn't working and I don't see how to switch databases that way, either.
Thanks a ton!
Ben
You can switch management studio to sqlcmd mode (query menu) and then run a script with :r script.sql
To do this on a dynamically generated list of databases you have to do some sqlcmd trickery:
set output to file
generate the command to execute
set output to stdout
execute the file
delete the temp file
I assume in this example that the file script.sql exists in c:\temp. Note that the GO statements are important in the script or the sqlcmd parser will get confused.
:OUT $(TEMP)\db.sql
declare #script nvarchar(max)
select #script = isnull(#script, '')
+ 'use ' + name + char(13) + char(10)
+ ':r c:\temp\script.sql' + char(13) + char(10)
from sys.databases
where name like N'%[_]db'
print #script
GO
:OUT stdout
:r $(TEMP)\db.sql
GO
!!del $(TEMP)\db.sql /s /q
You don't need to do this in SSMS. You just need to create a CMD script.
IF you have a static set of databases to run on, then use the following:
#ECHO OFF
SET MyServer="(local)"
SET MyScript="c:\release.sql"
SQLCMD -S %MyServer% -E -i %MyScript% -d database1
SQLCMD -S %MyServer% -E -i %MyScript% -d database2
...
SQLCMD -S %MyServer% -E -i %MyScript% -d database20
IF you have a dynamic set of databases that can be queried for, then use the following:
#ECHO OFF
SET MyServer="(local)"
SET MyScript="c:\release.sql"
SET MyQuery="SET NOCOUNT ON; SELECT [Name] FROM [sys].[databases] sd WHERE sd.[name] LIKE N'%%[_]db' ORDER BY sd.[name];"
FOR /F %%B IN ('SQLCMD -h -1 -S %MyServer% -E -Q %MyQuery%') DO (
REM remove the "echo" from the next line to run the scripts
echo SQLCMD -S %MyServer% -E -i %MyScript% -d %%B -o results-%%B.txt
)
Using the %%B in the output filename will give you a different output file per database, as in:
results-database1_db.txt
results-database2_db.txt
...
Other notes:
Use (local) instead of localhost when connecting to the local, default instance as it uses shared memory while localhost forces a TCP connection.
If you are searching for an underscore in a LIKE statement, enclose it in square brackets else it is a single-character wild card (which still technically works sometimes, but could also match other characters): [_]
Thanks everyone who pitched in! The following seems like it might work (based on #srutzky's answer)
sqlcmd -S "localhost" -E -i "c:\release.sql" -d database1 -o results.txt
The thing I am missing by using a cmd prompt instead of SSMS is that I don't think I can write cursor to loop through each database that ends with "_db" and then execute against that... Here's the SQL I have but I just need to be able to put the link to the SQL file to execute.
link
If I put the release script SQL into this file into the #text variable it doesn't work because it blows up on each GO statement I have in my release.sql file.
declare #text as nvarchar(max)
set #text = N'
-- GET AND RUN SCRIPT FROM DISK!
'
declare C_CURSOR CURSOR FOR
select [Name] from sys.databases
where name like '%_db'
order by name
declare #runtext as nvarchar(max)
declare #DB_Name as nvarchar(200)
OPEN C_CURSOR
fetch next from C_CURSOR INTO #DB_Name
WHILE(##FETCH_STATUS = 0)
BEGIN
print #DB_Name
set #runtext = 'select ''' + #DB_Name + ''' as DatabaseName
use ' + #DB_Name + N'
' + #text
exec sp_executesql #runtext
fetch next from C_CURSOR INTO #DB_Name
END
CLOSE C_CURSOR
DEALLOCATE C_CURSOR
Thanks again!
I ended up combining 2 things. I made a SQL script that creates a cursor to find the databases and then prints a list of commands for a CMD prompt. I then run that in the command prompt. Below is what we output with our sql script and then save as a .bat file that we run. It's working great!
That script is essentially created with the following SQL script:
/*** GET DATABASES IN THE CURSOR QUERY BELOW! */
declare C_CURSOR CURSOR FOR
select [Name] from sys.databases
where name like '%_db'
order by name
/* THIS IS WHERE THE CURSOR STARTS*/
declare #DB_Name as nvarchar(200)
OPEN C_CURSOR
fetch next from C_CURSOR INTO #DB_Name
WHILE(##FETCH_STATUS = 0)
BEGIN
print 'SQLCMD -S "localhost" -E -i "C:\release.sql" -d ' + #DB_Name + ' -o ' + #DB_Name + '_results.txt'
fetch next from C_CURSOR INTO #DB_Name
END
CLOSE C_CURSOR
DEALLOCATE C_CURSOR
That outputs the following which we then run in a .bat file
SQLCMD -S "localhost" -E -i "C:\release.sql" -d database1 -o database1_results.txt
SQLCMD -S "localhost" -E -i "C:\release.sql" -d database2 -o database2_results.txt
SQLCMD -S "localhost" -E -i "C:\release.sql" -d database3 -o database3_results.txt
Thanks everyone!

Using variable as file name in sqlcmd - SQL Server 2008

I'm trying to print a table content into to a csv file using sqlcmd.
The file name is generated using a query :
set nocount on
set ansi_warnings off
declare #report_date datetime
select #report_date = (select MAX(ddate) from table_to_export);
declare #ctl_file varchar(100)
set #ctl_file = 'BATCH_' + CONVERT(VARCHAR(8), max(#report_date), 112) + '.CSV'
:out #ctl_file
select * from table_to_export where ddate = #report_date;
:out stdout
and executing the script from the cmd using
sqlcmd -i c:\temp\batch_report.sql -s"," -W -h-1 -f 65001
I'm currently getting an empty file named #ctl_file in the active directory.
Is there any way to pass a file name to :out command ?
I've tried using bcp but it wont output UTF encoding so it's not an option.
Thanks.
Try something like this:
:setvar ctl_file "c:\temp\Batch_20140812.txt"
:out $(ctl_file)
select * from table_to_export where ddate = #report_date;
I am not sure how to set the file name within the script, but you could save a generic script and call it from sqlcmd, passing in the the filename as a variable.

SQL server 2008: Copy a file and rename it

I have a file inside a directory \\myServer\Admin\temp\testtemp.txt
I need to write a TSQL to
Search for testtemp.txt file.
If exists, create a copy of it and rename it to Copytesttemp.txt
If there's testtemp.txt already in the above directory like this
\\abcd\Admin\temp\Copytesttemp.txt
then delete it and recreate Copytesttemp.txt
How do I achieve it? Thanks.
You can use xp_cmdshell to run any DOS commands you like, e.g.
declare #cmdstring varchar(1000)
set #cmdstring = 'copy \\myServer\Admin\temp\testtemp.txt \\myServer\Admin\temp\Copytesttemp.txt'
exec master..xp_cmdshell #cmdstring
Just make sure xp_cmdshell is enabled on your installation.
Create a SQL Agent job which runs a command script to do the actions.
You can try this for Copy a file and rename
EXEC master..xp_cmdshell 'COPY D:\T1\a.txt D:\T2\b.txt'
Only copy and move just like CMD
EXEC master..xp_cmdshell 'COPY D:\T1\abcd.txt D:\T2'
EXEC master..xp_cmdshell 'Move D:\T1\abcd.txt D:\T2'

Resources