Reputation: 9856
In SQL server 2008R2, I am trying to restore multiple databases/BAK files located in one folder only, using a SQL query given here - http://www.karaszi.com/sqlserver/code/sp_RestoreFromAllFilesInDirectory_2008sp1.txt
It uses a stored procedure like this, the code for which is given at the end -
exec sp_RestoreFromAllFilesInDirectory 'C:\Mybakfiles\',
'D:\Mydatabasesdirectory\' ,
'C:\MylogDirectory\'
Folders invloved - 'C:\Mybakfiles\', 'D:\Mydatabasesdirectory\' , 'C:\MylogDirectory\'
You should know the path to the first folder. The second and third can be found with a query or by SSMS. For the query, refer to alex aza's answer at - What is the most efficient way to restore multiple databases in SQL 2008 . I have also given his query at the end.
I copied all my BAK files to - C:\Program Files\Microsoft SQL Server\MSSQL10_50.SS2008\MSSQL\Backup\
Then, I entered executed the SP as follows -
exec sp_RestoreFromAllFilesInDirectory 'C:\Program Files\
Microsoft SQL Server\MSSQL10_50.SS2008\MSSQL\Backup\',
'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SS2008\MSSQL
\DATA\' , 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SS2008\
MSSQL\DATA\'
and got the following sample output -
RESTORE DATABASE AdventureWorksDW FROM DISK = 'C:\Program Files\
Microsoft SQL Server\MSSQL10_50.SS2008\MSSQL\Backup\AdventureWorksDW.bak'
WITH MOVE 'AdventureWorksDW_Data' TO 'C:\Program Files\Microsoft SQL
Server\MSSQL10_50.SS2008\MSSQL\DATA\AdventureWorksDW_Data.mdf', MOVE
'AdventureWorksDW_Log' TO 'C:\Program Files\Microsoft SQL Server\
MSSQL10_50.SS2008\MSSQL\DATA\AdventureWorksDW_Log.ldf'
Problem - I refreshed my server in management studio and saw no new databases. Why ? Have I restored my Databases correctly ? If not, how do I do it using the code I have provided below ? If you think that code is not good, is there any other reliable way to do it ?
PS - Its a shame that MS does not let you do this easily.
EXTRA INFORMATION -
Here is the sp to restore multiple databases -
CREATE PROC [dbo].[sp_RestoreFromAllFilesInDirectory]
@SourceDirBackupFiles nvarchar(200), @DestDirDbFiles
nvarchar(200),@DestDirLogFiles nvarchar(200)
AS
--Originally written by Tibor Karaszi 2004. Use at own risk.
--Restores from all files in a certain directory. Assumes that:
-- There's only one backup on each backup device.
-- Each database uses only two database files and the mdf file
is returned first from the RESTORE FILELISTONLY command.
--Sample execution:
-- EXEC sp_RestoreFromAllFilesInDirectory 'C:\Mybakfiles\',
'D:\Mydatabasesdirectory\' ,’C:\MylogDirectory\’
SET NOCOUNT ON
--Table to hold each backup file name in
CREATE TABLE #files(fname varchar(200),depth int, file_ int)
INSERT #files
EXECUTE master.dbo.xp_dirtree @SourceDirBackupFiles, 1, 1
--Table to hold the result from RESTORE HEADERONLY. Needed to get
the database name out from
CREATE TABLE #bdev(
BackupName nvarchar(128)
,BackupDescription nvarchar(255)
,BackupType smallint
,ExpirationDate datetime
,Compressed tinyint
,Position smallint
,DeviceType tinyint
,UserName nvarchar(128)
,ServerName nvarchar(128)
,DatabaseName nvarchar(128)
,DatabaseVersion int
,DatabaseCreationDate datetime
,BackupSize numeric(20,0)
,FirstLSN numeric(25,0)
,LastLSN numeric(25,0)
,CheckpointLSN numeric(25,0)
,DatabaseBackupLSN numeric(25,0)
,BackupStartDate datetime
,BackupFinishDate datetime
,SortOrder smallint
,CodePage smallint
,UnicodeLocaleId int
,UnicodeComparisonStyle int
,CompatibilityLevel tinyint
,SoftwareVendorId int
,SoftwareVersionMajor int
,SoftwareVersionMinor int
,SoftwareVersionBuild int
,MachineName nvarchar(128)
,Flags int
,BindingID uniqueidentifier
,RecoveryForkID uniqueidentifier
,Collation nvarchar(128)
,FamilyGUID uniqueidentifier
,HasBulkLoggedData int
,IsSnapshot int
,IsReadOnly int
,IsSingleUser int
,HasBackupChecksums int
,IsDamaged int
,BegibsLogChain int
,HasIncompleteMetaData int
,IsForceOffline int
,IsCopyOnly int
,FirstRecoveryForkID uniqueidentifier
,ForkPointLSN numeric(25,0)
,RecoveryModel nvarchar(128)
,DifferentialBaseLSN numeric(25,0)
,DifferentialBaseGUID uniqueidentifier
,BackupTypeDescription nvarchar(128)
,BackupSetGUID uniqueidentifier
,CompressedBackupSize nvarchar(128)
)
--Table to hold result from RESTORE FILELISTONLY. Need to
generate the MOVE options to the RESTORE command
CREATE TABLE #dbfiles(
LogicalName nvarchar(128)
,PhysicalName nvarchar(260)
,Type char(1)
,FileGroupName nvarchar(128)
,Size numeric(20,0)
,MaxSize numeric(20,0)
,FileId int
,CreateLSN numeric(25,0)
,DropLSN numeric(25,0)
,UniqueId uniqueidentifier
,ReadOnlyLSN numeric(25,0)
,ReadWriteLSN numeric(25,0)
,BackupSizeInBytes int
,SourceBlockSize int
,FilegroupId int
,LogGroupGUID uniqueidentifier
,DifferentialBaseLSN numeric(25)
,DifferentialBaseGUID uniqueidentifier
,IsReadOnly int
,IsPresent int
,TDEThumbprint nvarchar(128)
)
DECLARE @fname varchar(200)
DECLARE @dirfile varchar(300)
DECLARE @LogicalName nvarchar(128)
DECLARE @PhysicalName nvarchar(260)
DECLARE @type char(1)
DECLARE @DbName sysname
DECLARE @sql nvarchar(1000)
DECLARE files CURSOR FOR
SELECT fname FROM #files
DECLARE dbfiles CURSOR FOR
SELECT LogicalName, PhysicalName, Type FROM #dbfiles
OPEN files
FETCH NEXT FROM files INTO @fname
WHILE @@FETCH_STATUS = 0
BEGIN
SET @dirfile = @SourceDirBackupFiles + @fname
--Get database name from RESTORE HEADERONLY, assumes there's
only one backup on each backup file.
TRUNCATE TABLE #bdev
INSERT #bdev
EXEC('RESTORE HEADERONLY FROM DISK = ''' + @dirfile + '''')
SET @DbName = (SELECT DatabaseName FROM #bdev)
--Construct the beginning for the RESTORE DATABASE command
SET @sql = 'RESTORE DATABASE ' + @DbName + ' FROM DISK = ''' +
@dirfile + ''' WITH MOVE '
--Get information about database files from backup device into temp table
TRUNCATE TABLE #dbfiles
INSERT #dbfiles
EXEC('RESTORE FILELISTONLY FROM DISK = ''' + @dirfile + '''')
OPEN dbfiles
FETCH NEXT FROM dbfiles INTO @LogicalName, @PhysicalName, @type
--For each database file that the database uses
WHILE @@FETCH_STATUS = 0
BEGIN
IF @type = 'D'
SET @sql = @sql + '''' + @LogicalName + ''' TO ''' +
@DestDirDbFiles + @LogicalName + '.mdf'', MOVE '
ELSE IF @type = 'L'
SET @sql = @sql + '''' + @LogicalName + ''' TO ''' +
@DestDirLogFiles + @LogicalName + '.ldf'''
FETCH NEXT FROM dbfiles INTO @LogicalName, @PhysicalName, @type
END
--Here's the actual RESTORE command
PRINT @sql
--Remove the comment below if you want the procedure to
actually execute the restore command.
--EXEC(@sql)
CLOSE dbfiles
FETCH NEXT FROM files INTO @fname
END
CLOSE files
DEALLOCATE dbfiles
DEALLOCATE files
Query to get the folder locations for DATA and LOG files -
declare @DefaultData nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'Software\Microsoft\MSSQLServer\MSSQLServer',
N'DefaultData', @DefaultData output
declare @DefaultLog nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'Software\Microsoft\MSSQLServer\MSSQLServer',
N'DefaultLog', @DefaultLog output
declare @MasterData nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\
Microsoft\MSSQLServer\MSSQLServer\Parameters', N'SqlArg0', @MasterData output
select @MasterData=substring(@MasterData, 3, 255)
select @MasterData=substring(@MasterData, 1, len(@MasterData) -
charindex('\', reverse(@MasterData)))
declare @MasterLog nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\
Microsoft\MSSQLServer\MSSQLServer\Parameters', N'SqlArg2', @MasterLog output
select @MasterLog=substring(@MasterLog, 3, 255)
select @MasterLog=substring(@MasterLog, 1, len(@MasterLog) -
charindex('\', reverse(@MasterLog)))
select
isnull(@DefaultData, @MasterData) DefaultData,
isnull(@DefaultLog, @MasterLog) DefaultLog
Use SSMS to find DATA and LOG folders -
SSMS > Your Server > Right click > Properties > Database Settings node.
Upvotes: 4
Views: 16232
Reputation: 21
Thank you so much for this very helpful script.
I have added the new columns for newer versions of SQL Server as well as added the alter database to single-user mode before the restore and alter it back to multiuser after the restore. By default, these options are commented out.
--If you need to overwrite the existing database uncomment this
--SET @sql = 'ALTER DATABASE [' + @DbName + '] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--RESTORE DATABASE ' + @DbName + ' FROM DISK = ''' +
--@dirfile + ''' WITH FILE = 1, MOVE '
--If you need to overwrite the existing database uncomment this as it will reinstate the database to multi-user
--SET @sql = @sql + '''' + @LogicalName + ''' TO ''' +
--@DestDirLogFiles + @LogicalName + '.ldf '', NOUNLOAD, REPLACE, STATS = 5
--ALTER DATABASE [' + @DbName + '] SET MULTI_USER
--'
Here is the latest stored procedure:
USE [master]
GO
/****** Object: StoredProcedure [dbo].[sp_RestoreFromAllFilesInDirectory] Script Date: 2020/10/19 13:37:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[sp_RestoreFromAllFilesInDirectory]
@SourceDirBackupFiles nvarchar(200), @DestDirDbFiles
nvarchar(200),@DestDirLogFiles nvarchar(200)
AS
--Originally written by Tibor Karaszi 2004. Use at own risk.
--Restores from all files in a certain directory. Assumes that:
-- There's only one backup on each backup device.
-- Each database uses only two database files and the mdf file
--is returned first from the RESTORE FILELISTONLY command.
--Sample execution:
-- EXEC sp_RestoreFromAllFilesInDirectory 'C:\Mybakfiles\',
--'D:\Mydatabasesdirectory\' ,’C:\MylogDirectory\’
SET NOCOUNT ON
--Table to hold each backup file name in
CREATE TABLE #files(fname varchar(200),depth int, file_ int)
INSERT #files
EXECUTE master.dbo.xp_dirtree @SourceDirBackupFiles, 1, 1
--EXEC master.sys.xp_cmdshell 'dir /B \\vm-biol-sql03\restore\*.bak'
--SELECT * FROM #files
--WHERE file_ = 1 AND RIGHT(fname,4) = '.BAK'
----ORDER BYid;
--GO
--Table to hold the result from RESTORE HEADERONLY. Needed to get
--the database name out from
CREATE TABLE #bdev(
BackupName nvarchar(128)
,BackupDescription nvarchar(255)
,BackupType smallint
,ExpirationDate datetime
,Compressed tinyint
,Position smallint
,DeviceType tinyint
,UserName nvarchar(128)
,ServerName nvarchar(128)
,DatabaseName nvarchar(128)
,DatabaseVersion int
,DatabaseCreationDate datetime
,BackupSize numeric(20,0)
,FirstLSN numeric(25,0)
,LastLSN numeric(25,0)
,CheckpointLSN numeric(25,0)
,DatabaseBackupLSN numeric(25,0)
,BackupStartDate datetime
,BackupFinishDate datetime
,SortOrder smallint
,CodePage smallint
,UnicodeLocaleId int
,UnicodeComparisonStyle int
,CompatibilityLevel tinyint
,SoftwareVendorId int
,SoftwareVersionMajor int
,SoftwareVersionMinor int
,SoftwareVersionBuild int
,MachineName nvarchar(128)
,Flags int
,BindingID uniqueidentifier
,RecoveryForkID uniqueidentifier
,Collation nvarchar(128)
,FamilyGUID uniqueidentifier
,HasBulkLoggedData int
,IsSnapshot int
,IsReadOnly int
,IsSingleUser int
,HasBackupChecksums int
,IsDamaged int
,BegibsLogChain int
,HasIncompleteMetaData int
,IsForceOffline int
,IsCopyOnly int
,FirstRecoveryForkID uniqueidentifier
,ForkPointLSN numeric(25,0)
,RecoveryModel nvarchar(128)
,DifferentialBaseLSN numeric(25,0)
,DifferentialBaseGUID uniqueidentifier
,BackupTypeDescription nvarchar(128)
,BackupSetGUID uniqueidentifier
,CompressedBackupSize nvarchar(128)
,Containment int
,KeyAlgorithm nvarchar(32)
,EncryptorThumbprint varbinary(20)
,EncryptorType nvarchar(32)
)
--Table to hold result from RESTORE FILELISTONLY. Need to
--generate the MOVE options to the RESTORE command
CREATE TABLE #dbfiles(
LogicalName nvarchar(128)
,PhysicalName nvarchar(260)
,Type char(1)
,FileGroupName nvarchar(128)
,Size numeric(20,0)
,MaxSize numeric(20,0)
,FileId int
,CreateLSN numeric(25,0)
,DropLSN numeric(25,0)
,UniqueId uniqueidentifier
,ReadOnlyLSN numeric(25,0)
,ReadWriteLSN numeric(25,0)
,BackupSizeInBytes int
,SourceBlockSize int
,FilegroupId int
,LogGroupGUID uniqueidentifier
,DifferentialBaseLSN numeric(25)
,DifferentialBaseGUID uniqueidentifier
,IsReadOnly int
,IsPresent int
,TDEThumbprint nvarchar(128)
,SnapshotURL nvarchar(360)
)
DECLARE @fname varchar(200)
DECLARE @dirfile varchar(300)
DECLARE @LogicalName nvarchar(128)
DECLARE @PhysicalName nvarchar(260)
DECLARE @type char(1)
DECLARE @DbName sysname
DECLARE @sql nvarchar(1000)
DECLARE files CURSOR FOR
SELECT fname FROM #files
WHERE file_ = 1 AND RIGHT(fname,4) = '.BAK'
--and fname not in ('Clinical_Full_3602931155336463893_2020-10-10_21-56-02.bak', '
--ConfidentialReporting_Full_3602926454752534117_2020-10-10_20-14-00.bak',
--'Staging_Full_3602930308161851174_2020-10-10_20-01-30.bak', 'Reporting_Full_3602917625954565769_2020-10-10_19-33-08.bak',
--'Staging_Differential_3602917962091834093_2020-10-16_18-06-23.bak')
DECLARE dbfiles CURSOR FOR
SELECT LogicalName, PhysicalName, Type FROM #dbfiles
OPEN files
FETCH NEXT FROM files INTO @fname
WHILE @@FETCH_STATUS = 0
BEGIN
SET @dirfile = @SourceDirBackupFiles + @fname
--Get database name from RESTORE HEADERONLY, assumes there's
--only one backup on each backup file.
TRUNCATE TABLE #bdev
INSERT #bdev
EXEC('RESTORE HEADERONLY FROM DISK = ''' + @dirfile + '''')
SET @DbName = (SELECT DatabaseName FROM #bdev)
--Construct the beginning for the RESTORE DATABASE command
SET @sql = 'RESTORE DATABASE ' + @DbName + ' FROM DISK = ''' +
@dirfile + ''' WITH FILE = 1, MOVE '
--If you need to overwrite the existing database uncomment this
--SET @sql = 'ALTER DATABASE [' + @DbName + '] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--RESTORE DATABASE ' + @DbName + ' FROM DISK = ''' +
--@dirfile + ''' WITH FILE = 1, MOVE '
--Get information about database files from backup device into temp table
TRUNCATE TABLE #dbfiles
INSERT #dbfiles
EXEC('RESTORE FILELISTONLY FROM DISK = ''' + @dirfile + '''')
OPEN dbfiles
FETCH NEXT FROM dbfiles INTO @LogicalName, @PhysicalName, @type
--For each database file that the database uses
WHILE @@FETCH_STATUS = 0
BEGIN
IF @type = 'D'
SET @sql = @sql + '''' + @LogicalName + ''' TO ''' +
@DestDirDbFiles + @LogicalName + '.mdf'', MOVE '
ELSE IF @type = 'L'
SET @sql = @sql + '''' + @LogicalName + ''' TO ''' +
@DestDirLogFiles + @LogicalName + '.ldf '', NOUNLOAD, REPLACE, STATS = 5'
--If you need to overwrite the existing database uncomment this as it will reinstate the database to multi-user
--SET @sql = @sql + '''' + @LogicalName + ''' TO ''' +
--@DestDirLogFiles + @LogicalName + '.ldf '', NOUNLOAD, REPLACE, STATS = 5
--ALTER DATABASE [' + @DbName + '] SET MULTI_USER
--'
FETCH NEXT FROM dbfiles INTO @LogicalName, @PhysicalName, @type
END
--Here's the actual RESTORE command
PRINT @sql
--Remove the comment below if you want the procedure to
--actually execute the restore command.
--EXEC(@sql)
CLOSE dbfiles
FETCH NEXT FROM files INTO @fname
END
CLOSE files
DEALLOCATE dbfiles
DEALLOCATE files
Upvotes: 2
Reputation: 11
first thanx for the script:) kindly check the columns RESTOREHEADERONLY and FILELISTONLY. You need to add some columns. At least mine worked when added new columns.
Upvotes: 0
Reputation: 685
To make the script work on MS SQL Server 2012, add another column to #bdev table:
Containment int
Also, I had to change a few columns in #dbfiles table to be bigint.
Upvotes: 0
Reputation: 416
First thank you for providing the script of sp_RestoreFromAllFilesInDirectory
as the creator homepage no longer available.
The script you provided only print the generated sql so all you need to uncomment the line:
EXEC(@sql)
I know the question is too old but that my save someone else
Upvotes: 5