This tip presents two very useful stored procedures that live in the master database but are not mentioned in SQL Server Books Online. These system procedures come in very handy for jobs such as determining the space used, the number of rows, the indexes on the user tables, and so on.
The first procedure, sp_MSForEachDB, runs up to three commands against every database on the server of interest.
|> @command1: first command to execute
|> @replacechar: substitute another placeholder for the "?"
|> @command2: second command to execute
|> @command3: third command to execute
|> @precommand: execute command once before entering the loop
|> @postcommand: execute command once after exiting the loop
Each set of commands (even if the set consists of only one command) is run as a batch against the databases, so it's most useful to capture the output to text rather than to the standard result-set grid. To do this, select Query | Results To | Results To Text from the menu or press [Ctrl]T.
The following code returns the number of user tables in each database on the server:
exec sp_MSForEachDB
@command1 = "use ? exec sp_SpaceUsed"
The abbreviated output looks like this:
database_name database_size unallocated space
--------------------- ------------------ ------------------
master 5.25 MB 1.26 MB
reserved data index_size unused
------------------ ------------------ ------------------ ------------------
2808 KB 1144 KB 1080 KB 584 KB
The second procedure, sp_MSForEachTable, accepts seven parameters:
|> @command1: first command to execute
|> @replacechar: substitute another placeholder for the "?"
|> @command2: second command to execute
|> @command3: third command to execute
|> @whereand: Where condition (or Order By clause)
|> @precommand: execute command once before entering the loop
|> @postcommand: execute command once after exiting the loop
By naming the parameters you want to pass, you can skip the necessity of passing null values. The @replacechar parameter is useful when the commands you want to execute contain a question mark. The @whereand parameter was implemented so you can scope the output according to a filter.
You can also sneak in an ORDER BY clause. The following example returns the row counts from every table in the AdventureWorks database, and sorts them by table name:
exec sp_MSForEachTable
@command1 = "Print \'?\'"
, @command2 = "select count(*) from ?"
, @whereand = "ORDER BY 1"
Here are a few rows of the output:
[HumanResources].[Department]
-----------
16
[HumanResources].[Employee]
-----------
290
[HumanResources].[EmployeeAddress]
-----------
290
[HumanResources].[EmployeeDepartmentHistory]
-----------
296
I like that it sorts the tables by both schema and table name.




1
Tony White - 29/07/08
These procs have been around for quite a while, but do be aware that these are undocumented procs. As such they could be removed by Microsoft, without warning at any service pack or patch level.
» Report offensive content
2
Jamie - 29/07/08
*You could probably just recreate them yourself if they were removed and are critical.
I see commonly people throw the results in a temp table to combine into one result set. Something like
» Report offensive content
3
Oded Dror - 29/07/08
I'm using the following view on a daily basis
» Report offensive content
4
Tony - 29/07/08
Jamie, you are absolutely right.
Would it not be better though, to create your own procs to do just this within your DBA maintenance database? That way you will never lose them and can maintain some level of source control.
Even if you just crib some of MS code from the existing procs... After all, they are only cursors, which are, as we all know, the spawn of the devil - discuss :)
» Report offensive content
5
JumpIn - 30/07/08
WOW, Thanks a lot!
I've been using the MSForeach? procs for years but never knew the parameter names, didn't even know you could exec more than one query with a single call.
This is a great help. Again thanks a lot.
JumpIn
» Report offensive content