Sql-server – Apply procedures in multiple databases

master-system-databasesql server 2014stored-procedurest-sql

I have reach a support line that gave me a T-SQL Script for one DB that I now need to apply many more times.

The original script goes like:

IF EXISTS  Procedure 
THEN DROP
GO

CREATE PROCEDURE [dbo].[Procedure]
...
END
GO   

exec Procedure 'With Arguments'

What I'm trying to do goes like:

DECLARE @db_name VARCHAR(50) -- database name 
DECLARE db_cursor CURSOR FOR 
SELECT name FROM sys.databases 
where create_date > DATETIMEFROMPARTS(2017,12,27,0,0,0,0) 
AND create_date < DATETIMEFROMPARTS(2017,12,30,0,0,0,0)
OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @db_name 
WHILE @@FETCH_STATUS = 0  
BEGIN 
    EXECUTE('USE ' + @db_name)  
    exec Procedure 'With Arguments'
    FETCH NEXT FROM db_cursor INTO @db_name  
END  
CLOSE db_cursor  
DEALLOCATE db_cursor 

But I' m not getting the expected results. I believe that is because I'm not creating the procedure inside each DB.
What is the clean way to do the "If Exists" and "Create Procedure" repeatedly?

I also used :

USE master
CREATE PROCEDURE sp_procedure AS ...

and

USE aDB
exec sp_procedure 'With Arguments'

But it says sp_procedure does not exists…

I'm working with windows SQL server 2014

Help appreciated.

EDIT:
The end code after reading all the answers and marking as System was:

...
BEGIN 
    SET @CMD = 'exec ' + @db_name + '.dbo.sp_procedure ''With Arguments'';';
    exec sp_executesql @CMD;
    ...

Best Answer

I believe that is because I'm not creating the procedure inside each DB. What is the clean way to do the "If Exists" and "Create Procedure" repeatedly?

If I understood you correct, you need to execute the same procedure in many databases.

For example, it can be a procedure that makes a script of all the indexes of the specific table, in this case the procedure is always the same but it should be "local" respect to database where the table resides, this way you can use sys.indexes/sys.columns that are "database sensitive".

The simplest way to do this is to make your procedure "system" procedure, i.e. it will be created in master database, it will have sp prefix and marked as system, so that it can be called from any database and will always use system tables "local" to the database from which it was called.

To accomplish this you should create your procedure only one time in master database as you did:

USE master
CREATE PROCEDURE sp_procedure AS ...

And mark this procedure as system one:

exec sys.sp_MS_marksystemobject 'sp_procedure'

Noe when you run your code like this

USE aDB
exec sp_procedure 'With Arguments'

You will not get

sp_procedure does not exists

anymore.

........................................................

If you still prefer to create this procedure many times in every database the simplest way to do it is to save your procedure script in a file including the rows

IF EXISTS  Procedure 
THEN DROP
GO

And then launch this script from every database:

sqlcmd -S <ComputerName>\<InstanceName> -d <dbname> -i <MyScript.sql>

(you should add -U MyLogin -P MyPassword if you don't want to use Integrated Security).

You should format this string dynamically in your cursor addind dbname like this:

set @cmd = 'sqlcmd -S <ComputerName>\<InstanceName> -d '+ @db_name + ' -i <MyScript.sql>';

exec master.dbo.xp_cmdshell @cmd

.................................................................

Otherwise, you should put the whole text of your sp (create proc...) in a string variable and execute it in your cursor:

declare @sp varchar(max) = cast(' CREATE PROCEDURE ' as varchar(max)) + '[dbo].[Procedure].....'

declare @sql varchar(max) = 'USE ' + @db_name + @sp
EXECUTE(@sql);