在SQL Server中查找损坏的对象

Jon*_*len 23 sql-server sql-server-2008

是否有一个工具可以找到SQL Server中的所有对象(函数,过程,视图),这些对象无法工作,因为它们引用了不存在的对象?

Dan*_*llo 17

您可能有兴趣查看以下文章:

您可以按如下方式测试Michael J. Swart的解决方案:

CREATE PROCEDURE proc_bad AS
    SELECT col FROM nonexisting_table
GO

SELECT
    OBJECT_NAME(referencing_id) AS [this sproc or VIEW...],
    referenced_entity_name AS [... depends ON this missing entity name]
FROM 
    sys.sql_expression_dependencies
WHERE 
    is_ambiguous = 0
    AND OBJECT_ID(referenced_entity_name) IS NULL
ORDER BY 
    OBJECT_NAME(referencing_id), referenced_entity_name;
Run Code Online (Sandbox Code Playgroud)

哪个回报:

+------------------------+------------------------------------------+
| this sproc or VIEW...  |  ... depends ON this missing entity name |
|------------------------+------------------------------------------|
| proc_bad               |  nonexisting_table                       |
+------------------------+------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

  • 这看起来确实很有希望。但是where子句中有一个小缺陷。如果您使用跨数据库查询,则它需要“ AND ISNULL(sys.sql_expression_dependencies.referenced_database_name,'XXX')='XXX'”。 (2认同)
  • 这在我的测试数据库上产生了大量的误报-可能是多个模式中的实体,可能是同义词。答案中的其他脚本和Michael J Swart链接的注释5中的脚本所产生的结果看起来更好,但不太一致-将仔细检查结果并找出原因,并且可以相信! (2认同)

eft*_*trm 10

此前的两个解决方案很有意思,但我的测试数据库都失败了.

最初的迈克尔·斯沃特(Michael J Swart)剧本给我带来了大量误报,太多不值得趟过.Rick V.在这里的解决方案更好 - 它给出的唯一误报是跨数据库引用.

有关RaduSun的Michael J Swart文章的评论给出了一个我无法打破的解决方案!这是它,为了可读性和我的目的而温和地调整,但是归功于RaduSun的逻辑.

SELECT 
    QuoteName(OBJECT_SCHEMA_NAME(referencing_id)) + '.' 
        + QuoteName(OBJECT_NAME(referencing_id)) AS ProblemObject,
    o.type_desc,
    ISNULL(QuoteName(referenced_server_name) + '.', '')
    + ISNULL(QuoteName(referenced_database_name) + '.', '')
    + ISNULL(QuoteName(referenced_schema_name) + '.', '')
    + QuoteName(referenced_entity_name) AS MissingReferencedObject
FROM
    sys.sql_expression_dependencies 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)
ORDER BY
    ProblemObject,
    MissingReferencedObject
Run Code Online (Sandbox Code Playgroud)


Pau*_*son 6

Red Gate Software的SQL Prompt 5具有Find In Invalid Objects功能,在这种情况下可能很有用.该工具通过数据库查找在执行时会产生错误的对象,这听起来正是您想要的.

您可以免费下载14天的试用版,因此您可以尝试一下,看看它是否有帮助.

Paul Stephenson
SQL提示项目经理
Red Gate Software


Mou*_*mit 6

First query会给你破对象名称包括Stored Procedure,View,Scalar function,DML trigger,Table-valued-function类型

/*
/////////////
////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
Run Code Online (Sandbox Code Playgroud)

并且below one搜索未解决的引用.通常被视为warning,仍然可能会导致error某些时候

/*
/////////////
///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]
Run Code Online (Sandbox Code Playgroud)

谢谢@SQLMonger ..为我提供了线索,使其成为First query我的实际要求


dev*_*ost 6

从 SQL Server 2008 开始,这里有一个更简单的方法:

 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;
Run Code Online (Sandbox Code Playgroud)

正如源文章(Microsoft MSDN 文章关于查找缺失的依赖项)中所述,“找到的对象中有一个 'NULL' 值?” 列表示在 sys.objects 中未找到该对象。”

示例输出:

??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
?            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    ?
??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

如果您收到一条错误消息,指出子查询返回了多个值,那么您就有多个名称等于 [referenced_entity_name] 的对象,您将需要通过添加另一个 where 子句来使子查询更加具体。

您可以通过检查 sys.objects 获取更多信息,如下所示:

SELECT *
FROM   sys.objects
WHERE  name = [referenced_entity_name]
Run Code Online (Sandbox Code Playgroud)

如果仅凭这些信息不足以确定如何区分您的多个结果,您可能需要将 sys.objects 加入其他元数据视图之一(主要记录在此处:https : //docs.microsoft.com /en-us/sql/relational-databases/system-catalog-views/object-catalog-views-transact-sql?view=sql-server-ver15)或 sys.schemas (记录在这里:https://docs。 microsoft.com/en-us/sql/relational-databases/system-catalog-views/schemas-catalog-views-sys-schemas?view=sql-server-ver15)以获取更多信息。


SQL*_*ger 5

/*
modified version of script from http://michaeljswart.com/2009/12/find-missing-sql-dependencies/
Added columns for object types & generated refresh module command...
filter out user-define types: http://stackoverflow.com/questions/2330521/find-broken-objects-in-sql-server
Run Code Online (Sandbox Code Playgroud)

* /

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
    ,case when o.type_desc in( 'SQL_STORED_PROCEDURE' ,'SQL_SCALAR_FUNCTION' ,'SQL_TRIGGER' ,'VIEW')
          then 'EXEC sys.sp_refreshsqlmodule ''' + QuoteName(OBJECT_SCHEMA_NAME(referencing_id)) + '.' + QuoteName(OBJECT_NAME(referencing_id)) + ''';'
          else null
       end as [Refresh SQL Module command]
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]
Run Code Online (Sandbox Code Playgroud)


Bre*_*een 2

我实际上正在使用 sys.refreshmodule 过程,该过程现在包含在带有 SQL Server Powershell 插件的 powershell 脚本中。

\n\n

这效果更好,因为这个方便的小 sys 函数摆脱了 CREATE 与 ALTER 的东西。这里的其他一些答案也使用这种方法,但我更喜欢这种封装在 Powershell 中的方法,也许有些人会发现它很有用。

\n\n
$server = "YourDBServer"\ncls\nImport-Module \xe2\x80\x9csqlps\xe2\x80\x9d -DisableNameChecking\n\n$databases = Invoke-Sqlcmd -Query "select name from sys.databases where name not in (\'master\', \'tempdb\', \'model\', \'msdb\')" -ServerInstance $server\nforeach ($db in $databases) {\n    $dbName = $db.name\n    $procedures = Invoke-Sqlcmd -Query "select SCHEMA_NAME(schema_id) as [schema], name from $dbName.sys.procedures" -ServerInstance $server\n    foreach ($proc in $procedures) {\n        if ($schema) {\n            $shortName = $proc.schema + "." + $proc.name\n            $procName =  $db.name + "." + $shortName\n            try {\n                $result = Invoke-Sqlcmd -Database $dbName -Query "sys.sp_refreshsqlmodule \'$shortName\'" -ServerInstance $server -ErrorAction Stop\n                Write-Host "SUCCESS|$procName"\n            }\n            catch {\n                $msg = $_.Exception.Message.Replace([Environment]::NewLine, ",")\n                Write-Host "FAILED|$procName|$msg" -ForegroundColor Yellow\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n