简体   繁体   English

需要帮助从一个文件夹中恢复多个数据库/bak 文件

[英]Need help to restore multiple databases/bak files from one folder

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在 SQL Server 2008R2 中,我试图使用此处给出的 SQL 查询恢复位于一个文件夹中的多个数据库/BAK 文件 - 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\\'涉及的文件夹 - '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.第二个和第三个可以通过查询或 SSMS 找到。 For the query, refer to alex aza's answer at - What is the most efficient way to restore multiple databases in SQL 2008 .有关查询,请参阅 alex aza 的回答 - What is the most Effective 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\\我将所有 BAK 文件复制到 - C:\\Program Files\\Microsoft SQL Server\\MSSQL10_50.SS2008\\MSSQL\\Backup\\

Then, I entered executed the SP as follows -然后,我输入执行的 SP 如下 -

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. PS - 很遗憾 MS 不允许您轻松完成此操作。


EXTRA INFORMATION -额外的信息 -

Here is the sp to restore multiple databases -这是恢复多个数据库的 sp -

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 -查询以获取 DATA 和 LOG 文件的文件夹位置 -

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 查找 DATA 和 LOG 文件夹 -

SSMS > Your Server > Right click > Properties > Database Settings node. SSMS > 您的服务器 > 右键单击​​ > 属性 > 数据库设置节点。

在此处输入图片说明

First thank you for providing the script of sp_RestoreFromAllFilesInDirectory as the creator homepage no longer available.首先感谢您提供sp_RestoreFromAllFilesInDirectory的脚本,因为创建者主页不再可用。

The script you provided only print the generated sql so all you need to uncomment the line:您提供的脚本仅打印生成的 sql,因此您只需取消注释该行:

EXEC(@sql)

I know the question is too old but that my save someone else我知道这个问题太老了,但我救了别人

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.我为较新版本的 SQL Server 添加了新列,并在还原前将更改数据库添加到单用户模式,并在还原后将其更改回多用户模式。 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 

To make the script work on MS SQL Server 2012, add another column to #bdev table:要使脚本在 MS SQL Server 2012 上运行,请将另一列添加到 #bdev 表:

Containment int

Also, I had to change a few columns in #dbfiles table to be bigint.此外,我不得不将#dbfiles 表中的几列更改为 bigint。

first thanx for the script:) kindly check the columns RESTOREHEADERONLY and FILELISTONLY .首先感谢脚本:) 请检查列RESTOREHEADERONLYFILELISTONLY You need to add some columns.您需要添加一些列。 At least mine worked when added new columns.添加新列时,至少我的工作正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM