Is there a tool that will find all objects in SQL Server (functions, procs, views) that cannot possibly work because they refer to objects that don\'t exist?
I'm actually using sys.refreshmodule procedure now wrapped in a powershell script with the SQL Server Powershell add ins.
This works better because this handy little sys function gets rid of the CREATE vs ALTER stuff. Some other answers here use this approach as well, but I prefer this one that's wrapped in Powershell and maybe some will find it useful.
$server = "YourDBServer"
cls
Import-Module “sqlps” -DisableNameChecking
$databases = Invoke-Sqlcmd -Query "select name from sys.databases where name not in ('master', 'tempdb', 'model', 'msdb')" -ServerInstance $server
foreach ($db in $databases) {
$dbName = $db.name
$procedures = Invoke-Sqlcmd -Query "select SCHEMA_NAME(schema_id) as [schema], name from $dbName.sys.procedures" -ServerInstance $server
foreach ($proc in $procedures) {
if ($schema) {
$shortName = $proc.schema + "." + $proc.name
$procName = $db.name + "." + $shortName
try {
$result = Invoke-Sqlcmd -Database $dbName -Query "sys.sp_refreshsqlmodule '$shortName'" -ServerInstance $server -ErrorAction Stop
Write-Host "SUCCESS|$procName"
}
catch {
$msg = $_.Exception.Message.Replace([Environment]::NewLine, ",")
Write-Host "FAILED|$procName|$msg" -ForegroundColor Yellow
}
}
}
}
As of SQL Server 2008, a much simpler method is here:
SELECT OBJECT_NAME(referencing_id) AS 'object making reference' ,
referenced_class_desc ,
referenced_schema_name ,
referenced_entity_name AS 'object name referenced' ,
( SELECT object_id
FROM sys.objects
WHERE name = [referenced_entity_name]
) AS 'Object Found?'
FROM sys.sql_expression_dependencies e
LEFT JOIN sys.tables t ON e.referenced_entity_name = t.name;
As mentioned in the source article (Microsoft MSDN Article on Finding Missing Dependencies), "A 'NULL' value in the 'Object Found?' column indicates the object was not found in sys.objects."
Example output:
╔═══════════════════════════════════════════════╦═══════════════════════╦════════════════════════╦═══════════════════════════════════════╦═══════════════╗
║ object making reference ║ referenced_class_desc ║ referenced_schema_name ║ object name referenced ║ Object Found? ║
╠═══════════════════════════════════════════════╬═══════════════════════╬════════════════════════╬═══════════════════════════════════════╬═══════════════╣
║ usvConversationsWithoutServerNotices ║ OBJECT_OR_COLUMN ║ dbo ║ ConversationLinesWithID ║ NULL ║
║ usvFormattedConversationLines_WithSpeakerName ║ OBJECT_OR_COLUMN ║ dbo ║ ConversationLinesWithID ║ NULL ║
║ usvFormattedConversationLines_WithSpeakerName ║ OBJECT_OR_COLUMN ║ dbo ║ FormattedConversationLines_Cached ║ NULL ║
║ udpCheckForDuplicates ║ OBJECT_OR_COLUMN ║ dbo ║ FormattedConversationLines_WithChatID ║ NULL ║
║ usvFormattedConversationsCombined ║ OBJECT_OR_COLUMN ║ dbo ║ GROUP_CONCAT_D ║ 178099675 ║
║ usvSequenceCrossValidationSetStudents ║ OBJECT_OR_COLUMN ║ dbo ║ usvSequenceCrossValidationSet ║ 1406628054 ║
╚═══════════════════════════════════════════════╩═══════════════════════╩════════════════════════╩═══════════════════════════════════════╩═══════════════╝
If you get an error that says the subquery returned more than one value, then you have more than one object with the name equaling the [referenced_entity_name], and you will need the subquery to be more specific by adding another where clause.
You can get more information by checking sys.objects, like this:
SELECT *
FROM sys.objects
WHERE name = [referenced_entity_name]
If that information alone isn't helpful enough to figure out how to distinguish your multiple results, you may need to join sys.objects to one of the other metadata views (which are mostly documented here: https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/object-catalog-views-transact-sql?view=sql-server-ver15 ) or to sys.schemas (documented here: https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/schemas-catalog-views-sys-schemas?view=sql-server-ver15 ) to get more information.
Your best bet is to start using a tool like Visual Studio Database Edition. It's role is to manage a database schema. One of the many things it will do is to throw an error when you attempt to build the database project and it contains broken objects. It will of course do much more than this. The tool is free to any user of Visual Studio Team Suite or Visual Studio Developer Edition.
Note the query in this thread finds missing objects, not invalid ones.
SQL Server doesn't find a referencing object is invalid until you execute it.
Enhancement to that query to handle objects in other schemas as well as types:
SELECT
'[' + OBJECT_SCHEMA_NAME(referencing_id) + '].[' + OBJECT_NAME(referencing_id) + ']'
AS [this sproc, UDF or VIEW...],
isnull('[' + referenced_schema_name + '].', '') + '[' + referenced_entity_name + ']'
AS [... depends ON this missing entity name]
FROM
sys.sql_expression_dependencies
WHERE
is_ambiguous = 0 AND
(
(
[referenced_class_desc] = 'TYPE' and
TYPE_ID(
isnull('[' + referenced_schema_name + '].', '') +
'[' + referenced_entity_name + ']'
) IS NULL
) or
(
[referenced_class_desc] <> 'TYPE' and
OBJECT_ID(
isnull('[' + referenced_schema_name + '].', '') +
'[' + referenced_entity_name + ']'
) IS NULL
)
)
ORDER BY
'[' + OBJECT_SCHEMA_NAME(referencing_id) + '].[' + OBJECT_NAME(referencing_id) + ']',
isnull('[' + referenced_schema_name + '].', '') + '[' + referenced_entity_name + ']'
Red Gate Software's SQL Prompt 5 has a Find Invalid Objects feature that might be useful in this situation. The tool goes through the database finding objects that will give an error when executed, which sounds exactly what you want.
You can download a 14-day trial for free, so you can give it a try and see if it helps.
Paul Stephenson
SQL Prompt Project Manager
Red Gate Software
First query
will give you broken objects name includesStored Procedure
,View
,Scalar function
,DML trigger
,Table-valued-function
type
/*
/////////////
////ERROR////
/////////////
All error will be listed if object is broken
*/
DECLARE @AllObjectName TABLE (
OrdinalNo INT IDENTITY
,ObjectName NVARCHAR(MAX)
,ObjectType NVARCHAR(MAX)
,ErrorMessage NVARCHAR(MAX)
)
INSERT INTO @AllObjectName (
ObjectName
,ObjectType
)
SELECT '[' + SCHEMA_NAME(schema_id) + '].[' + NAME + ']' ObjectName
,CASE [TYPE]
WHEN 'P'
THEN 'Stored Procedure'
WHEN 'V'
THEN 'View'
WHEN 'FN'
THEN 'Scalar function'
WHEN 'TR'
THEN 'DML trigger'
WHEN 'TF'
THEN 'Table-valued-function'
ELSE 'Unknown Type'
END
FROM sys.objects
WHERE [TYPE] IN (
'P'
,'V'
,'FN'
,'TR'
,'TF'
)
ORDER BY NAME
DECLARE @i INT = 1
DECLARE @RowCount INT = (
SELECT count(1)
FROM @AllObjectName
)
DECLARE @ObjectName VARCHAR(MAX)
WHILE @i <= @RowCount
BEGIN
BEGIN TRY
SET @ObjectName = (
SELECT ObjectName
FROM @AllObjectName
WHERE OrdinalNo = @i
)
EXEC sys.sp_refreshsqlmodule @ObjectName
END TRY
BEGIN CATCH
DECLARE @message VARCHAR(4000)
,@xstate INT;
SELECT @message = ERROR_MESSAGE()
,@xstate = XACT_STATE();
IF @xstate = - 1
ROLLBACK;
UPDATE @AllObjectName
SET ErrorMessage = @message
WHERE OrdinalNo = @i
END CATCH
SET @i = @i + 1
END
SELECT ObjectName
,ObjectType
,ErrorMessage
FROM @AllObjectName
WHERE ErrorMessage IS NOT NULL
And the
below one
search for unresolved references .. Generally which treated aswarning
, is still may causeerror
sometime
/*
/////////////
///Warning///
/////////////
Here all warning will come if object reference is not stated properly
*/
SELECT TOP (100) PERCENT QuoteName(OBJECT_SCHEMA_NAME(referencing_id)) + '.' + QuoteName(OBJECT_NAME(referencing_id)) AS [this Object...]
,o.type_desc
,ISNULL(QuoteName(referenced_server_name) + '.', '') + ISNULL(QuoteName(referenced_database_name) + '.', '') + ISNULL(QuoteName(referenced_schema_name) + '.', '') + QuoteName(referenced_entity_name) AS [... depends ON this missing entity name]
,sed.referenced_class_desc
FROM sys.sql_expression_dependencies AS sed
LEFT JOIN sys.objects o ON sed.referencing_id = o.object_id
WHERE (is_ambiguous = 0)
AND (OBJECT_ID(ISNULL(QuoteName(referenced_server_name) + '.', '') + ISNULL(QuoteName(referenced_database_name) + '.', '') + ISNULL(QuoteName(referenced_schema_name) + '.', '') + QuoteName(referenced_entity_name)) IS NULL)
AND NOT EXISTS (
SELECT *
FROM sys.types
WHERE types.NAME = referenced_entity_name
AND types.schema_id = ISNULL(SCHEMA_ID(referenced_schema_name), SCHEMA_ID('dbo'))
)
ORDER BY [this Object...]
,[... depends ON this missing entity name]
Thanks @SQLMonger .. for providing me the clue to make the
First query
which was my actual requirement