Instead of using sp_msForEachdb, which is problematic as Aaron described, you could use a cursor for this.
IF OBJECT_ID(N'tempdb..#Results') IS NOT NULL
BEGIN
DROP TABLE #Results;
END
CREATE TABLE #Results
(
DatabaseName SYSNAME NULL
, IsOnline BIT NULL
, ParentObject varchar(100) NULL
, [Object] varchar(100) NULL
, [Field] varchar(100) NULL
, [Value] varchar(100) NULL
);
DECLARE @cmd NVARCHAR(MAX);
DECLARE @dbName SYSNAME;
DECLARE @IsOnline BIT;
DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC
FOR
SELECT DBCCCommand = 'DBCC DBINFO(''' + d.name + ''') WITH TABLERESULTS;'
, DatabaseName = d.name
, IsOnline = CONVERT(BIT,
CASE WHEN d.state_desc = 'ONLINE' THEN 1 ELSE 0 END
)
FROM sys.databases d
ORDER BY d.name;
OPEN cur;
FETCH NEXT FROM cur INTO @cmd, @dbName, @IsOnline;
WHILE @@FETCH_STATUS = 0
BEGIN
RAISERROR (@dbName, 0, 1) WITH NOWAIT;
IF @IsOnline = 1
BEGIN
INSERT INTO #Results (ParentObject, [Object], [Field], [Value])
EXEC sp_executesql @cmd;
UPDATE #Results
SET DatabaseName = @dbName
, IsOnline = @IsOnline
WHERE DatabaseName IS NULL;
END
ELSE
BEGIN
INSERT INTO #Results (DatabaseName, IsOnline)
VALUES (@dbName, @IsOnline)
END
FETCH NEXT FROM cur INTO @cmd, @dbName, @IsOnline;
END
CLOSE cur;
DEALLOCATE cur;
SELECT r.DatabaseName
, LastKnownGoodDate = CONVERT(DATETIME, r.value, 120)
, r.IsOnline
FROM #Results r
WHERE r.field = 'dbi_dbccLastKnownGood'
OR r.field IS NULL;
This output has the database name along with the LastKnownGood column from the DBCC DBINFO output as a DATETIME variable. Databases that are not "online" are included in the output, with the LastKnownGoodDBCC column set to NULL.
The cursor created in my example above is a local, forward-only, static cursor that is highly efficient. Local indicates the scope of the cursor is limited to our session, which is clearly not a problem (the sp_msForEachdb uses a global cursor that is quite expensive to setup). The forward-only option indicates we don't intend on being able to scroll backwards though the cursor, and allows SQL Server to use forward-only, read-only cursor semantics. The static option forces SQL Server to materialize the cursor results into a temporary table in tempdb, and read each row from there. The MSDN page on DECLARE CURSOR has excellent details about the cursor options, and is well worth reading and understanding.