zoukankan      html  css  js  c++  java
  • sp_MSforeachtable 与 sp_MSforeachdb


    在MSSQL里有许多不公开的系统存储过程,其中可能常用的sp_MSforeachtable和sp_MSforeachdb有这2个。
    分别用于遍历某数据库的每个用户表、每个数据库。

    sp_MSforeachtable


    create proc sp_MSforeachtable
        
    @command1 nvarchar(2000),             --第一条运行的T-SQL
        
    @replacechar nchar(1= N'?',          --指定的占位符
        
    @command2 nvarchar(2000= null,      --第二条运行的T-SQL   
       
    @command3 nvarchar(2000= null,      --第三条运行的T-SQL
        
    @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(int0x0002)))

        
    if (@precommand is not null)
            
    exec(@precommand)

        
    /* Create the select */
        
    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''IsUserTable'') = 1 ' + N' and o.category & ' + @mscat + N' = 0 '
        
    + @whereand)
        --上面的代码,就是定义游标根据系统表sysobjects获取用户表,@whereand就确定 sysobjects的where条件
        
    declare @retval int
        
    select @retval = @@error
        
    if (@retval = 0)
            --调用sp_MSforeach_worker 执行游标遍历
            --sp_MSforeach_worker存储过程见最后
            
    exec @retval = sp_MSforeach_worker @command1@replacechar@command2@command3

        
    if (@retval = 0 and @postcommand is not null)
            
    exec(@postcommand)

        
    return @retval

    go
    --统计数据库里每个表的详细情况
    exec sp_MSforeachtable 'sp_spaceused ''?'''
    --获得每个表的记录数和容量
    exec sp_MSforeachtable 'select ''?''','?', 'sp_spaceused ''?''', 'SELECT count(*) FROM ? '
    --获得所有的数据库的存储空间
    exec sp_MSforeachdb  'select  ''?''','?','sp_spaceused '
    --检查所有的数据库
    exec sp_MSforeachdb  @command1="print '?'",'DBCC CHECKDB (?) '
    --更新PUBS数据库中已t开头的所有表的统计
    exec sp_MSforeachtable
           'print ''*'' update statistics * ',
           '*',
           null,
           null,
           ' and name like ''t%''',
           'print ''Updating Statistics.....''',
           'print ''Complete Update Statistics!'''

    --删除当前数据库所有表中的数据
    sp_MSforeachtable 'Delete from ?'
    sp_MSforeachtable 'Truncate Table ?'

    --更新Table1/Table2中note列为NULL的值
    sp_MSforeachtable 'Update ? Set note='''' Where note is null',null,null,null,' AND o.name in (''Table1'',''Table2'')



    sp_MSforeachdb 在应用上与sp_MSforeachTable一样,只是没有@whereand 这个条件变量而已
    /*
     * The following table definition will be created by SQLDMO at start of each connection.
     * We don't create it here temporarily because we need it in Exec() or upgrade won't work.
     
    */
    Create proc sp_MSforeachdb
        
    @command1 nvarchar(2000), 
        
    @replacechar nchar(1= N'?'
        
    @command2 nvarchar(2000= null
        
    @command3 nvarchar(2000= null,
        
    @precommand nvarchar(2000= null
        
    @postcommand nvarchar(2000= null
    as
       
    set deadlock_priority low
        
    /* This proc returns one or more rows for each accessible db, with each db 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 @inaccessible nvarchar(12), @invalidlogin nvarchar(12), @dbinaccessible nvarchar(12)
        
    select @inaccessible = ltrim(str(convert(int0x03e0), 11))
        
    select @invalidlogin = ltrim(str(convert(int0x40000000), 11))
        
    select @dbinaccessible = N'0x80000000'        /* SQLDMODbUserProf_InaccessibleDb; the negative number doesn't work in convert() */

        
    if (@precommand is not null)        exec(@precommand)

        
    declare @origdb nvarchar(128)
        
    select @origdb = db_name()

        
    /* If it's a single user db and there's an entry for it in sysprocesses who isn't us, we can't use it. */
        
    /* Create the select */
        
    exec(N'declare hCForEach cursor global for select name from master.dbo.sysdatabases d ' +
                N
    ' where (d.status & ' + @inaccessible + N' = 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)))' )

        
    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)

        
    declare @tempdb nvarchar(258)
           
    SELECT @tempdb = REPLACE(@origdb, N']', N']]')
           
    exec (N'use ' + N'[' + @tempdb + N']')

        
    return @retval

    go


    sp_MSforeach_worker
    /*
     * 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 - 11= 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 - 11= 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(@name11= 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(@name2@tempindex-2 )
                           
    select @nametmp2 = substring(@name@tempindex+3len(@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(@name11= 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(@name2len(@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 < @namelenbegin
                           
    /* 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(@cmd1@replacecharindex)
                           
    select @cmd = substring(@cmd@replacecharindex + 12000)
                           
    select @nextcmd = stuff(@nextcmd@replacecharindex1@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 (@useqsubstring(@cmd1@replacecharindex - 1))
                       
    if (substring(@cmd@replacecharindex - 11= N' '
                       
    begin
                           
    select @cmd = N' ' + substring(@cmd@replacecharindex2000)
                       
        select @replacecharindex = 2
                       
    end 
                       
    else 
                       
    begin
                           
    select @cmd = substring(@cmd@replacecharindex2000)
                           
    select @replacecharindex = 1
                       
    end
                       
    select @useq = @useq + 1
                   
    end
               
        select @cmd = stuff(@cmd@replacecharindex1@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 (@usecmdwhen 2 then @command2 when 3 then @command3 else null end
           
        if (@nextcmd is not null and substring(@nextcmd12= N'++'
               
    begin
                   
    insert #qtemp values (@useq@cmd)
                   
    select @cmd = substring(@nextcmd32000), @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


    其他一些sql中的扩展存储的总结:

    xp_availablemedia    (无)      显示系统上可用的盘符'C:\' xp_availablemedia 
    xp_enumgroups                     列出当前系统的使用群组及其说明 xp_enumgroups 
    xp_enumdsn            (无)      列出系统上已经设置好的ODBC数据源名称 xp_enumdsn 
    xp_dirtree            (无)      显示某个目录下的子目录与文件架构 xp_dirtree 'C:\inetpub\wwwroot\' 
    xp_getfiledetails    (无)      获取某文件的相关属性 xp_getfiledetails 'C:\inetpub\wwwroot.asp' 
    dbp.xp_makecab        (无)     将目标计算机多个档案压缩到某个档案里所压缩的档案都可以接在参数的后面用豆号隔开             dbp.xp_makecab 'C:\lin.cab','evil',1,'C:\inetpub\mdb.asp' 
    xp_unpackcab           (无)      解压缩 xp_unpackcab 'C:\hackway.cab','C:\temp',1 
    xp_ntsec_enumdomains  (无)      列出服务器域名 xp_ntsec_enumdomains 
    xp_servicecontrol     (无)      停止或者启动某个服务 xp_servicecontrol 'stop','schedule' 
    xp_terminate_process  (无)     用pid来停止某个执行中的程序 xp_terminate_process 123 
    dbo.xp_subdirs        (无)      只列某个目录下的子目录 dbo.xp_subdirs 'C:\'


    网络上有个存储过程sp_MSforeachObject,这是根据sp_MSforeachtable延伸出来的一个存储过程,扩展了应用。个人感觉很有用,这里推荐下。
    USE MASTER
    GO
    --=============================================================
    --
    @objectType 对象类型 
    --
    1  IsUserTable
    --
    2  IsView
    --
    3  IsTrigger
    --
    4  IsProcedure
    --
    5  IsDefault
    --
    6  IsForeignKey
    --
    7  IsScalarFunction
    --
    8  IsInlineFunction
    --
    9  IsPrimaryKey
    --
    10 IsExtendedProc
    --
    11 IsReplProc
    --
    12 IsRule
    --
    =============================================================
    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(int0x0002)))
    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

    --下面2个例子:第一个 所有存储过程源代码,第2个修改所有表的所有者为dbo
    sp_MSforeachObject 
    4,'sp_helptext ''?'''
    sp_MSforeachObject 
    1,'sp_changeobjectowner ''?''''dbo'''  --当然这个可以应用sp_MSforeachtable 来完成

  • 相关阅读:
    第5-7次OO作业总结分析
    面向对象课程作业1-3总结分析
    OO第四次作业总结
    OO第三次作业总结
    OO第二次作业总结
    OO第一次作业总结
    BUAA 编译源码阅读_pascal
    OO第四阶段总结
    OO第三阶段总结
    OO第二阶段总结
  • 原文地址:https://www.cnblogs.com/piaoqingsong/p/780290.html
Copyright © 2011-2022 走看看