从数据库备份文件

时间:2018-03-27 00:05:38

标签: sql sql-server database database-restore

我在SQL Server中有一个存储过程,用于从不同服务器创建的备份文件中恢复数据库。它动态构建语句以从磁盘上的备份文件进行还原,在数据库中创建新用户(因为它正在还原到其他服务器),以两种不同的模式授权用户,将用户分配给两个不同的角色,然后删除旧用户(从另一台服务器上的旧数据库)。

存储过程代码如下(对不起,这很长),但我可以测试它,我添加了一个标志参数(@exec bit = 0)来控制它是否实际执行了它生成的SQL语句,或者只是将它们打印出来。如果你传递@exec = 1它会执行SQL,但如果没有,它只是打印出来,所以我可以单独运行它们来测试动态SQL代码的生成。由于存储过程代码调用还原,并且您无法还原当前数据库,因此必须从同一服务器上的另一个数据库运行,但在存储过程中,在执行Restore后,它会切换当前数据库到新恢复的数据库以执行剩余的SQL语句。它构造的SQL语句如下:

Restore Database [newDBName]
from disk = N'\\BTSSqlTest1\lien_refreshes\BackUps\LASDB.1.31s100.bak'  
with File = 1,
move N'lasdb' to N'E:\lien_refreshes\SQLData\newDBName.mdf',
move N'lasdb_log' to N'E:\lien_refreshes\SQLData\newDBName.ldf',
NoUnload, Replace, Stats = 25;


Use [newDBName]

Create User [domain\NewUserName]

Grant execute to [domain\NewUserName]

Alter Authorization On Schema::[db_backupoperator] to [domain\NewUserName]

Alter Authorization On Schema::[db_Owner] to [domain\NewUserName]

sp_AddRolemember 'db_backupoperator', domain\NewUserName'

sp_AddRolemember 'db_owner', domain\NewUserName'

sp_DropUser [domain\OldUserName]

当我在SQL Server企业管理器中单独运行这些语句时,它都按设计工作。

当我使用@exec=1运行存储过程时,它会使用Exec ([SQL])单独执行每个语句。但是,尽管所有内容似乎都成功完成,但Drop User语句除外,它会引发错误

  

数据库中不存在用户

运行存储过程的结果:

25 percent processed. 
50 percent processed. 
75 percent processed. 
100 percent processed. 
Processed 779144 pages for database 'newDBName', file 'lasdb' on file 1.
Processed 6 pages for database 'newDBName', file 'lasdb_log' on file 1. 
RESTORE DATABASE successfully processed 779150 pages in 11.532 seconds (527.845 MB/sec). 
Database [newDBName] restored. 
Switched to Database [newDBName]. 
Execute granted to user [domain\NewUserName]. 
User [domain\NewUserName] authorized in schema db_backupoperator. 
User [domain\NewUserName] authorized in schema db_Owner. 
User [domain\NewUserName] added to role db_backupoperator. 
User [domain\NewUserName] added to role db_Owner. 
Msg 15008, Level 16, State 1, Procedure sp_dropuser, Line 12 
User domain\OldUserName' does not exist in the current database. 
Dropped User [domain\OldUserName].

当我查看生成的数据库本身时(即使刷新后),新创建的用户不在数据库中,而其他服务器中的旧用户仍在那里。

 ******************************************************
 ****** Stored proc ***********************************
 Create PROCEDURE RestoreProdTest
 @fileSpec nvarchar(400), 
 @exec bit = 0
 As
 Set NoCount On
 declare @nl Char(2) = char(13) + char(10)
 declare @2nl char(4) = @nl + @nl
 -- --------------------------------
 declare @debugMsg varchar(max) = 'Variable Values:' + @nl
 declare @sqlCode varchar(max) = 'Executable SQL Code:' + @nl

   declare @dbNm nvarchar(50) = 'newDBName' 
   declare @user varchar(40) = 'domain\NewUserName' 
   declare @dbId int = DB_Id(@dbNm)
   -- ----------------------------------------------------------------
   Declare @tab Table 
          (logNm varchar(256), phyNm varchar(300), 
        Typ varchar, FilGrpNm varChar(128), Siz varchar(128), 
           MaxSize varChar(128), FileId varchar(128), 
           CreateLSN varChar(128), 
           DropLSN varchar(128), UniqueId varChar(128), 
           ROLSN varchar(128), 
           RWLSN varchar(128), BkSizBytes varChar(128), 
           SrceBlckSize varchar(128), 
           FileGrpId varchar(128), LogGrpId varChar(128), 
           DiffBaseLSN varchar(128), 
           DiffBaseGUID varchar(128), IsReadOnly varChar(128), 
           IsPresent varchar(128), ThumbPrint varchar(128)) 
   -- ----------------------------------------------------------
   Insert @tab(logNm, phyNm, Typ, FilGrpNm, Siz, MaxSize, FileId, 
          CreateLSN, DropLSN, UniqueId, ROLSN, RWLSN, BkSizBytes, 
          SrceBlckSize, FileGrpId, LogGrpId, DiffBaseLSN, 
          DiffBaseGUID, IsReadOnly, IsPresent, ThumbPrint)
   Exec('Restore fileListOnly from disk=''' + @fileSpec + '''')
   declare @oldDataFileSpec varChar(400),
           @oldLogFileSpec  varChar(400)
   Set @oldDataFileSpec = (Select logNm from @tab where Typ = 'D')
   Set @oldLogFileSpec  = (Select logNm from @tab where Typ = 'L')
   -- -------------------------------------
   declare @dataFile varChar(400)
   declare @logFile varChar(400)
   Select @dataFile = physical_name
   from sys.Master_Files 
   Where Database_Id = @dbId and type = 0
   Select @logFile = physical_name
   from sys.Master_Files
   Where Database_Id = @dbId and type = 1

   declare @killSql nVarChar(200) = 'msdb.dbo.sp_KillUserProc '  

   declare @restoreSql nVarChar(1000) = 
          N'Restore Database [' + @dbNm + ']' + @nl + 
          'from disk = N''' + @fileSpec + ''' with File = 1,' + @nl +
          '   move N''' + @oldDataFileSpec + '''' + ' to N''' + 
              @dataFile + ''',' + @nl +
          '   move N''' + @oldLogFileSpec  + '''' + ' to N'''  + 
              @logFile + ''',' + @nl +
          '   NoUnload, Replace, Stats = 25;'


   declare @spids table (spid integer primary key not null)
   insert @spids(spid)
   select session_id from sys.dm_exec_sessions
   where database_id = @dbId
   -- ----------------------
   declare @spid int = 0
   declare @spidstr varchar(4)
   while exists (select * from @spids where spid > @spid) begin
          Select @spid = min(spid) from @spids where spid > @spid
          set @spidstr = format(@spid, '0')
          set @sqlCode += @killSql + @spidstr + @nl
   end
   -- --------------------------------------------

   if @exec = 1 Begin 
          Set @spid = 0
          while exists (select * from @spids where spid > @spid) begin
                 Select @spid = min(spid) from @spids where spid > @spid
                 set @spidstr = format(@spid, '0')
                 exec(@killSql + @spidstr)
          end
          -- ------------------------------------------------
          exec (@restoreSql)
          print ' Database [' + @dbNm + '] restored.'
   end
   else Set @sqlCode += @restoreSql + @2nl 

   -- Switch to new restored database
   declare @UseSql nVarChar(100) = 'Use [' + @dbNm + ']'
   if @exec = 1 begin
          exec (@UseSql) 
          print 'Switched to Database [' + @dbNm + '].'
   end else Set @sqlCode += @UseSql + @2nl

   -- Grant execute permissions (also creates the user)
   declare @grantSql nVarChar(1000) = N'Grant execute to [{User}]'
   Set @grantSql = Replace(@grantSql, '{User}', @user)
   if @exec = 1  begin
          exec (@grantSql) 
          print 'Execute granted to user [' + @user + '].'
   end else Set @sqlCode += @grantSql + @2nl

   -- Assign user to schemas -------------
   declare @schmSql nVarChar(200) = 
          N'Alter Authorization On Schema::[db_backupoperator] to [{user}]'
   Set @schmSql = Replace(@schmSql, '{User}', @user)
   if @exec = 1 begin
          exec (@schmSql) 
          print 'User [' + @user + '] authrzd in schema db_backupoperator.'
   end else Set @sqlCode += @schmSql + @2nl
   -- ----------------------------
   Set @schmSql = Replace(@schmSql, 'db_backupoperator', 'db_Owner')
   if @exec = 1 begin
          exec (@schmSql) 
          print 'User [' + @user + '] authorized in schema db_Owner.'
   end else Set @sqlCode += @schmSql + @2nl
   -- --------------------------------------------------

   -- Grant backup operator & dbOwner Roles 
   declare @roleSql nVarChar(1000) = 
          'sp_AddRolemember ''db_backupoperator'', ''{User}''' 
   Set @roleSql = Replace(@roleSql, '{User}', @user)
   if @exec = 1 begin
          exec (@roleSql) 
          print 'User [' + @user + '] added to role db_backupoperator.'
   end else Set @sqlCode += @roleSql + @2nl
   -- ---------------------------
   set @roleSql = 'sp_AddRolemember ''db_owner'', ''{User}''' 
   Set @roleSql = Replace(@roleSql, '{User}', @user)
   if @exec = 1 begin
          exec (@roleSql) 
          print 'User [' + @user + '] added to role db_Owner.'
   end else Set @sqlCode += @roleSql + @2nl

   -- ----- Drop PROD User -----------
   declare @dropUserSql nVarchar(50) = 
          'sp_DropUser [rose\LasPROD_Svc]' 
   if @exec = 1 begin
          exec (@dropUserSql) 
          print 'Dropped User [rose\LasPROD_Svc].'
   end else Set @sqlCode += @dropUserSql + @2nl
   -- ---------------------------
   if @exec = 0 print @sqlCode
   Return 0

1 个答案:

答案 0 :(得分:0)

每次EXEC调用都应包含“USE db_name”。

或者将脚本作为一个大脚本而不是多个脚本运行。