Drop database only if Backup is successful - sql

This might be an easy one for some one but I haven't found a simple solution yet.
I'm automating a larger process at the moment, and one step is to back up then drop the database, before recreating it from scratch.
I've got a script that will do the back up and drop as follows:
Use [Master]
BACKUP DATABASE [databaseName]
TO DISK='D:\Backup\databaseName\20100122.bak'
ALTER DATABASE [databaseName]
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE
DROP DATABASE [databaseName]
but I'm worried that the DROP will happen even if the BACKUP fails.
How can I change the script so if the BACKUP fails, the DROP won't happen?
Thanks in advance!

If your SQL Server version is 2005 or greater, you can wrap your statements with a try catch. If the backup fails, it will jump to the catch without dropping the database...
Use [Master]
BEGIN TRY
BACKUP DATABASE [databaseName]
TO DISK='D:\Backup\databaseName\20100122.bak'
ALTER DATABASE [databaseName]
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE
DROP DATABASE [databaseName]
END TRY
BEGIN CATCH
PRINT 'Unable to backup and drop database'
END CATCH

You can catch any error codes that occur with the SQL server error variable as follows. A zero indicates no error occurred. Note that the value is set every time a T-SQL statement is executed, so you need to catch it as soon as you have backed up:
USE [Master]
DECLARE #errorCode int
BACKUP DATABASE [databaseName]
TO DISK='D:\Backup\databaseName\20100122.bak'
SET #errorCode = ##ERROR
IF (#errorCode = 0)
BEGIN
ALTER DATABASE [databaseName]
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE
DROP DATABASE [databaseName]
END
This is the simplest way I can think of, as well as allowing you to catch known error codes and handle them differently if you need to. SELECT * FROM master.sys.messages gives you a list of all known error codes and messages if you want to take it further.

Related

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.

How to drop a database when it's currently in use?

NB. I don't want to mark the check box in the wizard for deletion. This question's strictly about scripting the behavior.
When I run the following script to get a fresh start, I get the error that the database Duck can't be deleted because it's currently in use.
use Master
drop database Duck
drop login WorkerLogin
drop login AdminLogin
go
Be that as it may (even though I'm the only user currently in the system and I run no other queries but that's another story), I need to close all the existing connections. One way is to wait it out or restart the manager. However I'd like to script in that behavior so I can tell the stubborn server to drop the duck down. (Yes, "typo" intended.)
What do I need to add to the dropping statement?
Try below code.
USE master;
ALTER DATABASE [Duck] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [Duck] ;
For deep discussion see this answer.
You have to kill first all active connections before you can drop the database.
ALTER DATABASE YourDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--do you stuff here
ALTER DATABASE YourDatabase SET MULTI_USER
http://wiki.lessthandot.com/index.php/Kill_All_Active_Connections_To_A_Database
How do you kill all current connections to a SQL Server 2005 database?
if you're ssms tab is not currently on the db to be dropped (meaning you are in the master db), then these will help:
https://dba.stackexchange.com/questions/2387/sql-server-cannot-drop-database-dbname-because-it-is-currently-in-use-but-n
https://dba.stackexchange.com/questions/34264/how-to-force-drop-database-in-sql-server-2008

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 deadlocking..in single user mode now

Couple of databases produced an error this morning whilst running in Single User Mode. Due to the following error I am unable to do anything :(
Msg 1205, Level 13, State 68, Line 1
Transaction (Process ID 62) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
I receive that error when trying the following (using the Master Database as a Sys Admin):
ALTER DATABASE dbname
SET MULTI_USER;
GO
For the sake of it I have tried Restarting the SQL Server, I have tried killing any processes and I have even tried resetting the single user myself:
ALTER DATABASE dbname
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
The job which was running was designed to copy the database and put it in single user mode immediately to try and make it faster.
Anyway I can remove the locks?
Had the same problem. This worked for me:
set deadlock_priority high; -- could also try "10" instead of "high" (5)
alter database dbname set multi_user; -- can also add "with rollback immediate"
From ideas/explanation:
http://myadventuresincoding.wordpress.com/2014/03/06...
http://www.sqlservercentral.com/blogs/pearlknows/2014/04/07/...
Ok, I will answer my own.
I had to use the following:
sp_who
which displayed details of the current connected users and sessions, I then remembered about Activity Monitor which shows the same sort of stuff...Anyway that led me away from my desk to some bugger who had maintained connections to the database against my wishes...
Anyway once I had shut the PC down (by unplugging it...deserved it) I could then run the SQL to amend it into MULTI_USER mode (using system admin user):
USE Master
GO
ALTER DATABASE dbname
SET MULTI_USER;
GO
FYI for those who care, this can be used to immediately set the DB to SINGLE_USER:
ALTER DATABASE dbname
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
Further details, if you know the process id you can use kill pid:
kill 62
Bare in mind SSMS creates a process for your user as well, in my case this was being rejected due to another.
EDIT: As Per Bobby's recommendations we can use:
sp_Who2
This can show us which process is blocked by the other process.
tanks a lot.
SET DEADLOCK_PRIORITY HIGH ---- could also try "10" instead of "high" (5)
GO
ALTER DATABASE SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE SET MULTI_USER
GO
When related system processes are at dead block scenario.
SPID 15 & SPID 29 - both are background SysProcesses.
This helps in such cases:
--------- START OF CMDs--------
SET DEADLOCK_PRIORITY HIGH ---- could also try "10" instead of "high" (5)
GO
ALTER DATABASE <dbname> SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE <dbname> SET MULTI_USER
GO
-------------------------- END OF CMDs ------------------
Blocking Case with an User DB RESTORE process putting DB in Single_User

Bulletproof way to DROP and CREATE a database under Continuous Integration

I am attempting to drop and recreate a database from my CI setup. But I'm finding it difficult to automate the dropping and creation of the database, which is to be expected given the complexities of the db being in use. Sometimes the process hangs, errors out with "db is currently in use" or just takes too long. I don't care if the db is in use, I want to kill it and create it again. Does some one have a straight shot method to do this? alternatively does anyone have experience dropping all objects in the db instead of dropping the db itself?
USE master
--Create a database
IF EXISTS(SELECT name FROM sys.databases
WHERE name = 'mydb')
BEGIN
ALTER DATABASE mydb
SET SINGLE_USER --or RESTRICTED_USER
--WITH ROLLBACK IMMEDIATE
DROP DATABASE uAbraham_MapSifterAuthority
END
CREATE DATABASE mydb;
We use Hudson to rebuild staging sites for our QA team all the time. We kill connections, drop the database, then restore/rebuild/remigrate a DB.
This is what I use to kill connections so I can drop a DB.
USE MASTER
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_KillDatabaseProcesses]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[sp_KillDatabaseProcesses]
GO
CREATE PROCEDURE dbo.sp_KillDatabaseProcesses(#databaseName varchar(100))
AS
DECLARE #databaseId int,
#sysProcessId int,
#cmd varchar(1000)
EXEC ('USE MASTER')
SELECT #databaseId = dbid FROM master..sysdatabases
WHERE [name] = #databaseName
DECLARE sysProcessIdCursor CURSOR FOR
SELECT spid FROM [master]..[sysprocesses] WHERE [dbid] = #databaseId
OPEN sysProcessIdCursor
FETCH NEXT FROM sysProcessIdCursor INTO #sysProcessId WHILE ##fetch_status = 0
BEGIN
SET #cmd = 'KILL '+ convert(nvarchar(30),#sysProcessId)
PRINT #cmd
EXEC(#cmd)
FETCH NEXT FROM sysProcessIdCursor INTO #sysProcessId
END
DEALLOCATE sysProcessIdCursor
GO
Setting single user with rollback immediate is the typical way of kicking everyone out before a drop.
But I'm a bit surprised that your CI drops the DB and creates it in the same script. Normally the CI should deploy the database, using the deploy script/methods of your build deliverable, just as a customer would do it. But you can't seriously have a deployment script that drops the database on the customer deployment. Usually the CI has a step to cleanup/flatten the test server, and then run the build deliverable setup process, which will deploy the database. And you should also have a story for upgrade scenarios, perhaps using an application metadata version upgrade step.