简体   繁体   English

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

[英]SQL Server stored procedure to Restore from Database backup file

I have a stored procedure in SQL Server designed to restore a database from a backup file created from a different server. 我在SQL Server中有一个存储过程,旨在从其他服务器创建的备份文件中还原数据库。 It dynamically constructs statement to restore from a backup file on disk, create a new user in the database (because it's being restored to a different server), authorize the user in two different schemas, assign the user to two separate roles, and then drop the old user (from the old database on the other server). 它动态构造语句以从磁盘上的备份文件还原,在数据库中创建一个新用户(因为它正在还原到另一台服务器),以两种不同的模式授权该用户,将该用户分配给两个单独的角色,然后删除旧用户(来自另一台服务器上的旧数据库)。

The stored procedure code is below (sorry it's so long), but so I could test it, I added a flag parameter ( @exec bit = 0 ) to control whether it actually executed the SQL statements it generated, or just printed them out. 存储过程代码在下面(很长一段时间),但是我可以对其进行测试,我添加了一个标志参数( @exec bit = 0 )来控制它是否实际执行所生成的SQL语句,或者只是将其打印出来。 If you pass @exec = 1 it executes the SQL, but if not, it just prints them out so I can run them separately to test the dynamic SQL code generation. 如果传递@exec = 1,它将执行SQL,但是如果不传递,它将只打印它们,因此我可以分别运行它们以测试动态SQL代码生成。 Since the stored procedure code calls restore, and you cannot restore the current database, it has to be run from another database on the same server, but in the stored procedure, after it executes the Restore , it switches the current DB to the newly restored database to execute the remaining SQL statements. 由于存储过程代码调用restore,并且您无法还原当前数据库,因此必须从同一服务器上的另一个数据库中运行它,但是在存储过程中,在执行Restore ,它将当前数据库切换到新还原的数据库。数据库执行剩余的SQL语句。 The SQL statements it constructs are as follows: 它构造的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]

When I run these statements separately in SQL Server Enterprise Manager, it all works as designed. 当我在SQL Server企业管理器中分别运行这些语句时,它们均按设计工作。

When I run the stored procedure with @exec=1 , it executes each of these statements individually using Exec ([SQL]) . 当我使用@exec=1运行存储过程时,它将使用Exec ([SQL])单独执行每个语句。 However, although everything appears to complete successfully except for the Drop User statement, which throws an error 但是,尽管除Drop User语句之外的所有内容似乎都已成功完成,这会引发错误

User does not exist in database 用户在数据库中不存在

Results from running the stored procedure: 运行存储过程的结果:

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].

When I look at the resulting database itself, (even after a refresh) the newly created user is not in the database, and the old user from the other server is still there. 当我查看生成的数据库本身时(即使刷新后),新创建的用户不在数据库中,而另一台服务器上的旧用户仍在该数据库中。

 ******************************************************
 ****** 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

"USE db_name" whould be included for every EXEC call. 每个EXEC调用应包括“ USE db_name”。

Or run the scripts as one large script rather than multiple scripts. 或者将脚本作为一个大脚本而不是多个脚本运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM