A while back, I wrote a post on locating an object in a SQL Server instance (post #351). One of the items I received as part of the feedback was to implement the logic using documented (and therefore supported) features.
As you may know, I had used the sp_MSforeachDB system stored procedure in my earlier post. This is an undocumented procedure and therefore the recommendation is to assume that it is unsupported and not use it in production environments. In today’s post, I present before you a script that achieves the same objective (i.e. locate an object in a SQL Server instance), but using fully documented (and therefore fully supported) features.
Improvements over the script using sp_MSforeachDB:
-
Uses fully documented features
-
Does a comparison on both – the schema name and the object name
-
Search is only limited to user databases by default (system databases can be easily reintroduced by commenting out appropriate filter conditions in the query below)
The entire script is provided below for your reference:
USE master;
GO
SET NOCOUNT ON;
--Declarations
BEGIN
--User to fill in
DECLARE @schemaToSearch NVARCHAR(255)
= N'dbo';
DECLARE @objectToSearch NVARCHAR(255)
= N'uspGetBillOfMaterials';
--Internal variables
DECLARE @databaseInformation TABLE
(DatabaseId INT NOT NULL,
DatabaseName NVARCHAR(255),
IsProcessed BIT NOT NULL
);
DECLARE @databaseId INT = 0;
DECLARE @databaseName NVARCHAR(255) = N'';
DECLARE @sqlStmnt NVARCHAR(1000) = N'';
END
--Fetch all user databases into temporary table variable
--for convenience
BEGIN
INSERT INTO @databaseInformation (DatabaseId,
DatabaseName,
IsProcessed)
SELECT sdb.database_id AS DatabaseId,
sdb.name AS DatabaseName,
0 AS IsProcessed
FROM sys.databases AS sdb
WHERE CAST((CASE WHEN SUBSTRING(sdb.name,0,14)
IN ('master',
'msdb',
'model',
'tempdb',
'ReportServer$')
THEN 1
ELSE sdb.is_distributor
END) AS BIT) = 0;
END
--Begin processing one database after another
WHILE EXISTS (SELECT dbi.DatabaseId
FROM @databaseInformation AS dbi
WHERE dbi.IsProcessed = 0
)
BEGIN
SELECT TOP 1
@databaseId = dbi.DatabaseId,
@databaseName = dbi.DatabaseName
FROM @databaseInformation AS dbi
WHERE dbi.IsProcessed = 0;
--Build the statement to fetch the objectId of an object
--and then check for it's existence
SET @sqlStmnt = N'USE ' + QUOTENAME(@databaseName) + N';
DECLARE @objectId INT;
SET @objectId = OBJECT_ID('''
+ QUOTENAME(@schemaToSearch)
+ N'.'
+ QUOTENAME(@objectToSearch)
+ N''')
IF EXISTS (SELECT *
FROM sys.objects AS so
WHERE so.is_ms_shipped = 0
AND so.object_id = @objectId
)
BEGIN
SELECT DB_NAME() AS DatabaseName;
END;'
--Execute the query
--PRINT @sqlStmnt;
EXEC sp_executesql @sqlStmnt = @sqlStmnt;
--Mark the database as done
UPDATE dbi
SET dbi.IsProcessed = 1
FROM @databaseInformation AS dbi
WHERE dbi.DatabaseId = @databaseId
AND dbi.DatabaseName = @databaseName;
END
GO
Until we meet next time,
Be courteous. Drive responsibly.
