完全自动化的SQL Server还原

我不太熟悉SQL Server命令。

我需要一个脚本来从.bak文件恢复数据库并将logical_data和logical_log文件移动到特定的path。

我可以:

restore filelistonly from disk='D:\backups\my_backup.bak' 

这将给我一个列LogicalName的结果集,接下来我需要在恢复命令中使用结果集中的逻辑名称:

 restore database my_db_name from disk='d:\backups\my_backups.bak' with file=1, move 'logical_data_file' to 'd:\data\mydb.mdf', move 'logical_log_file' to 'd:\data\mylog.ldf' 

如何将第一个结果集中的逻辑名称捕获到可以提供给“move”命令的variables中?

我认为解决scheme可能是微不足道的,但我是SQL Server的新手。

这里是全自动恢复T-SQL存储过程。 接受三(3)个参数。

  1. 目标数据库
  2. 源数据库
  3. 完全限定的备份文件名称位置
    \\yourserver\yourshare\backupfile.bak或简单的c:\backup.bak

 CREATE PROC [dbo].[restoreDB] @p_strDBNameTo SYSNAME, @p_strDBNameFrom SYSNAME, @p_strFQNRestoreFileName VARCHAR(255) AS DECLARE @v_strDBFilename VARCHAR(100), @v_strDBLogFilename VARCHAR(100), @v_strDBDataFile VARCHAR(100), @v_strDBLogFile VARCHAR(100), @v_strExecSQL NVARCHAR(1000), @v_strExecSQL1 NVARCHAR(1000), @v_strMoveSQL NVARCHAR(4000), @v_strREPLACE NVARCHAR(50), @v_strTEMP NVARCHAR(1000), @v_strListSQL NVARCHAR(4000), @v_strServerVersion NVARCHAR(20) SET @v_strREPLACE = '' IF exists (select name from sys.databases where name = @p_strDBNameTo) SET @v_strREPLACE = ', REPLACE' SET @v_strListSQL = '' SET @v_strListSQL = @v_strListSQL + 'IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''##FILE_LIST''))' SET @v_strListSQL = @v_strListSQL + 'BEGIN' SET @v_strListSQL = @v_strListSQL + ' DROP TABLE ##FILE_LIST ' SET @v_strListSQL = @v_strListSQL + 'END ' SET @v_strListSQL = @v_strListSQL + 'CREATE TABLE ##FILE_LIST (' SET @v_strListSQL = @v_strListSQL + ' LogicalName VARCHAR(64),' SET @v_strListSQL = @v_strListSQL + ' PhysicalName VARCHAR(130),' SET @v_strListSQL = @v_strListSQL + ' [Type] VARCHAR(1),' SET @v_strListSQL = @v_strListSQL + ' FileGroupName VARCHAR(64),' SET @v_strListSQL = @v_strListSQL + ' Size DECIMAL(20, 0),' SET @v_strListSQL = @v_strListSQL + ' MaxSize DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' FileID bigint,' SET @v_strListSQL = @v_strListSQL + ' CreateLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' DropLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' UniqueID UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' ReadOnlyLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' ReadWriteLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' BackupSizeInBytes DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' SourceBlockSize INT,' SET @v_strListSQL = @v_strListSQL + ' filegroupid INT,' SET @v_strListSQL = @v_strListSQL + ' loggroupguid UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' differentialbaseLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' differentialbaseGUID UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' isreadonly BIT,' SET @v_strListSQL = @v_strListSQL + ' ispresent BIT' SELECT @v_strServerVersion = CAST(SERVERPROPERTY ('PRODUCTVERSION') AS NVARCHAR) IF @v_strServerVersion LIKE '10.%' BEGIN SET @v_strListSQL = @v_strListSQL + ', TDEThumbpr DECIMAL' --PRINT @v_strServerVersion END SET @v_strListSQL = @v_strListSQL + ')' EXEC (@v_strListSQL) INSERT INTO ##FILE_LIST EXEC ('RESTORE FILELISTONLY FROM DISK = ''' + @p_strFQNRestoreFileName + '''') DECLARE curFileLIst CURSOR FOR SELECT 'MOVE N''' + LogicalName + ''' TO N''' + replace(PhysicalName, @p_strDBNameFrom, @p_strDBNameTo) + '''' FROM ##FILE_LIST SET @v_strMoveSQL = '' OPEN curFileList FETCH NEXT FROM curFileList into @v_strTEMP WHILE @@Fetch_Status = 0 BEGIN SET @v_strMoveSQL = @v_strMoveSQL + @v_strTEMP + ', ' FETCH NEXT FROM curFileList into @v_strTEMP END CLOSE curFileList DEALLOCATE curFileList PRINT 'Killing active connections to the "' + @p_strDBNameTo + '" database' -- Create the sql to kill the active database connections SET @v_strExecSQL = '' SELECT @v_strExecSQL = @v_strExecSQL + 'kill ' + CONVERT(CHAR(10), spid) + ' ' FROM master.dbo.sysprocesses WHERE DB_NAME(dbid) = @p_strDBNameTo AND DBID <> 0 AND spid <> @@spid EXEC (@v_strExecSQL) PRINT 'Restoring "' + @p_strDBNameTo + '" database from "' + @p_strFQNRestoreFileName + '" with ' PRINT ' data file "' + @v_strDBDataFile + '" located at "' + @v_strDBFilename + '"' PRINT ' log file "' + @v_strDBLogFile + '" located at "' + @v_strDBLogFilename + '"' SET @v_strExecSQL = 'RESTORE DATABASE [' + @p_strDBNameTo + ']' SET @v_strExecSQL = @v_strExecSQL + ' FROM DISK = ''' + @p_strFQNRestoreFileName + '''' SET @v_strExecSQL = @v_strExecSQL + ' WITH FILE = 1,' SET @v_strExecSQL = @v_strExecSQL + @v_strMoveSQL SET @v_strExecSQL = @v_strExecSQL + ' NOREWIND, ' SET @v_strExecSQL = @v_strExecSQL + ' NOUNLOAD ' SET @v_strExecSQL = @v_strExecSQL + @v_strREPLACE --PRINT '---------------------------' --PRINT @v_strExecSQL --PRINT '---------------------------' EXEC sp_executesql @v_strExecSQL 

RESTORE FILELISTONLY生成MSDN中logging的结果集。 然后你需要迭代这个结果集并构build一个合适的RESTORE … MOVE …如何捕获和迭代结果集取决于你的环境。 在C#应用程序中,您将使用SqlDataReader。 在纯粹的T-SQL中,你可以使用INSERT … EXEC 。

纯SQL解决scheme的骨架将是:

 declare @filelist table (LogicalName nvarchar(128), PhysicalName nvarchar(260), Type char(1), FilegroupName varchar(10), size int, MaxSize bigint, field int, createlsn bit, droplsn bit, uniqueid uniqueidentifier, readonlylsn bit, readwritelsn bit, backupsizeinbytes bigint, sourceblocksize int, filegroupid int, loggroupguid uniqueidentifier, differentialbaselsn bit, differentialbaseguid uniqueidentifier, isreadonly bit, ispresent bit, tdethumbprint varchar(5)); insert into @filelist exec sp_executesql N'restore filelistonly from disk=''D:\backups\my_backup.bak'''; set @sql = N'RESTORE database my_database from disk ''D:\backups\my_backup.bak'' with '; select @sql = @sql + N' move ' + LogicalName + N' to ' udf_localFilePath(PhysicalName) + N',' from @filelist; set @sql = substring(@sql, 1, len(@sql)-1); -- remove last ',' exec sp_executesql @sql; 

这不是实际的工作代码,只是为了让你的想法。 您也可以使用游标来代替@sql的非标准的分配内部查询结构

请注意RESTORE FILELISTONLY的结果集中的列的列表在SQL Server版本之间是不同的。 请参阅目标版本规格以获取正确的列表。

运用

作为参考,我想出了这个..我认为它的作品(没有testing备份多个文件)

 DECLARE @FileList TABLE ( LogicalName nvarchar(128) NOT NULL, PhysicalName nvarchar(260) NOT NULL, Type char(1) NOT NULL, FileGroupName nvarchar(120) NULL, Size numeric(20, 0) NOT NULL, MaxSize numeric(20, 0) NOT NULL, FileID bigint NULL, CreateLSN numeric(25,0) NULL, DropLSN numeric(25,0) NULL, UniqueID uniqueidentifier NULL, ReadOnlyLSN numeric(25,0) NULL , ReadWriteLSN numeric(25,0) NULL, BackupSizeInBytes bigint NULL, SourceBlockSize int NULL, FileGroupID int NULL, LogGroupGUID uniqueidentifier NULL, DifferentialBaseLSN numeric(25,0)NULL, DifferentialBaseGUID uniqueidentifier NULL, IsReadOnly bit NULL, IsPresent bit NULL, TDEThumbprint varbinary(32) NULL ); declare @RestoreStatement nvarchar(max), @BackupFile nvarchar(max); set @BackupFile = 'D:\mybackup.bak' SET @RestoreStatement = N'RESTORE FILELISTONLY FROM DISK=N''' + @BackupFile + '''' INSERT INTO @FileList EXEC(@RestoreStatement); declare @logical_data nvarchar(max), @logical_log nvarchar(max); set @logical_data = (select LogicalName from @FileList where Type = 'D' and FileID = 1) set @logical_log = (select LogicalName from @FileList where Type = 'L' and FileID = 2) 
 /* Automate restore w/o needing to know the logical file names. Specify destination database name, database backup source filename and .MDF, .LDF and .NDF directories. I do nightly automated database restores, and I've been using this code for about a month. Works for sql server 2008, might work for 2005. Created by wtm 5/27/2010 */ -- BEGIN - MODIFY THIS CODE - create a blank db if not exists(select * from master.sys.databases where [name]='sc') begin create database sc end go -- END - MODIFY THIS CODE - create a blank db declare @strDatabase varchar(130)='sc' -- MODIFY THIS LINE - db name declare @strBackupFile varchar(500)='c:\docs\db-backups\sc.bak' -- MODIFY THIS LINE - source db backup file declare @strRestoreMDFFilesTo varchar(500)='c:\docs\sqldata\' -- MODIFY THIS LINE - destination restore directory for main files declare @strRestoreLDFFilesTo varchar(500)='c:\docs\sqldata\' -- MODIFY THIS LINE - destination restore directory for tlog files declare @strRestoreNDFFilesTo varchar(500)='c:\docs\sqldata\' -- MODIFY THIS LINE - destination restore directory for non-main files -- other variables used declare @strSQL nvarchar(max) declare @strOriginalPhysicalName varchar(150) declare @strPhysicalName varchar(150) declare @strLogicalName varchar(150) declare @intReturn int -- begin restoring begin try drop table #tmpFilelist end try begin catch end catch create table #tmpFilelist ( LogicalName varchar(64), PhysicalName varchar(130), [Type] varchar(1), FileGroupName varchar(64), Size decimal(20, 0) ,MaxSize decimal(25, 0), FileID bigint, CreateLSN decimal(25,0), DropLSN decimal(25,0), UniqueID uniqueidentifier ,ReadOnlyLSN decimal(25,0), ReadWriteLSN decimal(25,0), BackSizeInBytes decimal(25,0), SourceBlockSize int ,filegroupid int, loggroupguid uniqueidentifier, differentialbaseLSN decimal(25,0), differentialbaseGUID uniqueidentifier ,isreadonly bit, ispresent bit, TDEThumbpr decimal ) if not exists(select * from sc.sys.tables) or exists(select * from sc.sys.tables where [name]='not-an-original-table') -- MODIFY THIS LINE - business logic to see if we need to restore the database at all begin print 'Restoring '+@strDatabase+' db ...' use master exec msdb.dbo.sp_delete_database_backuphistory @database_name = @strDatabase use [master] exec('alter database '+@strDatabase+' set single_user with rollback immediate') use [master] exec('drop database '+@strDatabase) insert into #tmpFilelist exec('restore filelistonly from disk = '''+@strBackupFile+'''') set @strSQL='restore database ['+@strDatabase+'] from disk='''+@strBackupFile+''' with ' set @strSQL=@strSQL+ 'file=1 ' set @strSQL=@strSQL+ ',nounload ' set @strSQL=@strSQL+ ',replace ' set @strSQL=@strSQL+ ',stats=10 ' -- show restore status every 10% while exists(select * from #tmpFilelist) begin select top 1 @strOriginalPhysicalName=PhysicalName, @strLogicalName=LogicalName from #tmpFilelist set @strPhysicalName=@strOriginalPhysicalName set @strPhysicalName=reverse(@strPhysicalName) set @strPhysicalName=left(@strPhysicalName, charindex('\', @strPhysicalName)-1) set @strPhysicalName=reverse(@strPhysicalName) set @strPhysicalName=replace(@strPhysicalName, '.', '_'+@strDatabase+'.') if @strPhysicalName like '%.mdf' set @strPhysicalName=@strRestoreMDFFilesTo+@strPhysicalName else if @strPhysicalName like '%.ldf' set @strPhysicalName=@strRestoreLDFFilesTo+@strPhysicalName else set @strPhysicalName=@strRestoreNDFFilesTo+@strPhysicalName set @strSQL=@strSQL+ ',move '''+@strLogicalName+''' to '''+@strPhysicalName+''' ' delete from #tmpFilelist where PhysicalName=@strOriginalPhysicalName end execute @intReturn=sp_executesql @strSQL end 

我有同样的问题,但在我的环境中,我有很多备份文件(更快的备份),并需要恢复到自定义位置。 此查询获取最新的完整备份信息并恢复到您指定的path。 在SQL 2005/2008上testing

 SET NOCOUNT ON Declare @BackupFiles varchar(500), @data_file_path VARCHAR(512), @log_file_path VARCHAR(512), @RestoreFileList varchar(2000), @RestoreStatement varchar(3000), @MoveFiles varchar(2000), @DBName varchar(150) DECLARE @filelist TABLE (LogicalName NVARCHAR(128) NOT NULL, PhysicalName NVARCHAR(260) NOT NULL, [Type] CHAR(1) NOT NULL, FileGroupName NVARCHAR(120) NULL, Size NUMERIC(20, 0) NOT NULL, MaxSize NUMERIC(20, 0) NOT NULL, FileID BIGINT NULL, CreateLSN NUMERIC(25,0) NULL, DropLSN NUMERIC(25,0) NULL, UniqueID UNIQUEIDENTIFIER NULL, ReadOnlyLSN NUMERIC(25,0) NULL , ReadWriteLSN NUMERIC(25,0) NULL, BackupSizeInBytes BIGINT NULL, SourceBlockSize INT NULL, FileGroupID INT NULL, LogGroupGUID UNIQUEIDENTIFIER NULL, DfferentialBaseLSN NUMERIC(25,0)NULL, DifferentialBaseGUID UNIQUEIDENTIFIER NULL, IsReadOnly BIT NULL, IsPresent BIT NULL, TDEThumbprint VARBINARY(32) NULL) SET @data_file_path = 'E:\SQLData\' SET @log_file_path = 'E:\SQLLog\' SET @DBName = 'Adventureworks' --Get last full backup: SELECT @BackupFiles=Coalesce(@BackupFiles + ',', '') + 'DISK = N'''+physical_device_name+'''' FROM msdb..backupset S JOIN msdb..backupmediafamily M ON M.media_set_id=S.media_set_id WHERE backup_set_id = ( SELECT max(backup_set_id) FROM msdb..backupset S JOIN msdb..backupmediafamily M ON M.media_set_id=S.media_set_id WHERE S.database_name = @DBName and Type = 'D') SELECT @RestoreFileList= 'RESTORE FILELISTONLY FROM ' + @BackupFiles + ' WITH FILE = 1 ' IF (@@microsoftversion / 0x1000000) & 0xff >= 10 --TDE capability Begin INSERT into @filelist (LogicalName,PhysicalName,Type,FileGroupName,Size,MaxSize,FileID,CreateLSN,DropLSN,UniqueID,ReadOnlyLSN,ReadWriteLSN,BackupSizeInBytes,SourceBlockSize,FileGroupID,LogGroupGUID,DfferentialBaseLSN,DifferentialBaseGUID,IsReadOnly,IsPresent,TDEThumbprint) EXEC (@RestoreFileList) End Else Begin INSERT into @filelist (LogicalName,PhysicalName,Type,FileGroupName,Size,MaxSize,FileID,CreateLSN,DropLSN,UniqueID,ReadOnlyLSN,ReadWriteLSN,BackupSizeInBytes,SourceBlockSize,FileGroupID,LogGroupGUID,DfferentialBaseLSN,DifferentialBaseGUID,IsReadOnly,IsPresent) EXEC (@RestoreFileList) End --next version, do a count on filename, any >1 put in alternate data/log location. SELECT @MoveFiles=Coalesce(@MoveFiles + ',' , '') + 'MOVE N''' + LogicalName + ''' to N''' + Case When type = 'D' Then @data_file_path+Right(physicalname, charindex('\',reverse(physicalname),1)-1) when type = 'L' Then @log_file_path+Right(physicalname, charindex('\',reverse(physicalname),1)-1) Else 'Full Text - code not complete' END +'''' From @filelist SELECT @RestoreStatement='RESTORE DATABASE [AuctionMain] FROM ' + @BackupFiles + ' WITH FILE = 1, ' + @MoveFiles + ', NOUNLOAD, REPLACE, STATS = 20' Print @RestoreStatement Exec(@RestoreStatement) 

没有一个版本包含SQL 2000.这将适用于所有这些:

 use master -- -- check SQL Server version DECLARE @sql_ver int; CREATE TABLE #tmp_sql_ver ( [Index] int, [Name] nvarchar(100), [iVal] int, [cVal] nvarchar(100) ) INSERT INTO #tmp_sql_ver EXEC('xp_msver ProductVersion'); IF (SELECT cast(cVal as char(2)) FROM #tmp_sql_ver) = '8.' SET @sql_ver = 8; ELSE SET @sql_ver = 9; DROP TABLE #tmp_sql_ver; -- -- get mdf/ldf names DECLARE @mdf_name varchar(50) DECLARE @ldf_name varchar(50) DECLARE @RestoreFileListOnly_columns varchar(2000) IF (@sql_ver = 8) BEGIN SET @RestoreFileListOnly_columns = ' LogicalName nvarchar(128), PhysicalName nvarchar(260), [Type] char(1), FileGroupName nvarchar(128), [Size] numeric(20,0), [MaxSize] numeric(20,0), ' END ELSE BEGIN SET @RestoreFileListOnly_columns = ' LogicalName nvarchar(128), PhysicalName nvarchar(260), [Type] char(1), FileGroupName nvarchar(128), [Size] numeric(20,0), [MaxSize] numeric(20,0), FileID bigint, CreateLSN numeric(25,0), DropLSN numeric(25,0) NULL, UniqueID uniqueidentifier, ReadOnlyLSN numeric(25,0) NULL, ReadWriteLSN numeric(25,0) NULL, BackupSizeInBytes bigint, SourceBlockSize int, FileGroupID int, LogGroupGUID uniqueidentifier NULL, DifferentialBaseLSN numeric(25,0) NULL, DifferentialBaseGUID uniqueidentifier, IsReadOnly bit, IsPresent bit ' DECLARE @tmp_ver NVARCHAR(20) SELECT @tmp_ver = CAST(SERVERPROPERTY ('PRODUCTVERSION') AS NVARCHAR) IF @tmp_ver LIKE '1[01].%' BEGIN SET @RestoreFileListOnly_columns = @RestoreFileListOnly_columns + ', TDEThumbpr DECIMAL' END END IF EXISTS (SELECT [table_name] FROM information_schema.tables WHERE [table_name] = 'tmp_RestoreFileListOnly') BEGIN DROP TABLE [tmp_RestoreFileListOnly]; END EXEC ('CREATE TABLE tmp_RestoreFileListOnly ('+@RestoreFileListOnly_columns+');'); INSERT INTO tmp_RestoreFileListOnly EXEC('RESTORE FILELISTONLY FROM DISK = ''' + @bkpfile + '''') PRINT 'RESTORE FILELISTONLY FROM DISK = ''' + @bkpfile + '''' --IF @@ROWCOUNT <> 2 RETURN SELECT @mdf_name = LogicalName FROM tmp_RestoreFileListOnly WHERE Type = 'D' SELECT @ldf_name = LogicalName FROM tmp_RestoreFileListOnly WHERE Type = 'L' DROP TABLE tmp_RestoreFileListOnly 

这可能有帮助。 我想为客户端创build一个脚本,并且需要为从单个位置恢复的多个数据库备份设置最小variables。 我试图避免使用dynamicSQL,因为我觉得这一切都变得有点混乱。

 -- Use VARCHAR as the restore statement doesn't like NVARCHAR DECLARE @data_file_path VARCHAR(512), @log_file_path VARCHAR(512), @backup_path VARCHAR(512), @backup_extension VARCHAR(4), @mdf_extension VARCHAR(4), @ldf_extension VARCHAR(4) -- ** VARIABLES THAT MUST BE SET **-- SET @data_file_path = 'E:\DataPath\' SET @log_file_path = 'F:\LogPath' SET @backup_path = 'B:\BackUpPath' -- **----------------------------**-- SET @backup_extension = '.bak' SET @mdf_extension = '.mdf' SET @ldf_extension = '.ldf' DECLARE @DATABASES_TO_RESTORE TABLE (rownum int IDENTITY (1, 1) PRIMARY KEY NOT NULL, backup_name VARCHAR(64), restore_as VARCHAR(64)) -- ** Declare the Databases to be Restored ** -- INSERT INTO @DATABASES_TO_RESTORE SELECT 'Intranet', 'Intranet_Test' UNION SELECT 'TestAudit', 'TestAudit_Test' -- ** -------------------------------------** -- DECLARE @max_rows INT, @row_count INT SET @row_count = 1 SELECT @max_rows=count(*) FROM @DATABASES_TO_RESTORE WHILE @row_count <= @max_rows BEGIN DECLARE @backup_name VARCHAR(32), @restore_as VARCHAR(32), @logical_data_name VARCHAR(64), @logical_log_name VARCHAR(64), @data_file_full_path VARCHAR(512), @log_file_full_path VARCHAR(512), @full_backup_path VARCHAR(MAX) SELECT @backup_name = backup_name, @restore_as = restore_as FROM @DATABASES_TO_RESTORE WHERE rownum = @row_count SET @full_backup_path = @backup_path + @backup_name + @backup_extension DECLARE @filelist TABLE (LogicalName NVARCHAR(128) NOT NULL, PhysicalName NVARCHAR(260) NOT NULL, [Type] CHAR(1) NOT NULL, FileGroupName NVARCHAR(120) NULL, Size NUMERIC(20, 0) NOT NULL, MaxSize NUMERIC(20, 0) NOT NULL, FileID BIGINT NULL, CreateLSN NUMERIC(25,0) NULL, DropLSN NUMERIC(25,0) NULL, UniqueID UNIQUEIDENTIFIER NULL, ReadOnlyLSN NUMERIC(25,0) NULL , ReadWriteLSN NUMERIC(25,0) NULL, BackupSizeInBytes BIGINT NULL, SourceBlockSize INT NULL, FileGroupID INT NULL, LogGroupGUID UNIQUEIDENTIFIER NULL, DfferentialBaseLSN NUMERIC(25,0)NULL, DifferentialBaseGUID UNIQUEIDENTIFIER NULL, IsReadOnly BIT NULL, IsPresent BIT NULL, TDEThumbprint VARBINARY(32) NULL) INSERT into @filelist EXEC ('RESTORE FilelistOnly FROM DISK = ''' + @full_backup_path + '''') IF @@ROWCOUNT = 2 BEGIN SELECT @logical_data_name = LogicalName FROM @filelist WHERE [Type] = 'D' SELECT @logical_log_name = LogicalName FROM @filelist WHERE [Type] = 'L' SET @data_file_full_path = @data_file_path + @restore_as + @mdf_extension SET @log_file_full_path = @log_file_path + @restore_as + @ldf_extension RESTORE DATABASE @restore_as FROM DISK = @full_backup_path WITH FILE = 1, MOVE @logical_data_name TO @data_file_full_path, MOVE @logical_log_name TO @log_file_full_path END ELSE PRINT 'CANNOT RESTORE DATABASE ' + @restore_as + ' THE BACKUP CONTAINS MORE THAN 1 BACKUP SET' SELECT @row_count = @row_count + 1 END 

又一个修改/实现。 这是我的2美分。 我已经修改了上面的Mevdiven的脚本,以便它将文件恢复到当前的数据库数据目录。 我有一个问题,我不想使用备份文件中定义的位置。

我抓住第一个主文件使用的数据目录

 SELECT top(1) @v_strRestorePath = physical_name FROM sys.master_files 

并将其用作我的目标数据path。

我还发现## FILE_LIST表是悬挂的,所以我把它放在最后。

额外的– “就是这样SQL在堆栈溢出看起来不错

 USE [master] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO IF OBJECT_ID('[dbo].[restoreDB]') IS NOT NULL DROP PROC [dbo].[restoreDB] GO CREATE PROC [dbo].[restoreDB] @p_strDBNameTo SYSNAME, @p_strDBNameFrom SYSNAME, @p_strFQNRestoreFileName VARCHAR(255) AS DECLARE @v_strDBFilename VARCHAR(100), @v_strDBLogFilename VARCHAR(100), @v_strDBDataFile VARCHAR(100), @v_strDBLogFile VARCHAR(100), @v_strExecSQL NVARCHAR(1000), @v_strExecSQL1 NVARCHAR(1000), @v_strMoveSQL NVARCHAR(4000), @v_strREPLACE NVARCHAR(50), @v_strTEMP NVARCHAR(1000), @v_strListSQL NVARCHAR(4000), @v_strServerVersion NVARCHAR(20), @v_strRestorePath varchar(500) SET @v_strREPLACE = '' IF exists (select name from sys.databases where name = @p_strDBNameTo) SET @v_strREPLACE = ', REPLACE' SET @v_strListSQL = '' SET @v_strListSQL = @v_strListSQL + 'IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''##FILE_LIST''))' SET @v_strListSQL = @v_strListSQL + 'BEGIN' SET @v_strListSQL = @v_strListSQL + ' DROP TABLE ##FILE_LIST ' SET @v_strListSQL = @v_strListSQL + 'END ' SET @v_strListSQL = @v_strListSQL + 'CREATE TABLE ##FILE_LIST (' SET @v_strListSQL = @v_strListSQL + ' LogicalName VARCHAR(64),' SET @v_strListSQL = @v_strListSQL + ' PhysicalName VARCHAR(130),' SET @v_strListSQL = @v_strListSQL + ' [Type] VARCHAR(1),' SET @v_strListSQL = @v_strListSQL + ' FileGroupName VARCHAR(64),' SET @v_strListSQL = @v_strListSQL + ' Size DECIMAL(20, 0),' SET @v_strListSQL = @v_strListSQL + ' MaxSize DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' FileID bigint,' SET @v_strListSQL = @v_strListSQL + ' CreateLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' DropLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' UniqueID UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' ReadOnlyLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' ReadWriteLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' BackupSizeInBytes DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' SourceBlockSize INT,' SET @v_strListSQL = @v_strListSQL + ' filegroupid INT,' SET @v_strListSQL = @v_strListSQL + ' loggroupguid UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' differentialbaseLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' differentialbaseGUID UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' isreadonly BIT,' SET @v_strListSQL = @v_strListSQL + ' ispresent BIT' SELECT @v_strServerVersion = CAST(SERVERPROPERTY ('PRODUCTVERSION') AS NVARCHAR) IF @v_strServerVersion LIKE '10.%' BEGIN SET @v_strListSQL = @v_strListSQL + ', TDEThumbpr DECIMAL' --PRINT @v_strServerVersion END SET @v_strListSQL = @v_strListSQL + ')' EXEC (@v_strListSQL) -- We want to get the current data path from this server as the backup file paths may not be the same on the server -- especially wehen switching between Express/Standard instances SELECT top(1) @v_strRestorePath = physical_name FROM sys.master_files; set @v_strRestorePath = REPLACE(@v_strRestorePath, RIGHT(@v_strRestorePath, CHARINDEX('\', REVERSE(@v_strRestorePath))-1),'') --print @v_strRestorePath --' INSERT INTO ##FILE_LIST EXEC ('RESTORE FILELISTONLY FROM DISK = ''' + @p_strFQNRestoreFileName + '''') -- want to see whats in the fillist? --SELECT * FROM ##FILE_LIST DECLARE curFileLIst CURSOR FOR -- Here we restore each file to the current server restore path. Right(...) grabs the file name from the back up SELECT 'MOVE N''' + LogicalName + ''' TO N''' + @v_strRestorePath + Replace(RIGHT(PhysicalName, CHARINDEX('\', REVERSE(PhysicalName))-1),@p_strDBNameFrom, @p_strDBNameTo) + '''' --' FROM ##FILE_LIST SET @v_strMoveSQL = '' OPEN curFileList FETCH NEXT FROM curFileList into @v_strTEMP WHILE @@Fetch_Status = 0 BEGIN SET @v_strMoveSQL = @v_strMoveSQL + @v_strTEMP + ', ' FETCH NEXT FROM curFileList into @v_strTEMP END CLOSE curFileList DEALLOCATE curFileList PRINT 'Killing active connections to the "' + @p_strDBNameTo + '" database' -- Create the sql to kill the active database connections SET @v_strExecSQL = '' SELECT @v_strExecSQL = @v_strExecSQL + 'kill ' + CONVERT(CHAR(10), spid) + ' ' FROM master.dbo.sysprocesses WHERE DB_NAME(dbid) = @p_strDBNameTo AND DBID <> 0 AND spid <> @@spid EXEC (@v_strExecSQL) PRINT 'Restoring "' + @p_strDBNameTo + '" database from "' + @p_strFQNRestoreFileName + '" with ' PRINT ' data file "' + @v_strDBDataFile + '" located at "' + @v_strDBFilename + '"' PRINT ' log file "' + @v_strDBLogFile + '" located at "' + @v_strDBLogFilename + '"' SET @v_strExecSQL = 'RESTORE DATABASE [' + @p_strDBNameTo + ']' SET @v_strExecSQL = @v_strExecSQL + ' FROM DISK = ''' + @p_strFQNRestoreFileName + '''' SET @v_strExecSQL = @v_strExecSQL + ' WITH FILE = 1,' SET @v_strExecSQL = @v_strExecSQL + @v_strMoveSQL SET @v_strExecSQL = @v_strExecSQL + ' NOREWIND, ' SET @v_strExecSQL = @v_strExecSQL + ' NOUNLOAD ' SET @v_strExecSQL = @v_strExecSQL + @v_strREPLACE --PRINT '---------------------------' --PRINT @v_strExecSQL --PRINT '---------------------------' --For Some reason the file list hangs when I was debugging remove it. IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '##FILE_LIST')) BEGIN DROP TABLE ##FILE_LIST END EXEC sp_executesql @v_strExecSQLter 

希望这也有助于一些!

不知道如何添加评论下一个特定的解决scheme,但我刚刚实施的Mevdiven上面提供的解决scheme…

在我的环境(服务器08 r2)中的drop table有一个小问题。 我不得不修改这个使用对象id为了成功地下降。

由于备份文件中有大量的分区,我也有问题,所以我不得不将string更改为nvarchar(MAX)。

我还增加了将数据库恢复到另一个目录的能力(因为我们的开发和生产环境有不同的path)

 CREATE PROC [dbo].[restoreDB] @p_strDBNameTo SYSNAME, @p_strDBNameFrom SYSNAME, @p_strBackupDirectory VARCHAR(255), @p_strRestoreDirectory VARCHAR(255), @p_strFQNBackupFileName VARCHAR(255) AS DECLARE @v_strDBFilename VARCHAR(200), @v_strDBLogFilename VARCHAR(200), @v_strDBDataFile VARCHAR(200), @v_strDBLogFile VARCHAR(200), @v_strExecSQL NVARCHAR(MAX), @v_strMoveSQL NVARCHAR(MAX), @v_strREPLACE NVARCHAR(50), @v_strTEMP NVARCHAR(1000), @v_strListSQL NVARCHAR(4000), @v_strServerVersion NVARCHAR(20) SET @v_strREPLACE = '' IF exists (select name from sys.databases where name = @p_strDBNameTo) SET @v_strREPLACE = ', REPLACE' SET @v_strListSQL = '' SET @v_strListSQL = @v_strListSQL + 'IF OBJECT_ID(''tempdb..##FILE_LIST'') IS NOT NULL DROP TABLE ##FILE_LIST ' SET @v_strListSQL = @v_strListSQL + 'CREATE TABLE ##FILE_LIST (' SET @v_strListSQL = @v_strListSQL + ' LogicalName VARCHAR(64),' SET @v_strListSQL = @v_strListSQL + ' PhysicalName VARCHAR(130),' SET @v_strListSQL = @v_strListSQL + ' [Type] VARCHAR(1),' SET @v_strListSQL = @v_strListSQL + ' FileGroupName VARCHAR(64),' SET @v_strListSQL = @v_strListSQL + ' Size DECIMAL(20, 0),' SET @v_strListSQL = @v_strListSQL + ' MaxSize DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' FileID bigint,' SET @v_strListSQL = @v_strListSQL + ' CreateLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' DropLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' UniqueID UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' ReadOnlyLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' ReadWriteLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' BackupSizeInBytes DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' SourceBlockSize INT,' SET @v_strListSQL = @v_strListSQL + ' filegroupid INT,' SET @v_strListSQL = @v_strListSQL + ' loggroupguid UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' differentialbaseLSN DECIMAL(25,0),' SET @v_strListSQL = @v_strListSQL + ' differentialbaseGUID UNIQUEIDENTIFIER,' SET @v_strListSQL = @v_strListSQL + ' isreadonly BIT,' SET @v_strListSQL = @v_strListSQL + ' ispresent BIT' SELECT @v_strServerVersion = CAST(SERVERPROPERTY ('PRODUCTVERSION') AS NVARCHAR) IF @v_strServerVersion LIKE '10.%' BEGIN SET @v_strListSQL = @v_strListSQL + ', TDEThumbpr DECIMAL' --PRINT @v_strServerVersion END SET @v_strListSQL = @v_strListSQL + ')' EXEC (@v_strListSQL) INSERT INTO ##FILE_LIST EXEC ('RESTORE FILELISTONLY FROM DISK = ''' + @p_strFQNBackupFileName + '''') DECLARE curFileLIst CURSOR FOR SELECT 'MOVE N''' + LogicalName + ''' TO N''' + replace(replace(PhysicalName, @p_strDBNameFrom, @p_strDBNameTo), @p_strBackupDirectory, @p_strRestoreDirectory) + '''' FROM ##FILE_LIST SET @v_strMoveSQL = cast('' as nvarchar(max)) OPEN curFileList FETCH NEXT FROM curFileList into @v_strTEMP WHILE @@Fetch_Status = 0 BEGIN SET @v_strMoveSQL = @v_strMoveSQL + cast(@v_strTEMP as nvarchar(max)) + cast(', ' as nvarchar(max)) FETCH NEXT FROM curFileList into @v_strTEMP END CLOSE curFileList DEALLOCATE curFileList PRINT 'Killing active connections to the "' + @p_strDBNameTo + '" database' -- Create the sql to kill the active database connections SET @v_strExecSQL = '' SELECT @v_strExecSQL = @v_strExecSQL + 'kill ' + CONVERT(CHAR(10), spid) + ' ' FROM master.dbo.sysprocesses WHERE DB_NAME(dbid) = @p_strDBNameTo AND DBID <> 0 AND spid <> @@spid EXEC (@v_strExecSQL) PRINT 'Restoring "' + @p_strDBNameTo + '" database from "' + @p_strFQNBackupFileName + '" with ' PRINT ' data file "' + @v_strDBDataFile + '" located at "' + @v_strDBFilename + '"' PRINT ' log file "' + @v_strDBLogFile + '" located at "' + @v_strDBLogFilename + '"' SET @v_strExecSQL = cast('RESTORE DATABASE [' as nvarchar(max)) + cast(@p_strDBNameTo as nvarchar(max)) + cast(']' as nvarchar(max)) SET @v_strExecSQL = @v_strExecSQL + cast(' FROM DISK = ''' as nvarchar(max)) + cast(@p_strFQNBackupFileName as nvarchar(max)) + cast('''' as nvarchar(max)) SET @v_strExecSQL = @v_strExecSQL + cast(' WITH FILE = 1,' as nvarchar(max)) SET @v_strExecSQL = @v_strExecSQL + @v_strMoveSQL SET @v_strExecSQL = @v_strExecSQL + cast(' NOREWIND, ' as nvarchar(max)) SET @v_strExecSQL = @v_strExecSQL + cast(' NOUNLOAD ' as nvarchar(max)) SET @v_strExecSQL = @v_strExecSQL + cast(@v_strREPLACE as nvarchar(max)) --If want to print string need to do in sections due to limitation of print string length PRINT 'Exec string: ' +cast(len(@v_strExecSQL) as nvarchar(max))+ ' ***:' PRINT substring(@v_strExecSQL,0,3999) PRINT substring(@v_strExecSQL,4000,7999) PRINT substring(@v_strExecSQL,8000,11999) PRINT substring(@v_strExecSQL,12000,15999) PRINT substring(@v_strExecSQL,16000,19999) PRINT substring(@v_strExecSQL,20000,23999) PRINT substring(@v_strExecSQL,24000,27999) PRINT substring(@v_strExecSQL,28000,31999) PRINT substring(@v_strExecSQL,32000,35999) EXEC sp_executesql @v_strExecSQL GO 

This is a link to a framework for automating SQL database restores. It can help to initialize database mirroring and availability groups, execute test restores to verify production backup file integrity, implement a basic log shipping solution and to perform side by side upgrades. Recovery to history points in time is also possible, restores are optimized using the appropriate full, diff, log backups.