5

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

2

4 Answers 4

6

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
Sign up to request clarification or add additional context in comments.

3 Comments

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.
This method is unfortunately invalid given the updated requirement that the database names be derived from a query. .
I updated the answer so it matches the new question.
2

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): [_]

1 Comment

@user1588449 Well, that wasn't the question you asked. Dynamically discovering the databases to run on is very different from having a static list. This needs to be mentioned in the question as it entirely invalidates Filip De Vos's answer as this is not possible in SQLCMD mode. I have updated my answer showing how to do this with a dynamic set of databases.
1

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!

1 Comment

Please post this as an update to the question. It is not an answer; it is just more detail on the question. It should be placed there and this answer should be deleted.
0

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!

1 Comment

Why would you do this? ... it is 3 steps, 2 of them requiring manual execution, compared to the 1 step I suggested that can be fully automated. ..what is the benefit of this method? ..did you see my updated answer? ..I explain why you should use (local) instead of localhost .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.