A better sp_MSForEachDB

Though undocumented and unsupported, I’m sure that at least once you happened to use Microsoft’s built-in stored procedure to execute a statement against all databases. Let’s face it: it comes handy very often, especially for maintenance tasks.

Some months ago, Aaron Bertand (blog|twitter) came up with a nice replacement and I thought it would be fun to code my own.

The main difference with his (and Microsoft’s) implementation is the absence of a cursor. While flagged correctly (LOCAL FORWARD_ONLY STATIC READ_ONLY) and run against a temporary table, nevertheless I was a bit disturbed by that tiny little cursor, so I decided to get rid of it.

Basically, my code relies on a dynamic SQL pushed down three levels:

  1. sp_executesql
  2. sp_executesql
  3. EXEC

This trick can be used as many times as you like, given that you keep on declaring and passing all the parameters you need to the lower levels.

I didn’t provide ad-hoc parameters to implement complex filters on sysdatabases, as I’m convinced that they would not be useful enough in a day to day use. If you like this code and want to use it, feel free to change it to incorporate any kind of filter.

Here is the code:

Let’s see some examples of its use:
Print the database name for each user database:

EXEC [dba_ForEachDB] @statement = 'PRINT DB_NAME()', @replacechar = '?', @name_pattern =  '[USER]'

Display the file path of each database file of system databases:

EXEC [dba_ForEachDB] @statement = 'SELECT physical_name, size FROM sys.database_files', @replacechar = '?', @name_pattern =  '[SYSTEM]'

I hope you like it and find it useful.
Happy coding.


Posted on September 9, 2011, in SQL Server, T-SQL and tagged , . Bookmark the permalink. 9 Comments.

  1. Gianluca – thanks for the script. When looking at trying to not use MSforeachdb recently I was going to venture down this same path. You just saved me a bunch of work.

  2. Thanks! Glad you liked it, Jason.

  3. This works for me. thanks a lot !

  4. Thanks, but I got some problem. I don´t think it handles dbname with multiple – in the name.
    I got these databases and it failes can´t find X123456.


    • I just tried with the database names you suggested and it works for me.
      Can you provide the whole set of parameters you are using?
      Which version are you running?

    • put square brackets around the string, or use QUOTENAME(‘[‘, objname), for building up your SQL string.

      • put square brackets around the parts in the SQL string for field names, table names or database names, or use QUOTENAME(‘[‘, objname), for building up your SQL string

        as in:

        @sql = ‘select * from [‘ + @dbname + ‘].dbo.[‘ + @tbl + ‘];’


        @sql = ‘select * from ‘ + quotename(‘[‘, @dbname) + ‘.dbo.’+quotename(‘[‘, @tbl)+’;’

  1. Pingback: Replay a T-SQL batch against all databases « spaghettidba

  2. Pingback: A viable alternative to dynamic SQL in administration scripts | spaghettidba

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: