介绍 (Introduction)

There have always been some undocumented objects in SQL Server that are used internally by Microsoft, but they can be used by anybody that have access to it. One of those objects is a stored procedure called sp_MSforeachtable.

Microsoft内部始终使用SQL Server中一些未记录的对象,但是有权访问它的任何人都可以使用它们。 这些对象之一是称为sp_MSforeachtable的存储过程。

sp_MSforeachtable is a stored procedure that is mostly used to apply a T-SQL command to every table, iteratively, that exists in the current database.

sp_MSforeachtable是一个存储过程,通常用于将T-SQL命令迭代地应用于当前数据库中存在的每个表。

Because official documentation from Microsoft doesn’t exist, the majority of people do not know about the existence of all of these parameters and how this stored procedure can be used to perform more than a simple operation over all the database tables.

由于不存在Microsoft的官方文档,因此大多数人不知道所有这些参数的存在以及如何使用此存储过程对所有数据库表执行简单的操作以外的其他操作。

This is main purpose of this article. To provide as much information as possible for this undocumented SQL Server stored procedure so everybody can take the maximum advantage when use it.

这是本文的主要目的。 为该未记录SQL Server存储过程提供尽可能多的信息,以便每个人都可以在使用它时最大程度地利用它。

典型用法 (Typical usages)

From my experience, I have found in the majority of use cases, people using this stored procedure to:

根据我的经验,我发现在大多数用例中,使用此存储过程的人员可以:

  • perform an unconditional reindex over all tables in the database: 对数据库中的所有表执行无条件重新索引:
 EXEC sp_MSforeachtable 'DBCC DBREINDEX(''?'')'
  • truncate all tables in the database: 截断数据库中的所有表:
 EXEC sp_MSforeachtable 'TRUNCATE TABLE ?'
  • get the information about the number of records from all tables in the database: 从数据库的所有表中获取有关记录数的信息:
 EXEC sp_MSforeachtable 'SELECT ''?'' TableName, Count(1) NumRecords FROM ?'

I think by now you should get the idea on how to use this undocumented stored procedure and also realized that the question mark (?) it is used as the replacement of the table and during the execution it will be replaced by the appropriate table name.

我认为,现在您应该对如何使用此未记录的存储过程有所了解,并且还意识到将问号(?)用作表的替换,并且在执行过程中它将被适当的表名替换。

But the above are only the examples for the typical usage of the sp_MSforeachtable stored procedure. This stored procedure allows more parameters. If only one is passed (as the above examples) it will use by default the @command1 parameter.

但是以上只是sp_MSforeachtable存储过程的典型用法示例。 此存储过程允许更多参数。 如果仅传递一个(如上述示例),则默认情况下将使用@ command1参数。

sp_MSforeachtable参数 (sp_MSforeachtable parameters)

So how to know the rest of the parameters if this is an undocumented stored procedure?

那么,如果这是一个未记录的存储过程,那么如何知道其余参数呢?

We can easily find out the parameters for the sp_MSforeachtable stored procedure by searching for it in the SQL Server Management Studio (SSMS). In SSMS, drill down to “Databases / System Databases / master / Programmability / Stored Procedures / System Stored Procedures” and look for sys.sp_MSforeachtable’s parameters:

通过在SQL Server Management Studio(SSMS)中进行搜索,我们可以轻松找到sp_MSforeachtable存储过程的参数。 在SSMS中,向下钻取至“ 数据库/系统数据库/主数据库/可编程性/存储过程/系统存储过程 ”,然后寻找sys.sp_MSforeachtable的参数:

@command1, @command2, @command3 sp_MSforeachtable stored procedure requires at least one command to be executed (@command1) but it allows up to 3 commands to be executed. Note that it will start to execute first the @command1 and then @command2 and @command3 by the last and this for each table.

@ command1,@ command2,@ command3 sp_MSforeachtable存储过程要求至少执行一个命令(@ command1),但最多允许执行3个命令。 请注意,它将首先开始执行@ command1,然后在最后执行@ command2和@ command3,并对每个表执行此操作。

@precommand Use this parameter to provide a command to be executed before the @command1. It is useful to set variable environments or perform any kind of initialization.

@precommand使用此参数可提供要在@ command1之前执行的命令。 设置可变环境或执行任何类型的初始化都是有用的。

@postcommand Use this parameter to provide a command to be executed after all the commands being executed successfully. It is useful for control and cleanup processes.

@postcommand使用此参数可提供所有命令成功执行后要执行的命令。 这对于控制和清理过程很有用。

@replacechar By default, a table is represented by the question mark (?) character. This parameter allows you to change this character. @replacechar默认情况下,表由问号(?)字符表示。 此参数允许您更改此字符。

@whereand By default, sp_MSforeachtable is applied to all user tables in the database. Use this parameter to filter the tables that you want to work with. On the next section, I will explain how you can filter the tables.

@whereand默认情况下, sp_MSforeachtable应用于数据库中的所有用户表。 使用此参数可以筛选要使用的表。 在下一节中,我将解释如何过滤表。

sp_MSforeachtable定义 (sp_MSforeachtable definition)

For a better understanding of the sp_MSforeachtable stored procedure let see it’s code. To get this stored procedure code, in SSMS right-click on the stored procedure name and choose the Modify option.

为了更好地了解sp_MSforeachtable存储过程,请查看其代码。 要获取此存储过程代码,请在SSMS中右键单击存储过程名称,然后选择“ 修改”选项。

This will create a new query window with the respective stored procedure code:

这将使用相应的存储过程代码创建一个新的查询窗口:


USE [master]
GO
/****** Object:  StoredProcedure [sys].[sp_MSforeachtable]    Script Date: 8/18/2017 8:47:44 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GOALTER proc [sys].[sp_MSforeachtable]@command1 nvarchar(2000), @replacechar nchar(1) = N'?', @command2 nvarchar(2000) = null,@command3 nvarchar(2000) = null, @whereand nvarchar(2000) = null,@precommand nvarchar(2000) = null, @postcommand nvarchar(2000) = null
as/* This proc returns one or more rows for each table (optionally, matching
@where), with each table defaulting to its own result set *//* @precommand and @postcommand may be used to force a single result set via
a temp table. *//* Preprocessor won't replace within quotes so have to use str(). */declare @mscat nvarchar(12)select @mscat = ltrim(str(convert(int, 0x0002)))if (@precommand is not null)exec(@precommand)/* Create the select */exec(N'declare hCForEachTable cursor global for select ''['' +
REPLACE(schema_name(syso.schema_id), N'']'', N'']]'') + '']'' + ''.'' + ''['' +
REPLACE(object_name(o.id), N'']'', N'']]'') + '']'' from dbo.sysobjects o join
sys.all_objects syso on o.id = syso.object_id '+ N' where OBJECTPROPERTY(o.id, N''IsUserTable'') = 1 ' + N' and o.category & ' + @mscat + N' = 0 '+ @whereand)declare @retval intselect @retval = @@errorif (@retval = 0)exec @retval = sys.sp_MSforeach_worker @command1, @replacechar, @command2, @command3, 0if (@retval = 0 and @postcommand is not null)exec(@postcommand)return @retval

You can see now the full code of this undocumented stored procedure. In the header, you can confirm the existence of the parameters referred in the previous section. You can also see that this procedure uses a Cursor (N’declare hCForEachTable cursor global) to go through all user tables (where OBJECTPROPERTY(o.id, N”IsUserTable”) = 1) in the current database. Plus, at the end it concatenates the select statement with whatever we pass in the @whereand parameter. Looking at the code, it joins dbo.sysobjects with sys.all_objects (from dbo.sysobjects o join sys.all_objects syso) so we just need to work from here.

现在,您可以看到此未记录的存储过程的完整代码。 在标题中,您可以确认上一节中提到的参数是否存在。 您还可以看到此过程使用游标( N'declare hCForEachTable cursor global )遍历当前数据库中的所有用户表( 其中OBJECTPROPERTY(o.id,N” IsUserTable”)= 1 )。 另外,最后,它将select语句与我们在@whereand参数中传递的内容连接起来 。 查看代码,它将dbo.sysobjects与sys.all_objects连接( 来自dbo.sysobjects或join sys.all_objects syso ),所以我们只需要从这里开始工作。

完整的例子 (Full example)

Now that we have the sp_MSforeachtable stored procedure definition let’s practice with an example so we can try to cover all parameters.

现在我们有了sp_MSforeachtable存储过程的定义,让我们以一个示例进行练习,以便我们尝试覆盖所有参数。

The AdventureWorks database has a HumanResources schema so I am using this database for this example.

AdventureWorks数据库具有HumanResources模式,因此在此示例中我将使用此数据库。

Imagine that our Human Resources department requested us to check the database growth because they are facing some kind of disk free space issue and want to determine which table or tables are growing more than expected.

想象一下,我们的人力资源部门要求我们检查数据库的增长,因为他们面临某种磁盘可用空间问题,并且想要确定哪些表增长超过了预期。

As can be seen in the solution I am presenting below, the @whereand parameter is used to filter only the tables that belong to HumanResources schema. As explained before, the code that is passed in this parameter is concatenated to the SELECT query that will be used by the cursor definition in the sp_MSforeachtable stored procedure so we are using it to filter the HumanResources schema.

从下面提供的解决方案中可以看出, @ whereand参数仅用于过滤属于HumanResources模式的表。 如前所述,在此参数中传递的代码被连接到SELECT查询,该查询将由sp_MSforeachtable存储过程中的游标定义使用,因此我们正在使用它来筛选HumanResources模式。

I am using the @precommand parameter to create a global temporary table called ##Statistics to store the information that will be need to be shown at the end. This global temporary table will be dropped at the end as it can be seen in the @postcommand parameter after returning the required data (the SELECT statement just before the DROP statement).

我正在使用@precommand参数创建名为## Statistics的全局临时表,以存储将需要在末尾显示的信息。 返回所需数据(在DROP语句之前的SELECT语句)之后,可以在@postcommand参数中看到该全局临时表的末尾。

So, for each table in that belongs to HumanResources schema it will be applied the code in @command1 and @command2 parameters. As explained before, these parameters are used sequentially, i.e. it will first execute @command1 and after this one finish it will execute @command2. If @command3 parameter exists, it will be executed after @command2 finish. And this is why I have an INSERT statement in @command1 parameter and an UPDATE statement in @command2 parameter, since it is expected that the row already exists when @command2 is executed so we will not insert again the row but update it instead.

因此,对于属于HumanResources模式的每个表,都将应用@ command1@ command2参数中的代码。 如前所述,这些参数是按顺序使用的,即它将首先执行@ command1,完成后将执行@ command2。 如果@ command3参数存在,它将在@ command2完成后执行。 这就是为什么我在@ command1参数中有INSERT语句,而在@ command2参数中有UPDATE语句的原因,因为在执行@ command2时预期该行已经存在,所以我们不会再次插入该行,而是对其进行更新。

Follow is the code that you can test. Feel free to change it to perform other kind of tests that can be useful for you:

遵循的是您可以测试的代码。 随时更改它以执行对您有用的其他类型的测试:


USE Adventureworks
GOexec sp_MSforeachtable
@precommand = 'CREATE TABLE ##Statistics (TableName varchar(128) NOT NULL, NumOfRows int,SpaceUsed float)'
,@command1='INSERT INTO ##Statistics (TableName, NumOfRows)SELECT ''?'' TableName, COUNT(1) NumOfRows FROM ?'
,@command2='UPDATE SSET s.SpaceUsed = g.SizeKBFROM ##Statistics sINNER JOIN (SELECT p.object_id TableID, sum(a.total_pages) * 8192 / 1024.0 SizeKBFROM sys.partitions p INNER JOIN sys.allocation_units a on p.partition_id = a.container_idGROUP BY p.object_id) gON OBJECT_ID(s.TableName) = g.TableIDWHERE s.TableName = ''?'''
,@postcommand = 'SELECT TableName, NumOfRows, SpaceUsedFROM ##StatisticsORDER BY SpaceUsed DESC, NumOfRows DESC;DROP TABLE ##Statistics'
,@whereand='AND schema_name(schema_id) = ''HumanResources'''

For the example above you will get a similar output as below:

对于上面的示例,您将获得类似以下的输出:

NOTE: The solution could be simpler by using the sp_spaceused but I preferred the above solution to better show how to work with more than a command parameter.

注意:通过使用sp_spaceused ,解决方案可能更简单,但是我更喜欢上面的解决方案,以更好地展示如何使用多个命令参数。

免责声明 (Disclaimer)

Microsoft does not recommend the usage of the undocumented objects because they do not offer any support for these kinds of objects as they may be changed or dropped in future SQL Server releases without any previous warning.

Microsoft不建议使用未记录的对象,因为它们不提供对此类对象的任何支持,因为它们可能会在将来SQL Server版本中更改或删除而没有任何事先警告。

From my own experience, these undocumented objects have been not experienced any changes in the past so if you want to use them, remember to perform tests with those objects in any new SQL Server version that will be released in the future to assure the correct operation of your code.

根据我自己的经验,这些未记录的对象在过去从未经历过任何更改,因此,如果要使用它们,请记住对这些对象进行测试,这些对象将在将来发布的任何新SQL Server版本中执行,以确保正确的操作您的代码。

翻译自: https://www.sqlshack.com/an-introduction-to-sp_msforeachtable-run-commands-iteratively-through-all-tables-in-a-database/

sp_MSforeachtable简介; 遍历数据库中的所有表运行命令相关推荐

  1. SQL Server 将指定的数据库中的所有表都列出来

    在很多情况下我们需要将指定的数据库中的所有表都列出来.在使用c#进行软件开发时,我们有哪些方法可是实现这个目的呢?本人对此进行概要的总结,有以下6中方式可以实现这个目的. 1.sqldmo SQLDM ...

  2. 获取数据库中的所有表

    本Blog登出后受到了大家的关注,其中"盛国军"朋友提出了使用存储过程"sp_tables"也可以实现这个目的,所有本人对这个Blog有进行了完善. 在很多情况 ...

  3. oracle 表导出pdm文件,如何将数据库中已有表导入到powerDesigner生成pdm文件

    1.create new PDM: 2.select database menu; 3.click Reverse  Engineer database : 4.then choose your sc ...

  4. java 遍历request_java 遍历request中的所有表单数据的实例代码

    java 遍历request中的所有表单数据的实例代码 实例如下: Enumeration rnames=request.getParameterNames(); for (Enumeration e ...

  5. Oracle表里的照片怎么导出来,如何导出oracle数据库中某张表到excel_oracle数据库表格导出到excel...

    如何将oracle数据库表字段导成excel表格 这个你只要用ADO连oracle并获取记录集,根据你用的编程语言打开EXCEL,然后操作EXCEL对象的工作表就可以了.以VB为例: 1.在工程中引用 ...

  6. mysql select 所有表_怎样用SQL语句查询一个数据库中的所有表

    展开全部 查询32313133353236313431303231363533e59b9ee7ad9431333431356639一个数据库中的所有表sql语句是show tables: 显示所有数据 ...

  7. Java代码判断数据库中某张表是否存在

    最近在开发一个同步数据的统计任务的时候遇到一个问题:要在Java代码中判断数据库中某张表是否存在,查资料后,总结了以下两种方法: 1.使用JdbcTemplate bean public boolea ...

  8. 一条SQL语句查询数据库中的所有表、存储过程、触发器

    一条SQL语句查询数据库中的所有表.存储过程.触发器 (sysobjects表信息)   该条语句查询返回所有的用户表 select * from sysobjects where xtype='u' ...

  9. SQLSERVER如何获取一个数据库中的所有表的名称、一个表中所有字段的名称

    1.查询数据库中的所有数据库名: 1 SELECT Name FROM Master..SysDatabases ORDER BY Name 2.查询某个数据库中所有的表名: 1 SELECT Nam ...

最新文章

  1. iOS---------关于野指针定位总结
  2. #102030:在30天内运行20 10K来庆祝Java的20年
  3. 云+X案例展 | 金融类:青云QingCloud助力泰康人寿云计算演进之路
  4. 改变 this 指向的 call 和 apply
  5. java jdbc代码_javajdbc代码解决
  6. iOS 14.5新功能:解锁iPhone更方便!
  7. Java入门到月入2W+ IT各种技术教学资料分享
  8. linux 查看cuda版本_Ubuntu18.04+Tensorflow GPU版本环境搭建
  9. what's the python之函数及装饰器
  10. 由canvas实现btn效果有感
  11. 动易模板制作示例(三)
  12. 工信部BIM工程师系列发布测评考试大纲
  13. hadoop put命令的格式_Hadoop Shell命令
  14. 测试显卡游戏里FPS温度性能的软件,求一个在游戏中显示FPS 显卡温度之类的工具...
  15. 相关性评估:皮尔逊相关系数,R2
  16. BZOJ2794: [Poi2012]Cloakroom【偏序+背包】
  17. 漫话:如何给女朋友解释什么是CDN?
  18. MATLA矩阵、特征值相关备忘
  19. 医学信息化管理与建设
  20. 实验一:信息隐藏与数字水印

热门文章

  1. c语言中不能编译,为什么`int;`可以在C语言中很好地编译,而在C ++中却不能?
  2. python中安装使用模块_python 安装模块
  3. MATLAB之图像与音频信号处理
  4. linux串口配置详解
  5. Scrum立会报告+燃尽图(Final阶段第四次)
  6. Python3+Selenium3+webdriver学习笔记8(单选、复选框、弹窗处理)
  7. IntelliJ IDEA 2018 设置代码提示对大小写不敏感
  8. python-使用字典使Fibonacci更有效率
  9. 读书笔记 - js高级程序设计 - 第四章 变量 作用域 和 内存问题
  10. C#实现对文件目录的实时监控