要从数据库备份文件还原的SQL Server存储过程

要从数据库备份文件还原的SQL Server存储过程,sql,sql-server,database,database-restore,Sql,Sql Server,Database,Database Restore,我在SQL Server中有一个存储过程,用于从另一台服务器创建的备份文件恢复数据库。它动态构造语句以从磁盘上的备份文件还原,在数据库中创建新用户(因为它被还原到另一台服务器),在两个不同的模式中授权用户,将用户分配到两个单独的角色,然后删除旧用户(从另一台服务器上的旧数据库) 下面是存储过程代码(很抱歉,太长了),但为了测试它,我添加了一个标志参数(@exec bit=0)来控制它是实际执行它生成的SQL语句,还是只是将它们打印出来。如果您传递@exec=1,它将执行SQL,但如果不传递,它只

我在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]
当我在SQLServerEnterpriseManager中单独运行这些语句时,它们都按设计工作

当我使用
@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
“使用数据库名称”将包含在每次执行调用中


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

EXEC(@sql)
在它自己的作用域中运行该sql,它不会为以下命令更改当前数据库。@DavidG,那么如何在新还原的数据库中运行其余命令呢?这些命令中的大多数只在“当前数据库”中运行,并且似乎没有可在另一个数据库中执行的语法变体(如使用完全限定名(
database.Schema.Object
)的select can)。是否有其他方法来执行这些命令,以便对新还原的数据库执行这些命令?您可以通过运行
PRINT DB_NAME()来测试它
,这将向您显示它运行在哪个数据库上下文中。我相信,执行上述操作的唯一方法是将从
使用…
到最后的所有内容作为单个语句运行。@DavidG,我可以想到一个选项,即使用其中的所有语句动态构造一个完整的存储过程,在他重新恢复了数据库,然后使用它的完全限定名执行它。这可能会起作用,但当它完成时,我需要删除它。要使所有语句都能起作用,我需要输入“Go”如果rep对你很重要,请加上这个作为答案,我会把它标记为正确答案。