自 SQL Server 6.5 起,系統提供 sp_MSforeachtable 與 sp_MSforeachDB 兩個未文件化的系統預存程序,極大簡化對所有資料庫或使用者表的批次操作。傳統做法需撰寫游標逐一處理,例如檢查所有使用者表完整性:
DECLARE @TableName varchar(255)
DECLARE @ExeSQL varchar(4000)
DECLARE Table_Cursor CURSOR FOR
SELECT [name] FROM sysobjects WHERE xtype='U'
OPEN Table_Cursor
FETCH NEXT FROM Table_Cursor INTO @TableName
WHILE(@@FETCH_STATUS=0)
BEGIN
PRINT @TableName
SELECT @ExeSQL='DBCC CHECKTABLE('''+@TableName+''')'
EXEC(@EXESQL)
FETCH NEXT FROM Table_Cursor INTO @TableName
END
CLOSE Table_Cursor
DEALLOCATE Table_Cursor
GO
EXEC sp_MSforeachtable @command1="print '?' DBCC CHECKTABLE('?')"
單行指令即可達到相同目的,雖然底層仍使用游標處理,但程式碼簡潔許多。
執行以下指令查看原始碼:
USE MASTER
GO
SP_HELPTEXT sp_MSforeachtable
CREATE proc 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
/* 為每個資料表傳回一或多列 (可選擇性符合 @where),
每個資料表預設為自己的結果集 */
/* @precommand 和 @postcommand 可用於透過暫存表強制單一結果集 */
/* 前置處理器不會替換引號內容,故使用 str() */
declare @mscat nvarchar(12)
select @mscat = ltrim(str(convert(int, 0x0002)))
if (@precommand is not null)
exec(@precommand)
/* 建立選取游標 */
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, ...')
| 參數 | 型別 | 預設值 | 說明 |
|---|---|---|---|
| @command1 | nvarchar(2000) | - | 主要執行命令,? 代表資料表名稱 |
| @replacechar | nchar(1) | N'?' | 替換字元,可自訂 |
| @command2 | nvarchar(2000) | null | 第二組命令 |
| @command3 | nvarchar(2000) | null | 第三組命令 |
| @whereand | nvarchar(2000) | null | 附加 WHERE 條件篩選資料表 |
| @precommand | nvarchar(2000) | null | 迴圈前執行命令(如建立暫存表) |
| @postcommand | nvarchar(2000) | null | 迴圈後執行命令(如查詢暫存表結果) |
EXEC sp_MSforeachtable
@precommand = 'CREATE TABLE #rowcounts (tablename sysname, rowcnt int)',
@command1 = 'INSERT INTO #rowcounts SELECT ''?'', COUNT(*) FROM ?',
@postcommand = 'SELECT * FROM #rowcounts ORDER BY rowcnt DESC'
EXEC sp_MSforeachtable
@command1 = "DBCC DBREINDEX('?', '', 90)"
EXEC sp_MSforeachtable
@whereand = "AND schema_name(schema_id) = 'Sales'",
@command1 = "PRINT 'Processing ?'"
hCForEach,並發環境需謹慎REPLACE(object_name(id), N']', N']]'))@precommand/@postcommand 使用暫存表聚合結果同理可用 sp_MSforeachDB 對所有資料庫執行命令,參數結構類似,? 代表資料庫名稱。例如:
EXEC sp_MSforeachDB @command1="PRINT '?' DBCC CHECKDB('?')"