Give DROP PROCEDURE a parameter - sql-server

I'm using SqlServer for the first time, and in every single one of our create procedure scripts there is a block of code like below to remove the procedure if it already exists:
IF EXISTS (SELECT *
FROM information_schema.routines
WHERE routine_name = 'SomeProcedureName'
AND routine_type = 'PROCEDURE'
BEGIN
DROP PROCEDURE SomeProcedureName
END
//then the procedure definition
To stop cutting and pasting this boilerplate code in every file I would like to put this code in its own stored procedure so that instead the scripts would look like this:
DropIfRequired('SomeProcedureName')
//then the procedure definition
My attempt at a solution is:
CREATE PROCEDURE DropIfRequired
(
#procedureName varchar
)
AS
IF EXISTS (SELECT * FROM information_schema.routines
WHERE routine_name = #procedureName
AND routine_type = 'PROCEDURE')
BEGIN
DROP PROCEDURE #procedureName
END
But I then get the following error:
Msg 102, Level 15, State 1, Procedure DeleteProcedure, Line 10
Incorrect syntax near '#procedureName'.
Any ideas how to do what I want?

The full answer is:
DECLARE #SQL VARCHAR(8000)
SELECT #SQL = 'USE ' + DB_NAME() + CHAR(10)
SET #SQL = #SQL + 'DROP PROCEDURE ' + #procName
--PRINT #SQL
EXEC(#SQL)
The one given by Andrew will only work if the default database for your login is set to the database you want. When using dynamic sql you get a new database context. So if you do not have a default database set you will execute the command from master.

One thing to note is that in the DropIfRequired procedure, you have defined the procedure name as follows:
CREATE PROCEDURE DropIfRequired
(
#procedureName varchar
)
You need to define a length of the varchar parameter, otherwise SQL will assume a length of one character. Instead, do something like as follows (1000 should be more than enough for most procedure names)
CREATE PROCEDURE DropIfRequired
(
#procedureName varchar(1000)
)

its missing quotes, try adding them in with an exec statement.
EXEC( 'DROP PROCEDURE ''' + #procName + '''') ( all single quotes)

Related

Could not find stored procedure 'sp_msforeachtable' while looping through server for stats (SSMS)

I've written this to loop through each database on a server, collecting the statistics for each table and storing them in a temp table. Eventually, I'll integrate this into a more permanent structure, but for now I'm just trying to get this working. My problem is, after 57 databases, I get the error stating it can't find the stored procedure sp_msforeachtable.
I've verified that this stored procedure exists on every database on the server and on the server level.
I've excluded this database in the findings by adding it to the "where name not in" condition, and it just moves to the next one in the list and gives the same error.(I've confirmed it exists on the next database also). I've actually done this for the next 6 databases.
This is causing me to not collect accurate information. Am I running out of resources somewhere?
DECLARE #Database TABLE (DbName SYSNAME);
IF OBJECT_ID('tempdb.dbo.#TableLvlSizes', 'U') IS NOT NULL
BEGIN
PRINT 'dropping table'
DROP TABLE tempdb.dbo.#TableLvlSizes;
END
CREATE TABLE #TableLvlSizes (
TableName nvarchar(128)
,NumberOfRows varchar(50)
,ReservedSpace varchar(50)
,TableDataSpace varchar(50)
,IndexSize varchar(50)
,unused varchar(50))
DECLARE #DbName AS SYSNAME;
DECLARE #Sql1 AS VARCHAR(MAX);
SET #DbName = '';
INSERT INTO #Database (DbName)
SELECT NAME
FROM sys.databases
where name not in ('tempdb')
ORDER BY NAME ASC;
WHILE #DbName IS NOT NULL
BEGIN
SET #DbName = (
SELECT MIN(DbName)
FROM #Database
WHERE DbName > #DbName
);
print #DbName;
SET #Sql1 =
'USE ' + #DbName + '; ' + '
Exec sp_msforeachtable
''insert into #TableLvlSizes exec sp_spaceused [?]''
'
Exec (#SQL1);
END
If someone is using Azure SQL, they will not find sp_MSforeachtable since it is not available in Azure SQL.
You may need to create one for yourself.
Since you already verified that the stored procedure does in fact exist, I believe your database is case sensitive. Therefore, the error is still accurate. Basically, the stored procedure with the case you used does not exist. The actual procedure name is sp_MSforeachtable
In your code, you are using the following:
Exec sp_msforeachtable
If you change your code to use the proper case for the stored procedure to be sp_MSforeachtable, it should work:
SET #Sql1 =
'USE ' + #DbName + '; ' + '
Exec sp_MSforeachtable
''insert into #TableLvlSizes exec sp_spaceused [?]'''

Is it possible to issue CREATE statements using sp_executesql with parameters?

I'm trying to dynamically create triggers, but ran into a confusing issue around using sp_executesql and passing parameters into the dynamic SQL. The following simple test case works:
DECLARE #tableName sysname = 'MyTable';
DECLARE #sql nvarchar(max) = N'
CREATE TRIGGER TR_' + #tableName + N' ON ' + #tableName + N' FOR INSERT
AS
BEGIN
PRINT 1
END';
EXEC sp_executesql #sql
However, I want to be able to use #tableName (and other values) as variables within the script, so I passed it along to the sp_executesql call:
DECLARE #tableName sysname = 'ContentItems';
DECLARE #sql nvarchar(max) = N'
CREATE TRIGGER TR_' + #tableName + N' ON ' + #tableName + N' FOR INSERT
AS
BEGIN
PRINT #tableName
END';
EXEC sp_executesql #sql, N'#tableName sysname', #tableName=#tableName
When running the above, I get an error:
Msg 156, Level 15, State 1, Line 2
Incorrect syntax near the keyword 'TRIGGER'.
After trying I few things, I've discovered that even if I don't use #tableName in the dynamic SQL at all, I still get this error. And I also get this error trying to create a PROCEDURE (except, obviously, the message is Incorrect syntax near the keyword 'PROCEDURE'.)
Since the SQL runs fine either directly or when not supplying parameters to sp_executesql, this seems like I'm running into a true limitation in the SQL engine, but I don't see it documented anywhere. Does anyone know if there is a way to accept to a dynamic CREATE script, or at least have insight into the underlying limitation that's being run into?
Update
I can add a PRINT statement, and get the below SQL, which is valid, and runs successfully (when run directly). I still get the error if there's nothing dynamic in the SQL (it's just a single string with no concatenation).
CREATE TRIGGER TR_ContentItems ON ContentItems FOR INSERT
AS
BEGIN
PRINT #tableName
END
I also get the same error whether using sysname or nvarchar(max) for the parameter.
If you execute your create trigger statement that you said you printed... you will find that it does not work. The print statement in the body of the trigger is trying to output #tablename, but is never defined, so you will get an error:
Must declare the scalar variable "#tableName".
But that is not your main issue. As for why you can't seem to execute a DDL statement with execute_sql with parameters, I couldn't find any documentation to explain why... but your experience and others proves that it's troublesome. I believe this post has a pretty good theory: sp_executesql adds statements to executed dynamic script?
You can however execute dynamic sql with DDL statements using the EXECUTE statement. So what you could do is create a parameterized sp_executesql statement that validates your table name and then creates a dynamic sql string to execute with the EXECUTE statement.
It doesn't look pretty, but it works:
DECLARE #tableName sysname = 'MyTable';
DECLARE #sql nvarchar(max) =
N'
set #tableName = (SELECT name FROM sys.tables WHERE OBJECT_ID = OBJECT_ID(#tableName)) --validate table
DECLARE #CreateTriggerSQL as varchar(max) =
''
CREATE TRIGGER '' + QUOTENAME(''TR_'' + #tableName) + '' ON '' + QUOTENAME( #tableName) + '' FOR INSERT
AS
BEGIN
PRINT '''''' + #tableName + ''''''
END
''
print isnull(#CreateTriggerSQL, ''INVALID TABLE'')
exec (#CreateTriggerSQL)
';
EXEC sp_executesql #sql, N'#tableName sysname', #tableName=#tableName;
You could also convert this into a stored procedure with parameters instead of running sp_executesql if that were more convenient. It looks a bit cleaner:
CREATE PROCEDURE sp_AddTriggerToTable (#TableName AS sysname) AS
set #tableName = (SELECT name FROM sys.tables WHERE OBJECT_ID = OBJECT_ID(#tableName)) --validate table
DECLARE #CreateTriggerSQL as varchar(max) =
'
CREATE TRIGGER ' + QUOTENAME('TR_' + #tableName) + ' ON ' + QUOTENAME( #tableName) + ' FOR INSERT
AS
BEGIN
PRINT ''' + #tableName + '''
END
'
print isnull(#CreateTriggerSQL, 'INVALID TABLE')
exec (#CreateTriggerSQL)
GO
I would strongly caution against using Dynamic SQL with table names. You are setting yourself up for some serious SQL Injection issues. You should validate anything that goes into the #tableName variable.
That said, in your example...
DECLARE #tableName sysname = 'ContentItems';
DECLARE #sql nvarchar(max) = N'
CREATE TRIGGER TR_' + #tableName + N' ON ' + #tableName + N' FOR INSERT
AS
BEGIN
PRINT #tableName
END';
EXEC sp_executesql #sql, N'#tableName sysname', #tableName=#tableName
... you are trying to input your declared #tableName into the text you're creating for #sql, and then you're trying to pass a parameter through spexecutesql. This makes your #sql invalid when trying to call it.
You can try:
DECLARE #tableName sysname = 'ContentItems';
DECLARE #sql nvarchar(max) = N'
CREATE TRIGGER TR_'' + #tableName + N'' ON '' + #tableName + N'' FOR INSERT
AS
BEGIN
PRINT #tableName
END';
EXEC sp_executesql #sql, N'#tableName sysname', #tableName=#tableName
... which will give you the string ...
'
CREATE TRIGGER TR_' + #tableName + N' ON ' + #tableName + N' FOR INSERT
AS
BEGIN
PRINT #tableName
END'
... which can then accept the parameter you pass through ...
EXEC sp_executesql #sql, N'#tableName sysname', #tableName=#tableName ;
Again, I'd use some heavy validation (and white-listing) before passing anything into dynamic SQL that will use a dynamic table name.
NOTE: As noted below, I believe you are limited on DML statements that can be executed with sp_executesql(), and I think parameterization is limited also. And based on your other comments, it doesn't sound like you're really needing a dynamic process but a way to repeat a specific task for a handful of elements. If that's the case, my recommendation is to do it manually with a copy/paste then execute the statements.
Since the SQL runs fine either directly or when not supplying
parameters to sp_executesql, this seems like I'm running into a true
limitation in the SQL engine, but I don't see it documented anywhere.
This behavior is documented, albeit not intuitive. The relevant excerpt from the documentation under the trigger limitations topic:
CREATE TRIGGER must be the first statement in the batch
When you execute a parameterized query, the parameter declarations are counted as being part of the batch. Consequently, a CREATE TRIGGER batch (and other CREATE statements for programmability objects like procs, functions, etc.) cannot be executed as a parameterized query.
The invalid syntax error message you get when you attempt to run CREATE TRIGGER as a parameterized query isn't particularly helpful. Below is an simplified version of your code using the undocumented and unsupported internal parameterized query syntax.
EXECUTE(N'(#tableName sysname = N''MyTable'')CREATE TRIGGER TR_MyTable ON dbo.MyTable FOR INSERT AS');
This at least yields an error calling out the CREATE TRIGGER limitation:
Msg 1050, Level 15, State 1, Line 73 This syntax is only allowed for
parameterized queries. Msg 111, Level 15, State 1, Line 73 'CREATE
TRIGGER' must be the first statement in a query batch.
Similarly executing another parameterized statement with this method runs successfully:
EXECUTE (N'(#tableName sysname = N''MyTable'')PRINT #tableName');
But if you don't actually use the parameter in the batch, an error results
EXECUTE (N'(#tableName sysname = N''MyTable'')PRINT ''done''');
Msg 1050, Level 15, State 1, Line 75 This syntax is only allowed for
parameterized queries.
The bottom line is that you need to build the CREATE TRIGGER statement as a string without parameters and execute the statement as a non-parameterized query to create a trigger.
Is it possible to issue CREATE statements using sp_executesql with
parameters?
Simple answer is "No", you can't
According to MSDN
Generally, parameters are valid only in Data Manipulation Language
(DML) statements, and not in Data Definition Language (DDL) statements
You can check more details about this Statement Parameters
What is the issue?
Parameters are only allowed in place of scalar literals, like quoted strings or dates, or numeric values. You can't parameterise a DDL operation.
What can be done?
I believe that you want to use parameterized sp_executesql is to avoid any SQL Injection Attack. To achieve this for the DDL operations you can do following thing to minimize the possibility of attack.
Use Delimiters : You can use QUOTENAME() for SYSNAME parameters like Trigger Name, Table Names and Column names.
Limiting Permissions : User Account you are using to run the dynamic DDL, should have only limited permission. Like on a
specific schema with only CREATE permission.
Hiding Error Message : Don't throw the actual error to the user. SQL Injection are mainly performed by trial and error approach. If
you hide the actual error message, it will become tough to crack it.
Input Validation : You can always have a function which validates the input string, escape the required characters, check
for specific keywords like DROP.
Any workaround?
If you want to parameterized your statement using sp_executesql, in that case you can get the query to be executed in a OUTPUT variable and run the query in next statement like following.
By this, the first call to sp_executesql will parameterized your query, and the actual execution will be performed by the second call to sp_executesql
For example.
DECLARE #TableName VARCHAR(100) = 'MyTable'
DECLARE #returnStatement NVARCHAR(max);
DECLARE #sql1 NVARCHAR(max)=
N'SELECT #returnStatement = ''CREATE TRIGGER TR_''
+ #TableName + '' ON '' + #TableName + '' FOR INSERT AS BEGIN PRINT 1 END'''
EXEC Sp_executesql
#sql1,
N'#returnStatement VARCHAR(MAX) OUTPUT, #TableName VARCHAR(100)',
#returnStatement output,
#TableName
EXEC Sp_executesql #returnStatement
Is it possible to issue CREATE statements using sp_executesql with
parameters?
The answer is "Yes", but with small adjustment:
USE msdb
DECLARE #tableName sysname = 'sysjobsteps';
DECLARE #sql nvarchar(max) = N'
EXECUTE ('' -- Added nested EXECUTE()
CREATE TRIGGER [TR_'' + #tableName + N''] ON ['' + #tableName + N''] FOR INSERT
AS
BEGIN
PRINT '''''+#tableName+'''''
END''
)' -- End of EXECUTE()
EXEC sp_executesql #sql, N'#tableName sysname', #tableName=#tableName
Adjsutments list:
Extra EXECUTE involved, comment below explains why
Extra square brackets added to make SQL Injections slightly harder
I'm looking for specific (ideally, documented) restrictions of
sp_executesql with parameters and if there are any workarounds for
those specific restrictions (beyond not using parameters)
in this case it is a limitation of DDL commands, not sp_executesql. DDL statements cannot be parametrized using variables. Microsoft documentation says:
Variables can be used only in expressions, not in place of object
names or keywords. To construct dynamic SQL statements, use EXECUTE.
source: DECLARE (Transact-SQL)
Therefore, the solution with EXECUTE is provided by me as a workaround
Personally I hate triggers and try to avoid them most of the time ;)
However if you really, really need this dynamic stuff you should use sp_MSforeachtable and avoid injection (as pointed out by Shawn) at any cost:
EXEC sys.sp_MSforeachtable
#command1 = '
DECLARE #sql NVARCHAR(MAX)
SET #sql = CONCAT(''CREATE TRIGGER TR_''
, REPLACE(REPLACE(REPLACE(''?'', ''[dbo].'', ''''),''['',''''),'']'','''')
, '' ON ? FOR INSERT
AS
BEGIN
PRINT ''''?'''';
END;'');
EXEC sp_executesql #sql;'
, #whereand = ' AND object_id IN (SELECT object_id FROM sys.objects
WHERE name LIKE ''%ContentItems%'')';
If you want to use the parameter as string, add double ' before and after the parameter name
like this :
DECLARE #tableName sysname = 'ContentItems';
DECLARE #sql nvarchar(max) = N'
CREATE TRIGGER TR_' + #tableName + N' ON ' + #tableName + N' FOR INSERT
AS
BEGIN
print ''' + #tableName
+''' END';
EXEC sp_executesql #sql
And if you want to use it as table name, use select instead of print ,
like this :
DECLARE #tableName sysname = 'ContentItems';
DECLARE #sql nvarchar(max) = N'
CREATE TRIGGER TR_' + #tableName + N' ON ' + #tableName + N' FOR INSERT
AS
BEGIN
select * from ' + #tableName
+' END';
EXEC sp_executesql #sql

Use Stored Procedure To Create View

I want to create a stored procedure which I can pass a parameter to for the database name and it will create a view for me.
I am just trying to save some time by not writing the same statement over and over and over for a create vew.
Below is my syntax - how could this be modified to run in a stored procedure accepting a parameter?
Alter View dbo.ForceClose
As
SELECT DISTINCT(SessionID) As CountofSessionID
FROM Database1
WHERE forceClosed IS NOT NULL
AND stillOpen IS NULL
and (userName is not null or userName IN ('JJones', 'MHill', 'RMort'))
Go
And in the stored procedure accept a parameter as the database name (I know this isn't valid just trying to show an example) -- call the stored procedure like so
exec dbo.Procedure 'DBName'
And the stored procedure would then look like
#DBName varchar(100)
Select blah blah FROM' + #DBName + '
You mean this?
CREATE PROCEDURE dbo.ForceClose
(
#DBNAME NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #SQL AS NVARCHAR(255)
#SQL='SELECT DISTINCT(SessionID) As CountofSessionID
FROM ['+#DBNAME+'].[SCHEMA].[TABLE_NAME]
WHERE forceClosed IS NOT NULL
AND stillOpen IS NULL
and (userName is not null or userName IN (''JJones'', ''MHill'', ''RMort''))'
EXEC (#SQL)
END
And you can run it by:
EXEC ForceClose <DBNAME>
With the View:
CREATE PROCEDURE dbo.ForceClose
(
#DBNAME NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #SQL AS NVARCHAR(255)
#SQL='CREATE VIEW VIEW_'+DBNAME+' AS SELECT DISTINCT(SessionID) As CountofSessionID
FROM ['+#DBNAME+'].[SCHEMA].[TABLE_NAME]
WHERE forceClosed IS NOT NULL
AND stillOpen IS NULL
and (userName is not null or userName IN (''JJones'', ''MHill'', ''RMort''))'
EXEC (#SQL)
END
And you can run it by:
SELECT * FROM VIEW_<DBNAME>
Im not sure what the create view is doing; the basic premise you want is dynamic SQL (and there are lots of good questions and answers on the subject. A really simple answer would be
declare #myparameter nvarchar(100)= 'master'
declare #myquery nvarchar(1000)
select #myquery = 'select * from ' + #myparameter + '.dbo.sysdatabases'
select #myquery
exec sp_executeSQL #myquery
Running this returns a list of the databases on your server.
If you want to create a view; would you not need to know the table to query? The basic technique is the same
declare #myparameter nvarchar(100)= 'master'
declare #myquery nvarchar(1000)
select #myquery = 'Create View myschema.vw' + #myparameter + ' as select * from ' + #myparameter + '.dbo.sysdatabases'
select #myquery
exec sp_executeSQL #myquery
If this is in an application the user permissions to do this would be very high for a general application; you might want to wrap it with an execute as permission to stop people doing too much damage.

SQL Server Select-Into stored procedure

I am trying to write a custom stored procedure to carry out a select into operation. I want to copy a table (or some columns from a table) from one database to another. I am using SQL Server 2012
CREATE Procedure select_into
AS
Begin
#selection varchar(128),
#newtabname varchar(128)
#fromtabname varchar(128)
Select selection,
INTO table1,
FROM table2,
WHERE selection = #selection AND table1 = #newtabname AND table2 =#fromtabname;
go
EXEC select_into, Ecode, relational_db.dbo.work, dbo.Work_Data;
I get an error message indicating a syntax error near the "." in relational_db.dbo.work.
I would appreciate any help in getting this right
You have a missing comma in parameter list and wrong syntax for procedure declaration. It should be::
CREATE Procedure select_into
(
#selection varchar(128),
#newtabname varchar(128),
#fromtabname varchar(128)
)
AS
Begin
BUT, in addition your syntax for an INSERT INTO contains extra commas and you cannot perform dynamic T-SQL that way.
Can I suggest you first learn TSQL's syntax for SQL Server.
Try something like this ...
CREATE Procedure select_into
#selection NVARCHAR(128),
#newtabname NVARCHAR(128),
#fromtabname NVARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'Select ' + QUOTENAME(#selection) +
N' INTO ' + QUOTENAME(#newtabname) +
N' FROM ' + QUOTENAME(#fromtabname)
EXECUTE sp_executesql #sql
END

sql use statement with variable

I'm trying to switch the current database with a SQL statement.
I have tried the following, but all attempts failed:
USE #DatabaseName
EXEC sp_sqlexec #Sql -- where #Sql = 'USE [' + #DatabaseName + ']'
To add a little more detail.
EDIT: I would like to perform several things on two separate database, where both are configured with a variable. Something like this:
USE Database1
SELECT * FROM Table1
USE Database2
SELECT * FROM Table2
The problem with the former is that what you're doing is USE 'myDB' rather than USE myDB.
you're passing a string; but USE is looking for an explicit reference.
The latter example works for me.
declare #sql varchar(20)
select #sql = 'USE myDb'
EXEC sp_sqlexec #Sql
-- also works
select #sql = 'USE [myDb]'
EXEC sp_sqlexec #Sql
exec sp_execsql #Sql
The DB change only lasts for the time to complete #sql
http://blog.sqlauthority.com/2007/07/02/sql-server-2005-comparison-sp_executesql-vs-executeexec/
I have the same problem, I overcame it with an ugly -- but useful -- set of GOTOs.
The reason I call the "script runner" before everything is that I want to hide the complexity and ugly approach from any developer that just wants to work with the actual script. At the same time, I can make sure that the script is run in the two (extensible to three and more) databases in the exact same way.
GOTO ScriptRunner
ScriptExecutes:
--------------------ACTUAL SCRIPT--------------------
-------- Will be executed in DB1 and in DB2 ---------
--TODO: Your script right here
------------------ACTUAL SCRIPT ENDS-----------------
GOTO ScriptReturns
ScriptRunner:
USE DB1
GOTO ScriptExecutes
ScriptReturns:
IF (db_name() = 'DB1')
BEGIN
USE DB2
GOTO ScriptExecutes
END
With this approach you get to keep your variables and SQL Server does not freak out if you happen to go over a DECLARE statement twice.
Just wanted to thank KM for his valuable solution.
I implemented it myself to reduce the amount of lines in a shrinkdatabase request on SQLServer.
Here is my SQL request if it can help anyone :
-- Declare the variable to be used
DECLARE #Query varchar (1000)
DECLARE #MyDBN varchar(11);
-- Initializing the #MyDBN variable (possible values : db1, db2, db3, ...)
SET #MyDBN = 'db1';
-- Creating the request to execute
SET #Query='use '+ #MyDBN +'; ALTER DATABASE '+ #MyDBN +' SET RECOVERY SIMPLE WITH NO_WAIT; DBCC SHRINKDATABASE ('+ #MyDBN +', 1, TRUNCATEONLY); ALTER DATABASE '+ #MyDBN +' SET RECOVERY FULL WITH NO_WAIT'
--
EXEC (#Query)
try this:
DECLARE #Query varchar(1000)
DECLARE #DatabaseName varchar(500)
SET #DatabaseName='xyz'
SET #Query='SELECT * FROM Server.'+#DatabaseName+'.Owner.Table1'
EXEC (#Query)
SET #DatabaseName='abc'
SET #Query='SELECT * FROM Server.'+#DatabaseName+'.Owner.Table2'
EXEC (#Query)
I case that someone need a solution for this, this is one:
if you use a dynamic USE statement all your query need to be dynamic, because it need to be everything in the same context.
You can try with SYNONYM, is basically an ALIAS to a specific Table, this SYNONYM is inserted into the sys.synonyms table so you have access to it from any context
Look this static statement:
CREATE SYNONYM MASTER_SCHEMACOLUMNS FOR Master.INFORMATION_SCHEMA.COLUMNS
SELECT * FROM MASTER_SCHEMACOLUMNS
Now dynamic:
DECLARE #SQL VARCHAR(200)
DECLARE #CATALOG VARCHAR(200) = 'Master'
IF EXISTS(SELECT * FROM sys.synonyms s WHERE s.name = 'CURRENT_SCHEMACOLUMNS')
BEGIN
DROP SYNONYM CURRENT_SCHEMACOLUMNS
END
SELECT #SQL = 'CREATE SYNONYM CURRENT_SCHEMACOLUMNS FOR '+ #CATALOG +'.INFORMATION_SCHEMA.COLUMNS';
EXEC sp_sqlexec #SQL
--Your not dynamic Code
SELECT * FROM CURRENT_SCHEMACOLUMNS
Now just change the value of #CATALOG and you will be able to list the same table but from different catalog.
If SQLCMD is an option, it supports scripting variables above and beyond what straight T-SQL can do. For example: http://msdn.microsoft.com/en-us/library/ms188714.aspx
You can do this:
Declare #dbName nvarchar(max);
SET #dbName = 'TESTDB';
Declare #SQL nvarchar(max);
select #SQL = 'USE ' + #dbName +'; {can put command(s) here}';
EXEC (#SQL);
{but not here!}
This means you can do a recursive select like the following:
Declare #dbName nvarchar(max);
SET #dbName = 'TESTDB';
Declare #SQL nvarchar(max);
SELECT #SQL = 'USE ' + #dbName + '; ' +(Select ... {query here}
For XML Path(''),Type)
.value('text()[1]','nvarchar(max)');
Exec (#SQL)
Use exec sp_execsql #Sql
Example
DECLARE #sql as nvarchar(100)
DECLARE #paraDOB datetime
SET #paraDOB = '1/1/1981'
SET #sql=N'SELECT * FROM EmpMast WHERE DOB >= #paraDOB'
exec sp_executesql #sql,N'#paraDOB datetime',#paraDOB
-- If you are using a variable for the database name.
-- Try something like this.
DECLARE #DBName varchar(50)
Set #DBName = 'Database1'; /* could be passed in by a parameter. */
IF( #DBName = 'Database1')
Begin
USE [Database1];
SELECT FROM Table1;
End
IF( #DBName = 'Database2')
Begin
USE [Database2];
SELECT FROM Table2;
End
IF( #DBName is null)
Begin
USE [Database1];
End

Resources