Fully automated SQL Server Restore

前端 未结 10 1371
予麋鹿
予麋鹿 2020-12-07 16:58

I\'m not very fluent with SQL Server commands.

I need a script to restore a database from a .bak file and move the logical_data and logical_log files to a specific p

相关标签:
10条回答
  • 2020-12-07 17:31
    /*
    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
    
    
    0 讨论(0)
  • 2020-12-07 17:35

    Using

    • http://www.karaszi.com/SQLServer/util_restore_all_in_file.asp
    • http://weblogs.sqlteam.com/dang/archive/2009/06/13/Restore-Database-Stored-Procedure.aspx

    as references, I came up with this .. and I think it works (not tested for backups with multiple files)

    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)
    
    0 讨论(0)
  • 2020-12-07 17:39

    I had same issue, but in my environment I have many backup files (faster backups), and did need to restore to custom location. This query gets latest full backup info and restores to the path you specify. Tested on SQL 2005/2008.

    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)
    
    0 讨论(0)
  • 2020-12-07 17:40

    not sure how to add comments under a particular solution but I have just implemented the solution provided by Mevdiven above...

    There is a slight problem with the drop table in my environment (Server 08 r2). I have had to modify this to use the object id in order to drop successfully.

    I also had problems due to a large number of partitions in the backup file, so I had to change the string to be nvarchar(MAX).

    I also added ability to restore the database into another directory (as our dev vs prod environments have different paths)

    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
    
    0 讨论(0)
提交回复
热议问题