首先说一下一个sql server 没有公开的存储过程:sp_msforeach_worker

以下是生成该存储过程的SQL语句:

/*******************************************************
sp_MSforeach_worker 系统存储过程共4个参数
      @command1    nvarchar(2000) --第一条运行的t-sql指令
      @replacechar    nchar(1)            --指定的占位符号
      @command2    nvarchar(2000) --第二条运行的t-sql指令
      @command3    nvarchar(2000)  --第三条运行的t-sql指令
********************************************************/
/*  
* This is the worker proc for all of the "for each" type procs.  Its function is to read the  
* next replacement name from the cursor (which returns only a single name), plug it into the  
* replacement locations for the commands, and execute them.  It assumes the cursor "hCForEach"  
* has already been opened by its caller.  
*/  
create proc sp_MSforeach_worker  
@command1 nvarchar(2000), @replacechar nchar(1) = N'?', @command2 nvarchar(2000) = null, @command3 nvarchar(2000) = null  
as  
  
create table #qtemp ( /* Temp command storage */  
  qnum    int    NOT NULL,  
  qchar    nvarchar(2000) COLLATE database_default NULL  
)  
  
set nocount on  
declare @name nvarchar(517), @namelen int, @q1 nvarchar(2000), @q2 nvarchar(2000)  
   declare @q3 nvarchar(2000), @q4 nvarchar(2000), @q5 nvarchar(2000)  
declare @q6 nvarchar(2000), @q7 nvarchar(2000), @q8 nvarchar(2000), @q9 nvarchar(2000), @q10 nvarchar(2000)  
declare @cmd nvarchar(2000), @replacecharindex int, @useq tinyint, @usecmd tinyint, @nextcmd nvarchar(2000)  
   declare @namesave nvarchar(517), @nametmp nvarchar(517), @nametmp2 nvarchar(258)  
  
open hCForEach
fetch hCForEach into @name  
  
/* Loop for each database */  
while (@@fetch_status >= 0) begin  
  /* Initialize. */  
  
      /* save the original dbname */  
      select @namesave = @name  
  select @useq = 1, @usecmd = 1, @cmd = @command1, @namelen = datalength(@name)  
  while (@cmd is not null) begin  /* Generate @q* for exec() */  
   /*  
    * Parse each @commandX into a single executable batch.  
    * Because the expanded form of a @commandX may be > OSQL_MAXCOLLEN_SET, we'll need to allow overflow.  
    * We also may append @commandX's (signified by '++' as first letters of next @command).  
    */  
   select @replacecharindex = charindex(@replacechar, @cmd)  
   while (@replacecharindex <> 0) begin  
  
            /* 7.0, if name contains ' character, and the name has been single quoted in command, double all of them in dbname */  
            /* if the name has not been single quoted in command, do not doulbe them */  
            /* if name contains ] character, and the name has been [] quoted in command, double all of ] in dbname */  
            select @name = @namesave  
            select @namelen = datalength(@name)  
            declare @tempindex int  
            if (substring(@cmd, @replacecharindex - 1, 1) = N'''') begin  
               /* if ? Is inside of '', we need to double all the ' in name */  
               select @name = REPLACE(@name, N'''', N'''''')  
            end else if (substring(@cmd, @replacecharindex - 1, 1) = N'[') begin  
               /* if ? Is inside of [], we need to double all the ] in name */  
               select @name = REPLACE(@name, N']', N']]')  
            end else if ((@name LIKE N'%].%]') and (substring(@name, 1, 1) = N'[')) begin  
               /* ? Is NOT inside of [] nor '', and the name is in [owner].[name] format, handle it */  
               /* !!! Work around, when using LIKE to find string pattern, can't use '[', since LIKE operator is treating '[' as a wide char */  
               select @tempindex = charindex(N'].[', @name)  
               select @nametmp  = substring(@name, 2, @tempindex-2 )  
               select @nametmp2 = substring(@name, @tempindex+3, len(@name)-@tempindex-3 )  
               select @nametmp  = REPLACE(@nametmp, N']', N']]')  
               select @nametmp2 = REPLACE(@nametmp2, N']', N']]')  
               select @name = N'[' + @nametmp + N'].[' + @nametmp2 + ']'  
            end else if ((@name LIKE N'%]') and (substring(@name, 1, 1) = N'[')) begin  
               /* ? Is NOT inside of [] nor '', and the name is in [name] format, handle it */  
               /* j.i.c., since we should not fall into this case */  
               /* !!! Work around, when using LIKE to find string pattern, can't use '[', since LIKE operator is treating '[' as a wide char */  
               select @nametmp = substring(@name, 2, len(@name)-2 )  
         select @nametmp = REPLACE(@nametmp, N']', N']]')  
               select @name = N'[' + @nametmp + N']'  
            end  
            /* Get the new length */  
            select @namelen = datalength(@name)  
  
            /* start normal process */  
    if (datalength(@cmd) + @namelen - 1 > 2000) begin  
     /* Overflow; put preceding stuff into the temp table */  
     if (@useq > 9) begin  
      raiserror 55555 N'sp_Msforeach_worker assert failed:  command too long'  
      close hCForEach  
      deallocate hCForEach  
      return 1  
     end  
     if (@replacecharindex < @namelen) begin  
      /* If this happened close to beginning, make sure expansion has enough room. */  
      /* In this case no trailing space can occur as the row ends with @name. */  
      select @nextcmd = substring(@cmd, 1, @replacecharindex)  
      select @cmd = substring(@cmd, @replacecharindex + 1, 2000)  
      select @nextcmd = stuff(@nextcmd, @replacecharindex, 1, @name)  
      select @replacecharindex = charindex(@replacechar, @cmd)  
      insert #qtemp values (@useq, @nextcmd)  
      select @useq = @useq + 1  
      continue  
     end  
     /* Move the string down and stuff() in-place. */  
     /* Because varchar columns trim trailing spaces, we may need to prepend one to the following string. */  
     /* In this case, the char to be replaced is moved over by one. */  
     insert #qtemp values (@useq, substring(@cmd, 1, @replacecharindex - 1))  
     if (substring(@cmd, @replacecharindex - 1, 1) = N' ') begin  
      select @cmd = N' ' + substring(@cmd, @replacecharindex, 2000)  
      select @replacecharindex = 2  
     end else begin  
      select @cmd = substring(@cmd, @replacecharindex, 2000)  
      select @replacecharindex = 1  
     end  
     select @useq = @useq + 1  
    end  
    select @cmd = stuff(@cmd, @replacecharindex, 1, @name)  
    select @replacecharindex = charindex(@replacechar, @cmd)  
   end  
  
   /* Done replacing for current @cmd.  Get the next one and see if it's to be appended. */  
   select @usecmd = @usecmd + 1  
   select @nextcmd = case (@usecmd) when 2 then @command2 when 3 then @command3 else null end  
   if (@nextcmd is not null and substring(@nextcmd, 1, 2) = N'++') begin  
    insert #qtemp values (@useq, @cmd)  
    select @cmd = substring(@nextcmd, 3, 2000), @useq = @useq + 1  
    continue  
   end  
  
   /* Now exec() the generated @q*, and see if we had more commands to exec().  Continue even if errors. */  
   /* Null them first as the no-result-set case won't. */  
   select @q1 = null, @q2 = null, @q3 = null, @q4 = null, @q5 = null, @q6 = null, @q7 = null, @q8 = null, @q9 = null, @q10 = null  
   select @q1 = qchar from #qtemp where qnum = 1  
   select @q2 = qchar from #qtemp where qnum = 2  
   select @q3 = qchar from #qtemp where qnum = 3  
   select @q4 = qchar from #qtemp where qnum = 4  
   select @q5 = qchar from #qtemp where qnum = 5  
   select @q6 = qchar from #qtemp where qnum = 6  
   select @q7 = qchar from #qtemp where qnum = 7  
   select @q8 = qchar from #qtemp where qnum = 8  
   select @q9 = qchar from #qtemp where qnum = 9  
   select @q10 = qchar from #qtemp where qnum = 10  
   truncate table #qtemp  
   exec (@q1 + @q2 + @q3 + @q4 + @q5 + @q6 + @q7 + @q8 + @q9 + @q10 + @cmd)  
   select @cmd = @nextcmd, @useq = 1  
  end /* while @cmd is not null, generating @q* for exec() */  
  
  /* All commands done for this name.  Go to next one. */  
  fetch hCForEach into @name  
end /* while FETCH_SUCCESS */  
close hCForEach  
deallocate hCForEach  
return 0

备注:使用此过程前必须手工声明一名为 hCForEach 的全局游标

<隐藏代码可以不看>

exec(N'declare hCForEach cursor global for select name from master.dbo.sysdatabases d ' +  
   N' where (d.status & ltrim(str(convert(int, 0x03e0), 11))  = 0)' +  
   N' and ((DATABASEPROPERTY(d.name, ''issingleuser'') = 0 and (has_dbaccess(d.name) = 1)) or ' +  
   N' ( DATABASEPROPERTY(d.name, ''issingleuser'') = 1 and not exists ' +  
   N' (select * from master.dbo.sysprocesses p where dbid = d.dbid and p.spid <> @@spid)))' )
exec sp_Msforeach_worker @command1="print '?'",@command2="dbcc checkdb (?) "

<以上是被隐藏的代码>

言归正传,下面开始写如何进行数据库还原:

1.我们之所以无法在程序里无法进行数据库还原操作,是因为我们自己在访问数据库,或者有别的用户在访问着我们要还原的数据库,这种情况下,我们很自然的就想到了用关闭掉用户连接的方法来实现我们的数据库还原操作.那么,如何关闭掉用户的连接呢?

2.关闭用户连接,也就是杀死相应的进程标识.在SQL SERVER里,我们可以通过master库里的kill + 进程ID 语句来杀掉某个进程.此时,我们就应该想办法来取出和我们要还原的数据库的相关进程ID.假设我们要还原的数据库名叫"testRestore",那么,我们可以通过select spid from master.dbo.sysprocesses where dbid=db_id('testRestore');语句来获取和testRestore数据库相关的进程ID,此时它获得的是一个记录集,即有几个连接用户,它就会有几条记录.

3.取出记录集后,我们很自然地就想到了要用游标来实现通过循环来杀死进程的方法.此时,我们就通过刚才说的sql server未公开的存储过程sp_msforeach_worker来实现此操作.

4.根据sp_msforeach_worker游标操作存储过程,我们写出如下语句来杀死所有与testRestore连接的进程:

--杀死所有与testRestore连接进程
declare hcforeach cursor global for select 'kill '+rtrim(spid) from master.dbo.sysprocesses
where dbid=db_id('testRestore');--声明并生成一个游标,取得所有与testRestore相关联的进程ID
exec sp_msforeach_worker'?'    --运行sp_msforeach_worker存储过程,执行杀死进程的过程

5.此时杀死了进程,我们就可以按照正常的还原数据库的语句开始进行还原了.

--进行数据库还原

restore database testRestore from disk='d:/test.bak';

6.总结:关于这个数据库还原问题,从我开始学习asp做数据库备份与还原时就一直困扰着我.今天终于把它搞定了!当然,以上几点只是把方法给大概说了一下,真正做起来,我觉得我们最好还是把"杀掉连接进程"与"数据库还原"语句写成一个master库的存储过程,然后传入一个数据库备份地址参数,此时,仅需要调用此存储过程,只要传入的备份是一个正确的备份,那么,无论有人在访问还是无人在访问,我们均可以正常地还原数据库了.

文章来源:http://hanxianlong888.blog.163.com/blog/static/2139025200771325422660

[导入]用程序来还原数据库(一个遗留了两年的问题)相关推荐

  1. oracle导入多个dmp文件到一个用户,Oracle dmp文件导入(还原)到不同的表空间和不同的用户下...

    ------------------------------------- 从生产环境拷贝一个dmp备份文件,在另外一台电脑上搭建测试环境,用imp命令导入dmp文件时提示如下错误: 问题描述: IM ...

  2. mysql批量导入json_微信小程序云开发---数据库批量导入json文件

    马上大学毕业了,于是最近做了一个关于班级信息的微信小程序,主要记录一些班级活动的照片.同学的通讯录...... 主要使用了微信小程序的云开发平台,因为班级同学的信息,班长都会有Excel表格统计的信息 ...

  3. 微信小程序云开发---数据库批量导入json文件

    马上大学毕业了,于是最近做了一个关于班级信息的微信小程序,主要记录一些班级活动的照片.同学的通讯录...... 主要使用了微信小程序的云开发平台,因为班级同学的信息,班长都会有Excel表格统计的信息 ...

  4. 新手如何用微信小程序和云数据库做一个论坛?【帖子页】

    新手小白用微信小程序和云数据库做一个论坛[帖子页] 先放个效果图 由于后面换了头像,所以评论的头像和发帖的头像不一样. 要做个同款论坛,首先需要用到云数据库.在微信开发者工具的左上角开通云开发就可以了 ...

  5. 微信小程序:后台数据库与云数据库对比取最后一个值并且取用定时更新

    微信小程序:后台数据库与云数据库对比取最后一个值并且取用定时更新的方式来现在在前端网页上 我们有时候会遇到这样的问题,在后台数据库提取到数据后想要提取他们中的某些有共同特征的一些数据,这时候我们就可以 ...

  6. Mysql备份还原数据库之mysqldump实例及参数详细说明

    我们在运营项目的过程中肯定会遇到备份数据库,还原数据库的情况,我们一般用一下两种方式来处理: 1.使用into outfile 和 load data infile导入导出备份数据 这种方法的好处是, ...

  7. SQL 备份与恢复之还原数据库

    一.还原用户数据库 1."还原数据库"基本操作 (1)目标数据库 在该列表中输入要还原的数据库.您可以输入新的数据库,也可以从下拉列表中选择现有的数据库.该列表包含了服务器上除系统 ...

  8. SQL Server 备份与恢复之八:还原数据库

    本文主要来源于Microsoft<SQL Server 2008 R2联机丛书>.转裁请注明出处. 一.还原用户数据库 1."还原数据库"基本操作 (1)目标数据库 在 ...

  9. t-sql还原数据库_如何更新T-SQL工具箱数据库

    t-sql还原数据库 介绍 (Introduction) In an earlier article, Solve Time Zone, GMT, and UTC problems using the ...

最新文章

  1. [引]ASP.NET 中 事务处理(SqlTransaction)示例
  2. py02-python基础
  3. LVM逻辑卷轴管理和磁盘配额实验
  4. [新活动] 2015年推广返利活动
  5. 【阿里聚安全·安全周刊】Python库现后门 可窃取用户SSH信息|Facebook再曝300万用户数据泄露...
  6. 解决夜神模拟器无法联机调试 adb server version (**) doesn't match this client (**); killing...
  7. 数据结构—链表-单链表基本操作实现
  8. Android 应用快捷方式 ShortcutManager 简单说明
  9. Java URLEncoder 和 URLDecoder 对中文进行编码和解码
  10. python将音频转换成文字_用Python将音频内容转换为文本格式
  11. Paradise(天堂)勒索病毒解密工具
  12. 20135202闫佳歆——信息安全系统设计基础第七周学习总结
  13. c语言编程实现红绿灯,C语言实现红绿灯.doc
  14. apk软件去广告 傻瓜教程
  15. Unity常用工作视图(上)(5大基本视图)
  16. 调用微信二维码识别开源库
  17. DTS北洋曳舞社网站开发手记
  18. 【渝粤题库】国家开放大学2021春2408中国当代文学题目
  19. 关于 I/O 的五分钟法则
  20. 有关OLE对象的使用(1)

热门文章

  1. oracle数据库12528,解决(Oracle)ORA-12528: TNS: 监听程序: 所有适用例程都无法建立新连接 问题...
  2. 方法到位,Linux也不难学会
  3. 单步调试_keil for arm 调试时无法单步运行及打断点
  4. linux网站权限怎么设置好,linux网站权限设置方法,网站安全配置,linux网站权限...
  5. 用计算机演银河系,天文学家利用计算机模拟类银河星系
  6. mongo 创建索引_索引系列:2dsphere索引
  7. matlab计算多张图像的灰度直方图_MATLAB图像处理基本操作
  8. enumerate在python中的意思_Python中enumerate用法详解
  9. BZOJ 2157 「国家集训队」旅游(树链剖分,线段树,边权转点权)【BZOJ计划】
  10. 2019年ACM团队预备赛(题解)