惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
InfoQ
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
B
Blog
罗磊的独立博客
GbyAI
GbyAI
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Security Blog
Microsoft Security Blog
宝玉的分享
宝玉的分享
The GitHub Blog
The GitHub Blog
人人都是产品经理
人人都是产品经理
博客园 - Franky
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
博客园 - 聂微东
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
Visual Studio Blog
MyScale Blog
MyScale Blog
Google DeepMind News
Google DeepMind News
G
Google Developers Blog
aimingoo的专栏
aimingoo的专栏

博客园 - Felix Liang

精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件 精进 Spring Boot 02 | Spring Boot 的文档结构、POM 文件格式的介绍,以及 Maven 的使用。 精进 Spring Boot 01 | Spring Boot 入门,用 Spring Boot 写第一个 Hello World How do I get started with Node.js 修改xampp的mysql默认密码和端口 Visual Studio 2013 错误系统找不到指定文件,0x80070002 Daily Build H公司数据同步的总结 VB2010新特性之——标识语言版本的新命令行选项/langversion (Visual Basic) 为什么开发人员不能估算时间? 获取应用程序的根Url - Felix Liang - 博客园 Lambda 表达式 Lambda Expressions (Visual Basic) 集合初始化器概览(Visual Basic) 宽松委托转换(Relaxed delegate conversion) VB2010 的隐式续行(Implicit Line Continuation) 自动实现属性 Visual Basic 2010 新特性 VS2008 Tips #009 – 您可以在 ASP.NET 的 Web.config 文件中注册用户控件 VS2008 Tips #008 如何创建ASP.NET Web 用户控件并包含在Web 页面中 - Felix Liang
[翻译]SQL Server 未公开的两个存储过程sp_MSforeachtable 和...
Felix Liang · 2011-05-10 · via 博客园 - Felix Liang

SQL Server 未公开的两个存储过程sp_MSforeachtable 和 sp_MSforeachdb

您是否曾经写过代码来处理数据库中的所有表?处理一个 SQL Server实例中的所有数据库的代码又该如何写?然则,您是否知道有多种方法可以解决这问题?您可以创建一个游标cursor包含所有数据表,或者包含SQL Server实例的所有数据库;或者使用非公开(undocumented)的存储过程。本文将向您阐述非公开的存储过程的工作方式,以及应用实例向您展示如何使用它们。非公开的存储过程比之游标更易用。

概述

Microsoft 提供了两个非公开化的存储过程,让您可以迭代处理数据库中的所有表,或者SQL Server 实例中的所有数据库。第一个存储过程是"sp_MSforeachtable",让您可以轻易地使用代码处理数据库中的所有表;另一个是"sp_MSforeachdb",处理SQL Server 实例中的所有数据库。让我们深入地了解这两个存储过程。

sp_MSforeachtable

"sp_MSforeachtable"没有在在线文档中出现,它存在于master数据库中,可以对给定数据库的所有表执行单条或多条T-SQL命令,请看下面的例子。

假如,您需要创建一个临时表,记录当前数据库拥有的表的表名、行记录数。为了实现此功能,您需要执行这样的命令:"select '<mytable>', count(*) from <mytable>"。其中"<mytable>"替换为数据库中的每个表名,并将结果插入到临时表。下面我们用游标与非公开的"sp_MSforeachtable"来分别实现。

使用游标的方式:

下面是输出结果:

下面代码应用非公开的"sp_MSforeachtable"生成相同的结果:

下面是结果:

可见,使用游标与sp_MSforeachtable可生成相同的结果,您认为哪种方式更具可读性,更简单?下面来详细介绍sp_MSforeachtable的语法:

exec @RETURN_VALUE=sp_MSforeachtable @command1, @replacechar, @command2,

@command3, @whereand, @precommand, @postcommand

说明:

  • @RETURN_VALUE – 返回值
  • @command1 – 类型是nvarchar(2000),sp_MSforeachtable最先执行的命令
  • @replacechar – 处理过程中,将命令行的这个字符替换为具体的表名(默认是"?")
  • @command2\@command3:对每个数据表,都会执行这两条命令,@command2在@command1之后执行,@command3在@command2之后执行
  • @whereand – 类型是varchar(2000),提供额外的约束来过滤 sysobjects 表的行
  • @precommand - 类型是varchar(2000),在处理任何表之前执行此命令
  • @postcommand - 类型是varchar(2000),在处理完所有表之后执行此命令

下面几个例子演示此存储过程的用法,处理所有表或者部分表。

下面查询以字母 p 开头的表,使用参数 @whereand 设置过滤条件,代码如下:

下面是结果:

上面的代码使用了参数 @command1 与 @whereand,参数 @whereand 用来设置 WHERE 条件,筛选出以字母 p 开头的表名,我设置了参数值为"and o.name like ''p%''"。如果您希望使用多个条件约束,如以 p 开头或者以 a 开头,设置参数值为:

and o.name like ''p%'' or o.name like ''a%''

如果语句有问题,将 name 的前缀去掉,如下:

and name like ''p%'' or name like ''a%''

注意,上面例子的参数 @command1 使用了"?",它叫做替换字符(replacement character),默认被所有表名替换。如果您需要在命令中使用"?"作为内容而不是被表名替换的替换字符,那么可以使用参数 @replacechar 来设置替换字符。下面例子使用"{"作为替换字符。

下面是结果:

还有两个参数 @precommand 与 @postcommand,看下面例子,把上面例子中的所有语句整合为一个简洁的存储过程调用。

注意上面例子用了全局临时表 ##rowcount,如果用临时表 #rowcount会报错。参数 @precommand 创建全局临时表,只执行了一次,并先于 @command1 的语句执行。@postcommmand 的语句待迭代处理完所有表后执行,也仅执行一次,用于显示结果并删除临时表。

sp_MSforeachdb

sp_MSforeachdb 同样也是在 master 数据库中,它迭代SQL Server 实例中的每个数据库,以执行T-SQL 语句,如"DBCCCHECKDB",在看看它的语法

exec @RETURN_VALUE = sp_MSforeachdb @command1, @replacechar,

@command2, @command3, @precommand, @postcommand

说明:

  • @RETURN_VALUE – 返回值
  • @command1 – 类型是 nvarchar(2000),最先执行的命令
  • @replacechar – 替换字符,命令字符串中被替换为实际的数据库名(默认是"?")
  • @command2\@command3:对每个数据库,都会执行这两条命令,@command2在@command1之后执行,@command3在@command2之后执行
  • @precommand - 类型是varchar(2000),在处理任何数据库之前执行此命令
  • @postcommand - 类型是varchar(2000),在处理完所有数据库之后执行此命令

sp_MSforeachdb 的参数与sp_MSforeachtable 的参数类似,因此,不再特意介绍这些参数。

请看下面的简单例子,此例子将进行数据库备份,然后对每个数据库做"DBCC CHECKDB":

这里我用了三条不同的命令,第一条打印正在处理的数据库名。sp_MSforeachtable 有一个参数用来过滤需要处理的数据表,但是sp_MSforeachdb没有类似的过滤参数。由于SQL Server 不支持对 tempdb 的备份,因此我要跳过tempdb,这是我在每条命令使用 IF 的原因。第二条命令进行数据库备份,最后一条命令对除 tempdb 之外的数据库运行"DBCC CHECKDB"。

运行上面命令之前要先创建目录"c:\temp",下面是部分输出结果:

使用SQL Server非公开存储过程的说明

当使用这些非公开的存储过程时您须小心,并进行测试。由于未公开,意味着Microsoft在任何版本的升级或者补丁包都可能对它们进行修改,并且不做任何告知。因此,您需要在所有的SQL Server版本做全面的测试,测试以验证您的代码是否在新版本中仍然正常运行。

结语

正如您所见,这两个非公开的存储过程比游标易用,以后您可以用它们来迭代处理数据表或数据库。但是请谨记,这两个存储过程是非公开的,Microsoft很可能会随时改变它们的功能。

参考

SQL Server Undocumented Stored Procedures sp_MSforeachtable and sp_MSforeachdb

sp_MSforeachtable