I am attempting to automate restoring .bak files on a secondary database in the case of a primary server failure. Both servers are SQL server 2014.
Here is a sample SQL script:
USE master
GO
DECLARE @DBName varchar(50)
DECLARE @BackupFile varchar(256)
Set @DBName = 'test-db'
Set @BackupFile = 'D:\MSSQL\Backups\test-db\test-db_backup_2016_03_18_001622_2611392.bak'
-- Find Logical and Physical file names
declare @LogicalDataFile sysname
, @LogicalLogFile sysname
, @PhysicalDataFile nvarchar(260)
, @PhysicalLogFile nvarchar(260)
-- Data file
select @LogicalDataFile = name
, @PhysicalDataFile = physical_name
from sys.master_files
where database_id = db_id(@DBName)
and type_desc = 'ROWS'
-- Log file
select @LogicalLogFile = name
, @PhysicalLogFile = physical_name
from sys.master_files
where database_id = db_id(@DBName)
and type_desc = 'LOG'
-- Print variables
Print 'Logical Data File: ' + @LogicalDataFile
Print 'Logical Log File: ' + @LogicalLogFile
Print 'Physical Data File: ' + @PhysicalDataFile
Print 'Physical Log File: ' + @PhysicalLogFile
-- Set as single user mode
EXEC('ALTER DATABASE [' + @DBName
+ '] SET SINGLE_USER
WITH ROLLBACK IMMEDIATE')
--DB that will be over written
RESTORE DATABASE [@DBName]
--Restore file with data
FROM DISK = @BackupFile
WITH MOVE @LogicalDataFile TO @PhysicalDataFile,
MOVE @LogicalLogFile TO @PhysicalLogFile,
REPLACE,
STATS=10
-- Return to multi-user mode
EXEC('ALTER DATABASE [' + @DBName
+ '] SET MULTI_USER')
When I run the above script I get the following output:
Logical Data File: test-db
Logical Log File: test-db_log
Physical Data File: D:\MSSQL\Data\test-db.mdf
Physical Log File: D:\MSSQL\Data\test-db_log.ldf
Msg 1834, Level 16, State 1, Line 50
The file 'D:\MSSQL\Data\test-db.mdf' cannot be overwritten. It is being used by database 'test-db'.
Msg 3156, Level 16, State 4, Line 50
File 'test-db' cannot be restored to 'D:\MSSQL\Data\test-db.mdf'. Use WITH MOVE to identify a valid location for the file.
Msg 1834, Level 16, State 1, Line 50
The file 'D:\MSSQL\Data\test-db_log.ldf' cannot be overwritten. It is being used by database 'test-db'.
Msg 3156, Level 16, State 4, Line 50
File 'test-db_log' cannot be restored to 'D:\MSSQL\Data\test-db_log.ldf'. Use WITH MOVE to identify a valid location for the file.
Msg 3119, Level 16, State 1, Line 50
Problems were identified while planning for the RESTORE statement. Previous messages provide details.
Msg 3013, Level 16, State 1, Line 50
RESTORE DATABASE is terminating abnormally.
I wanted to make sure that the MOVE statements weren't being ignored for some reason, so I changed the variable names for the logical and physical file names – as expected, I got an error stating that the variables must be declared.
Is there something else that needs to be done to allow the database to be overwritten? There are no other connections to this database.
Best Answer
You're trying to restore a database named
[@DBName]
(that's the literal name since it is surrounded by square brackets) onto files for the database named[test-db]
. Remove the[
and]
from the[@DBName]
piece of your code and you'll see you cannot use variable names in aRESTORE DATABASE
command.This needs to be performed with dynamic SQL. The list of files to move should be generated by looking at
RESTORE FILELISTONLY FROM DISK = 'C:\some_db_backup.bak';
Here is a very basic example of how to generate a
RESTORE DATABASE
command using dynamic SQL, for SQL Server 2005 to SQL Server 2012 (i.e. this is not tested on 2014, and may or may not work without modification there):