详解SQL Server的两个存储过程:sp_MSforeachtable/sp_MSforeachdb

参考:
https://blog.csdn.net/sxycgxj/article/details/1495568?utm_medium=distribute.pc_relevant_t0.none-task-blog-searchFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-searchFromBaidu-1.control

1.简介:
作为DBA会经常需要检查所有的数据库或用户表,比如:检查所有数据库的容量;看看指定数据库所有用户表的容量,所有表的记录数...,我们一般处理这样的问题都是用游标分别处理处理,比如:在数据库检索效率非常慢时,我们想检查数据库所有的用户表,我们就必须通过写游标来达到要求;如果我们用sp_MSforeachtable就可以非常方便的达到相同的目的:EXEC sp_MSforeachtable @command1="print '?' DBCC CHECKTABLE ('?')"
系统存储过程sp_MSforeachtable和sp_MSforeachdb,是微软提供的两个不公开的存储过程,从mssql6.5开始。存放在SQL Server的MASTER数据库中。可以用来对某个数据库的所有表或某个SQL服务器上的所有数据库进行管理,后面将对此进行详细介绍。

2.参数说明:

  @command1 nvarchar(2000),                     --第一条运行的SQL指令
  @replacechar nchar(1) = N'?',                     --指定的占位符号
  @command2 nvarchar(2000)= null,           --第二条运行的SQL指令
  @command3 nvarchar(2000)= null,           --第三条运行的SQL指令
  @whereand nvarchar(2000)= null,              --可选条件来选择表
  @precommand nvarchar(2000)= null,       --执行指令前的操作(类似控件的触发前的操作)
  @postcommand nvarchar(2000)= null      --执行指令后的操作(类似控件的触发后的操作)

以后为sp_MSforeachtable的参数,sp_MSforeachdb不包括参数@whereand

3.使用举例:

--统计数据库里每个表的详细情况:

  exec sp_MSforeachtable @command1="sp_spaceused '?'"

--获得每个表的记录数和容量:

  EXEC sp_MSforeachtable @command1="print '?'",
       @command2="sp_spaceused '?'",
       @command3= "SELECT count(*) FROM ? "

--获得所有的数据库的存储空间:

  EXEC sp_MSforeachdb  @command1="print '?'",
       @command2="sp_spaceused "

--检查所有的数据库

  EXEC sp_MSforeachdb  @command1="print '?'",
       @command2="DBCC CHECKDB (?) "

--更新PUBS数据库中已t开头的所有表的统计:

  EXEC sp_MSforeachtable @whereand="and name like 't%'",
       @replacechar='*',
       @precommand="print 'Updating Statistics.....' print ''",
       @command1="print '*' update statistics * ",
       @postcommand= "print''print 'Complete Update Statistics!'"

--删除当前数据库所有表中的数据

  sp_MSforeachtable @command1='Delete from ?'
  sp_MSforeachtable @command1 = "TRUNCATE TABLE ?"

4.参数@whereand的用法:

@whereand参数在存储过程中起到指令条件限制的作用,具体的写法如下:
@whereend,可以这么写 @whereand=' AND o.name in (''Table1'',''Table2'',.......)'
例如:我想更新Table1/Table2/Table3中NOTE列为NULL的值
sp_MSforeachtable @command1='Update ? Set NOTE='''' Where NOTE is NULL',@whereand=' AND o.name in (''Table1'',''Table2'',''Table3'')'

5."?"在存储过程的特殊用法,造就了这两个功能强大的存储过程.

  这里"?"的作用,相当于DOS命令中、以及我们在WINDOWS下搜索文件时的通配符的作用。

6.小结

有了上面的分析,我们可以建立自己的sp_MSforeachObject:(转贴)

USE MASTER
GO
CREATE proc sp_MSforeachObject
 @objectType int=1,
 @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)
 /* Defined  @isobject for save object type */
 Declare @isobject varchar(256)
 select @isobject= case @objectType when 1 then 'IsUserTable'
         when 2 then 'IsView'
         when 3 then 'IsTrigger'
         when 4 then 'IsProcedure'
         when 5 then 'IsDefault'  
         when 6 then 'IsForeignKey'
         when 7 then 'IsScalarFunction'
         when 8 then 'IsInlineFunction'
         when 9 then 'IsPrimaryKey'
         when 10 then 'IsExtendedProc'   
         when 11 then 'IsReplProc'
         when 12 then 'IsRule'
                  end
 /* Create the select */
 /* Use @isobject variable isstead of IsUserTable string */
EXEC(N'declare hCForEach cursor global for select ''['' + REPLACE(user_name(uid), N'']'', N'']]'') + '']'' + ''.'' + ''['' +
REPLACE(object_name(id), N'']'', N'']]'') + '']'' from dbo.sysobjects o '
        + N' where OBJECTPROPERTY(o.id, N'''+@isobject+''') = 1 '+N' and o.category & ' + @mscat + N' = 0 '
       + @whereand)
 declare @retval int
 select @retval = @@error
 if (@retval = 0)
  exec @retval = sp_MSforeach_worker @command1, @replacechar, @command2, @command3
 if (@retval = 0 and @postcommand is not null)
  exec(@postcommand)
 return @retval
GO

这样我们来测试一下:
--获得所有的存储过程的脚本:

         EXEc sp_MSforeachObject @command1="sp_helptext '?' ",@objectType=4

--获得所有的视图的脚本:

         EXEc sp_MSforeachObject @command1="sp_helptext '?' ",@objectType=2

--比如在开发过程中,没一个用户都是自己的OBJECT OWNER,所以在真实的数据库时都要改为DBO:

         EXEc sp_MSforeachObject @command1="sp_changeobjectowner '?', 'dbo'",@objectType=1
         EXEc sp_MSforeachObject @command1="sp_changeobjectowner '?', 'dbo'",@objectType=2
         EXEc sp_MSforeachObject @command1="sp_changeobjectowner '?', 'dbo'",@objectType=3
         EXEc sp_MSforeachObject @command1="sp_changeobjectowner '?', 'dbo'",@objectType=4

这样就非常方便的将每一个数据库对象改为DBO.

  1. 我个人的一个应用:

sp_MSforeachdb 定期统计数据库的空间分配情况:

create table master.dbo.dbsize (dbname sysname,checkTime VARCHAR(19),dbSize VARCHAR(50),logSize VARCHAR(50))

USE master
go

INSERT INTO master.dbo.dbsize ( dbName, checkTime, dbSize, logSize )
EXEC sp_msforeachdb 'select ''?'' dbName,CONVERT(VARCHAR(19),GETDATE(),120) checkTime,LTRIM(STR(SUM(CASE WHEN RIGHT(FILENAME,3)<>''ldf'' THEN convert (dec (15,2),size) * 8 / 1024 ELSE 0 END),15,2)+'' MB'') dbSize,  
                 LTRIM(STR(SUM(CASE WHEN RIGHT(FILENAME,3)=''ldf''  THEN convert (dec (15,2),size) * 8 / 1024 ELSE 0 END),15,2)+'' MB'') logSize from ?.dbo.sysfiles'

--SELECT * FROM @insSize ORDER BY CONVERT(DECIMAL,LTRIM(RTRIM(SUBSTRING(dbSize,1,LEN(dbSize)-2)))) DESC

--需要时查询该表即可
select * from master.dbo.dbsize;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358