将多个数据库文件还原到多个目录中以获取脚本错

时间:2013-04-17 18:09:53

标签: sql-server

我正在运行一个收到错误的脚本。当我注释掉脚本的一部分时,它说它成功了 - 但实际上并没有做任何事情。该脚本是多个目录中多个数据库的还原脚本。该脚本应该将这些数据库还原到与数据库同名的目录中。我将在这里附上脚本:

   use [master]
GO

set nocount on

declare @curdir nvarchar(400)
declare @line varchar(400)
declare @command varchar(400)
declare @counter bigint
Declare @Database_name varchar(400)
Declare @directory varchar(400)
Declare @filename_name varchar(400)
declare @is_final_restore varchar(1)

set @is_final_restore = 'N'

If (select count (*) from sys.objects where name='Output') <> 0 DROP TABLE output  
If (select count (*) from tempdb.sys.objects where name like '%#Tempoutput%') <> 0 DROP TABLE #Tempoutput   
If (select count (*) from tempdb.sys.objects where name like '%#dirs%') <> 0 DROP TABLE #dirs   

create table #dirs (DIRID bigint identity(1,1), directory varchar(400))
  Set @command = 'dir "E:\MVE_Backups\Full" /S/B/A:A'
 insert into #dirs exec xp_cmdshell @command
  set @counter = (select count(*) from #dirs)
create table #tempoutput (line varchar(400))

create table output (Path_name varchar(400),Directory varchar(400),Files varchar(400),Database_name varchar(400), FileSize varchar(400))
    While @Counter <> 0
      Begin
        Declare @filesize bigint
        set @curdir = (select directory from #dirs where DIRID = @counter)
        set @command = 'dir "' + @curdir +'"'
        insert into #tempoutput
        exec master.dbo.xp_cmdshell @command
           select @line = ltrim(replace(substring(line, charindex(')', line)+1,len(line)), ',', ''))
           from #tempoutput where line like '%File(s)%bytes'
           Set @filesize  = Replace(@line, ' bytes', '')
           Set @filename_name = reverse(left(reverse(@curdir), charindex('\', reverse(@curdir)) -1))
           Set @directory  = reverse(Right(reverse(@curdir), len(@curdir)-charindex('\', reverse(@curdir))))
           Set @Database_name = reverse(left(reverse(@directory), charindex('\', reverse(@directory)) -1))
        Insert into output (Path_name,Directory, Files,Database_name, Filesize) values (@curdir,@directory,@filename_name,@Database_name, @filesize)
        Set @counter = @counter -1
       End
  Delete from output where Path_name is null

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) 

  --- Create Temp tables for Restoring


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 bigint
) 

--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 BIGINT 
,SourceBlockSize INT 
,FilegroupId INT 
,LogGroupGUID uniqueidentifier 
,DifferentialBaseLSN numeric(25) 
,DifferentialBaseGUID uniqueidentifier 
,IsReadOnly INT 
,IsPresent INT 
,TDEThumbPrint uniqueidentifier 
) 

DECLARE dbfiles CURSOR FOR 
SELECT LogicalName, PhysicalName, Type FROM #dbfiles 

declare backup_cur cursor for
    select Path_name, Database_name from output 
open backup_cur

fetch next from backup_cur into @filename_name, @database_name

--Loop through each script.
while @@FETCH_STATUS = 0
BEGIN

    if @is_final_restore = 'Y'
    BEGIN
        set @dirfile = @filename_name

        set @Database_name = @Database_name + '_temp'

        print 'RESTORE DATABASE [' + @database_name + '] FROM  DISK = N''' + @dirfile + ''' WITH FILE = 1, NOUNLOAD'
        print 'GO'
        print 'USE [' + @database_name + ']'
        print 'GO'
        print 'sp_changedbowner ''' + @database_name + '_user'''
        print 'GO'
        print 'USE [master]'
        print 'GO'
        print 'ALTER DATABASE [' + @database_name + '] SET TRUSTWORTHY on'
        print 'GO'
        print 'GRANT UNSAFE ASSEMBLY TO [' + @database_name + '_user]'
        print 'GO'
        print 'sp_configure ''clr enabled'', 1'
        print 'GO'
        print 'reconfigure'
        print 'GO'
    END

    ELSE
    BEGIN

        --PRINT ('Now Restoring Database '+ @database_name+' in Non-Recovery Mode. From File :'+@filename_name  )
        set @dirfile = @filename_name
        --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 NORECOVERY, 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 ''' + 'F:\Database_Files\'+@database_name+'\' + @LogicalName  + '.mdf'', MOVE ' 
        ELSE IF @type = 'L' 
        SET @sql = @sql + '''' + @LogicalName + ''' TO ''' + 'F:\Database_Files\'+@database_name+'\' + @LogicalName + '.ldf''' 
        FETCH NEXT FROM dbfiles INTO @LogicalName, @PhysicalName, @type 
        END 
        PRINT ('EXECUTE master.dbo.xp_create_subdir N'''+'F:\Database_Files\'+@database_name+'''')
        PRINT ('GO')
        PRINT @SQL
        PRINT ('GO')
        close dbfiles
    END
fetch next from backup_cur into @filename_name, @database_name  
END

close backup_cur
deallocate backup_cur
DEALLOCATE dbfiles 

drop table output;

drop table #bdev
drop table #dbfiles

运行时出错:

Msg 213,Level 16,State 7,Line 1 列名或提供的值数与表定义不匹配。 Msg 3013,Level 16,State 1,Line 1 RESTORE HEADERONLY异常终止。

我评论的代码是:

BEGIN
    set @dirfile = @filename_name

    set @Database_name = @Database_name + '_temp'

    print 'RESTORE DATABASE [' + @database_name + '] FROM  DISK = N''' + @dirfile + ''' WITH FILE = 1, NOUNLOAD'
    print 'GO'
    print 'USE [' + @database_name + ']'
    print 'GO'
    print 'sp_changedbowner ''' + @database_name + '_user'''
    print 'GO'
    print 'USE [master]'
    print 'GO'
    print 'ALTER DATABASE [' + @database_name + '] SET TRUSTWORTHY on'
    print 'GO'
    print 'GRANT UNSAFE ASSEMBLY TO [' + @database_name + '_user]'
    print 'GO'
    print 'sp_configure ''clr enabled'', 1'
    print 'GO'
    print 'reconfigure'
    print 'GO'
END

ELSE

2 个答案:

答案 0 :(得分:0)

如果我理解正确,您将在SQL Server 2012服务器上恢复备份。作为文档saysRESTORE HEADERONLY的结果集中有一个名为containment的额外列,该列不在SQL 2008中,但您的#bdev表没有containment柱。如果您添加它,则RESTORE HEADERONLY结果将与表格结构匹配。

就个人而言,我会使用外部脚本来代替TSQL。使用外部脚本处理文件更容易,并且所有动态SQL都难以阅读和排除故障。使用PowerShell中的SMO是一个选项,或者只使用您首选的脚本语言来执行TSQL。

答案 1 :(得分:0)

我弄清楚问题是什么......从SQL 2008 R2到SQL 2012,在创建#bdev时还有其他列缺失。

我通过检查两个SQL服务器的表结构来解决了这个问题,并确定在SQL 2012中,他们添加了一个不在我脚本中的新列...添加此列时,脚本工作正常!