Search code examples
sql-serversp-msforeachdb

How to specify TABLE_SCHEMA name in sp_MSforeachdb to take database offline


I need to search for certain databases with a particular prefix. Once these databases have been located, I need to check to see if a certain schema exists and if it does not exist - take the database offline. I have been trying various suggestions I found on Google but nothing works. I have one error that I cannot get past. The error is 'XYZ' is not a recognized option. If I separate out the code it runs fine but when I add sp_MSforeachdb, the error returns.

EXEC sp_msforeachdb 'IF ''?'' LIKE ''abc_%''
  BEGIN
      IF (NOT EXISTS  (SELECT *
               FROM INFORMATION_SCHEMA.TABLES 
               WHERE TABLE_SCHEMA = 'XYZ'          
                               BEGIN
                               ALTER DATABASE [abc_xxxxxxxxx] SET OFFLINE WITH
                               ROLLBACK IMMEDIATE             
                               END'  

This code works fine:

SELECT *
 FROM INFORMATION_SCHEMA.TABLES 
 WHERE TABLE_SCHEMA = 'XYZ'

Solution

  • Here's a method that doesn't rely on the undocumented, unsupported and buggy system procedure sp_msforeachdb, and also doesn't rely on similarly unreliable INFORMATION_SCHEMA views.

    DECLARE @sql NVARCHAR(MAX);
    SET @sql = N'';
    
    SELECT @sql = @sql + N'IF NOT EXISTS (SELECT 1 FROM ' 
      + QUOTENAME(name) + '.sys.tables AS t
      INNER JOIN ' + QUOTENAME(name) + '.sys.schemas AS s
      ON t.schema_id = s.schema_id
      WHERE s.name = ''XYZ'')
      BEGIN
        EXEC sp_executesql N''ALTER DATABASE ' 
          + QUOTENAME(name) + ' SET OFFLINE;''
      END
    ' FROM sys.databases WHERE name LIKE 'abc_%';
    
    PRINT @sql;
    -- EXEC sp_executesql @sql;
    

    Your actual error is because you have string delimiters inside a string. You can't do this:

    SELECT ' WHERE TABLE_SCHEMA = 'XYZ' ... ';
    

    Error:

    Msg 102, Level 15, State 1, Line 1
    Incorrect syntax near ' ... '.

    You need to do this:

    SELECT ' WHERE TABLE_SCHEMA = ''XYZ'' ... ';
    

    However this gets convoluted quite quickly when you're nesting commands inside a command you're sending to an undocumented, unsupported and buggy system procedure. I know I'm repeating myself here. I hope it's clear that you should not be using sp_msforeachdb if you want reliable results.