How to pass a database name as a parameter in SQL Server - sql

USE master
GO
DECLARE #DbName nvarchar(MAX)
SET #DbName = N'DataBase'
ALTER DATABASE #DbName
SET SINGLE_USER WITH ROLLBACK IMMEDIATE
ALTER DATABASE #DbName SET OFFLINE WITH NO_WAIT
GO
ALTER DATABASE #DbName SET ONLINE
GO
ALTER DATABASE #DbName
SET MULTI_USER
GO
I know i can use EXEC but it's a bit ugly....

It is impossible to use DB name from variable.
Use Dynamic Querying, even if it is ugly.

You can't use the database name in a variable.
You have several options:
Different DML scripts for each DB
Dynamic SQL

Firstly, you can't parameterise DDL statements like this. Secondly, GO is a batch terminator and parameters won't be available after this.

I don't recall if MSSqlServer allows the same flexibility as Oracle and MySQL, but in those you can set the default database for each connection. If the queries and statements do not specify a database (use (dbname)), it uses the default. Perhaps that is sufficient parametrization for your purposes?

Related

SET statement with sp_msforeachdb

does anybody know why this script won't work?
EXECUTE sp_msforeachdb 'USE ?
IF DB_NAME() NOT IN(''master'',''msdb'',''tempdb'',''model'',''ReportServer'')
ALTER DATABASE ? SET AUTO_CLOSE OFF'
It executes fine, but does not exclude master and tempdb.
So the result is this:
Option 'AUTO_CLOSE' cannot be set in database 'master'.
Option 'AUTO_CLOSE' cannot be set in database 'tempdb'.
No idea, but sp_msforeachdb is undocumented and famously unreliable. Use something else instead, eg A reliable and flexible replacement for sp_MSforeachdb.

How can i use master db in stored procedures

I'm trying to create restore db proc. I encountered a problem because i cannot use the command 'use master'. I have try with dynamic SQL but there is no result:
My code:
alter proc dbo.RestoreDB
(
#location as varchar(4000)
)
as
begin
declare #setMasterDb as varchar(400) = 'use master'
exec (#setMasterDb);
ALTER DATABASE [testDb] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
RESTORE DATABASE [testDb] FROM DISK = #location WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 5
ALTER DATABASE [testDb] SET MULTI_USER
end
GO
Is there workaround?
Switching database contexts (USE someDBName) in the middle of a Stored Proc (or function) is not allowed. Also, you do not need to be pointed at the master db context to run a BACKUP/RESTORE, you can be pointed to almost any DB. To fix your issue, just remove your DB switching and point your query window any DB except the one you want to restore.
EDIT: Updated to point to any DB EXCEPT the one you're trying to restore. Thanks to #DMason for that comment.

Change a SQL Server 2008 R2 database collation

I have created a database and I forgot to set its collation. So all my chars are like ???? in it. The default one is SQL_Latin1_General_CP1_CI_AS and I want to change it to Persian_100_CI_AS.
I used this SQL statement:
USE master;
GO
ALTER DATABASE land_gis
COLLATE Persian_100_CI_AS ;
GO
But I get this error :
Msg 5030, Level 16, State 2, Line 1
The database could not be exclusively locked to perform the operation.
Msg 5072, Level 16, State 1, Line 1
ALTER DATABASE failed. The default collation of database 'land_gis' cannot be
set to Persian_100_CI_AS.
I can not drop and rebuild database. Is there any way to change it?
Thanks a lot
By the way, I'm using SQL Server 2008 R2.
Seems like your database is in use - if you're confident that you'll do no harm - you can use this code to get exclusive access:
USE master;
GO
ALTER DATABASE land_gis
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
ALTER DATABASE land_gis
COLLATE Persian_100_CI_AS ;
GO
Then your ALTER DATABASE COLLATE call should work .
WARNING: this call to SET SINGLE_USER WITH ROLLBACK IMMEDIATE will disconnect anyone who might be connected to that database without warning, without chance of saving data! USE WITH CAUTION! especially in production environments!!
You can use sp_lock then find the spid associated with concerned DB and kill them (but first you can check them whats running behind them by
DBCC inputbuffer(spid))
USE master;
GO
ALTER DATABASE land_gis
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
ALTER DATABASE land_gis
COLLATE Persian_100_CI_AS ;
GO

SQL Script to take a Microsoft Sql database online or offline?

If I wish to take an MS Sql 2008 offline or online, I need to use the GUI -> DB-Tasks-Take Online or Take Offline.
Can this be done with some sql script?
ALTER DATABASE database-name SET OFFLINE
If you run the ALTER DATABASE command whilst users or processes are connected, but you do not wish the command to be blocked, you can execute the statement with the NO_WAIT option. This causes the command to fail with an error.
ALTER DATABASE database-name SET OFFLINE WITH NO_WAIT
Corresponding online:
ALTER DATABASE database-name SET ONLINE
-- Take all user databases offline
CREATE PROCEDURE SP_TakeOfflineAllDatabase AS
BEGIN
DECLARE #db sysname, #q varchar(max);
DECLARE cur_db CURSOR FOR
SELECT name FROM sys.databases WHERE owner_sid<>0x01;
OPEN cur_db;
WHILE 1=1
BEGIN
FETCH NEXT FROM cur_db INTO #db;
IF ##FETCH_STATUS <> 0
BREAK;
SET #q = N'ALTER DATABASE [' + #db + N'] SET OFFLINE WITH NO_WAIT';
EXEC(#q);
END;
CLOSE cur_db;
DEALLOCATE cur_db;
END;
Restart the server before run the procedure. It will close the existed connections to the databases.
I know this is an old post but, just in case someone comes across this solution and would prefer a non cursor method which does not execute but returns the scripts.
I have just taken the previous solution and converted it into a select that builds based on results.
DECLARE #SQL VARCHAR(8000)
SELECT #SQL=COALESCE(#SQL,'')+'ALTER DATABASE '+name+ N' SET OFFLINE WITH NO_WAIT;
'
FROM sys.databases
WHERE owner_sid<>0x01
PRINT #SQL
Here's a note that just might be very usefull to you :
It's almost always possible to see what the GUI is doing TSQLwise behind the scenes.
c : http://www.mssqltips.com/tip.asp?tip=1505

How do I run SQL queries on different databases dynamically?

I have a sql server stored procedure that I use to backup data from our database before doing an upgrade, and I'd really like it to be able to run the stored procedure on multiple databases by passing in the database name as a parameter. Is there an easy way to do this? The best I can figure is to dynamically build the sql in the stored procedure, but that feels like its the wrong way to do it.
build a procedure to back up the current database, whatever it is. Install this procedure on all databases that you want to backup.
Write another procedure that will launch the backups. This will depend on things that you have not mentioned, like if you have a table containing the names of each database to backup or something like that. Basically all you need to do is loop over the database names and build a string like:
SET #ProcessQueryString=
'EXEC '+DatabaseServer+'.'+DatabaseName+'.dbo.'+'BackupProcedureName param1, param2'
and then just:
EXEC (#ProcessQueryString)
to run it remotely.
There isn't any other way to do this. Dynamic SQL is the only way; if you've got strict controls over DB names and who's running it, then you're okay just truncating everything together, but if there's any doubt use QUOTENAME to escape the parameter safely:
CREATE PROCEDURE doStuff
#dbName NVARCHAR(50)
AS
DECLARE #sql NVARCHAR(1000)
SET #sql = 'SELECT stuff FROM ' + QUOTENAME(#dbName) + '..TableName WHERE stuff = otherstuff'
EXEC sp_ExecuteSQL (#sql)
Obviously, if there's anything more being passed through then you'll want to double-check any other input, and potentially use parameterised dynamic SQL, for example:
CREATE PROCEDURE doStuff
#dbName NVARCHAR(50)
#someValue NVARCHAR(10)
AS
DECLARE #sql NVARCHAR(1000)
SET #sql = 'SELECT stuff FROM ' + QUOTENAME(#dbName) + '..TableName WHERE stuff = #pOtherStuff'
EXEC sp_ExecuteSQL (#sql, '#pOtherStuff NVARCHAR(10)', #someValue)
This then makes sure that parameters for the dynamic SQL are passed through safely and the chances for injection attacks are reduced. It also improves the chances that the execution plan associated with the query will get reused.
personally, i just use a batch file and shell to sqlcmd for things like this. otherwise, building the sql in a stored proc (like you said) would work just fine. not sure why it would be "wrong" to do that.
best regards,
don
MSSQL has an OPENQUERY(dbname,statement) function where if the the server is linked, you specify it as the first parameter and it fires the statement against that server.
you could generate this openquery statement in a dynamic proc. and either it could fire the backup proc on each server, or you could execute the statement directly.
Do you use SSIS? If so you could try creating a couple ssis packages and try scheduling them,or executing them remotely.