2010-02-24 13 views
22

是否有一種工具可以查找SQL Server(函數,過程,視圖)中的所有對象,因爲它們引用不存在的對象而無法工作?在SQL Server中查找破碎的對象

+1

有一個根本性的問題與此,如果您有任何動態SQL - 這可能是指任何對象可言,特別是如果與INFORMATION_SCHEMA結合。假設您使用動態SQL非常罕見,這不是一個問題,這是否公平? –

+1

只要找到那些靜態已知缺失的部分,我就會非常開心。動態SQL是我現在還沒有準備好處理的一個主題。 –

回答

2

我實際使用sys.refreshmodule過程現在包裹在與SQL Server的PowerShell的PowerShell腳本添加插件。

這個效果更好,因爲這個方便的小sys功能擺脫了CREATE vs ALTER的東西。其他一些答案也使用這種方法,但我更喜歡這個包裝在Powershell中的方法,也許有些人會覺得它很有用。

$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 
      } 
     } 
    } 
} 
17

你可能有興趣在檢查出下面的文章:

您可以測試邁克爾·斯沃特的解決方案如下:

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; 

其中返回:

+------------------------+------------------------------------------+ 
| this sproc or VIEW... | ... depends ON this missing entity name | 
|------------------------+------------------------------------------| 
| proc_bad    | nonexisting_table      | 
+------------------------+------------------------------------------+ 
+0

這看起來很有希望。儘管在where子句中有一個小小的缺陷。它需要「AND ISNULL(sys.sql_expression_dependencies。如果您使用跨數據庫查詢 –

+1

我支持此解決方案:-)請記住它依賴於sys.sql_expression_dependencies這是SQL Server 2008中的新視圖。 –

+1

這是生產在我的測試數據庫中有很多誤報 - 可能是多個模式中的實體,可能是同義詞的使用。這裏的答案中的另一個腳本和Michael J Swart鏈接的評論#5中的腳本都產生了看起來像更好,但不完全同意 - 將通過結果,並找出爲什麼,哪些可以信任! – eftpotrm

0

最好的辦法是開始使用像Visual Studio數據庫版本這樣的工具。它的作用是管理數據庫模式。它會做的很多事情之一是當你試圖構建數據庫項目並且它包含破碎的對象時拋出一個錯誤。它當然會做得比這更多。該工具對Visual Studio Team Suite或Visual Studio Developer Edition的任何用戶都是免費的。

+0

唉,這將無法正常工作。該產品不處理數據庫之間的循環引用。 –

6

Red Gate Software的SQL Prompt 5有一個查找無效對象功能,可能在這種情況下有用。該工具會通過數據庫查找在執行時會發出錯誤的對象,這聽起來正是您想要的。

您可以免費下載14天的免費試用版,所以您可以嘗試一下,看看它是否有幫助。

保羅·斯蒂芬森
SQL提示項目經理
紅門軟件

+0

An [anonymous user comments]( http://stackoverflow.com/suggested-edits/202231)當一個函數缺失時,你的工具不能正常工作(我猜這會更好,因爲你的錯誤報告?) – Rup

0

注意,在這個線程查詢查找缺少的對象,而不是無效的。  
SQL Server在執行它之前未發現引用對象無效。

增強到查詢處理其他架構以及類型的對象:

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 + ']' 
+0

這是當你有一個跨數據庫引用時,對我產生誤報,對不起。 – eftpotrm

6

前兩次在這裏的解決方案是有趣的,但都失敗了我的測試數據庫。

原來的邁克爾J斯沃特腳本產生了大量的誤報,對我來說太多了,無法穿越。 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 
+0

這很好,除了它不處理對用戶定義類型的引用。對於自己而言,我只是添加了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')) )'到'WHERE'子句,但可能有更好的方法。 – siride

+0

謝謝siride擴展它來處理,我沒有任何UDT來測試它:-) – eftpotrm

+0

我一直在使用這個查詢一段時間,直到我們升級到SQL 2016.現在它報告每一個觸發器無效,因爲引用INSERTED和DELETED表 –

4
/* 
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 

*/

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] 
4

First query會給你破對象名稱包括Stored ProcedureViewScalar functionDML triggerTable-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 

而且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] 

感謝@SQLMonger ..爲我提供線索,使First query這是我的實際要求

+0

第一個查詢是PERFECT!謝謝你,這真棒!我無法相信在幾十年後,MS仍然沒有建立這樣的東西。我幾乎想要接受這個問題並且把它包裝起來,想出如何編寫一個SSMS插件! – eidylon

+0

@eidylon ...那太好了......我正在創建一個......很快就會有更新..這裏是鏈接.... https://marketplace.visualstudio.com/items?itemName=MrMKM。主要的數據 – Moumit

1

我寫了一個腳本幾年前,會發現存儲過程ures不能通過拉取proc文本來編譯,並嘗試用try/catch塊重新編譯它。這非常簡單而且有效地發現至少可以放棄的程序。您可以輕鬆擴展視圖。

請注意,您應該只針對DEV或TEST環境運行此操作,因爲它實際上是在嘗試重新編譯這些過程。

SET NOCOUNT ON 

DECLARE @ProcedureName VARCHAR(2048) 
DECLARE @ProcedureBody VARCHAR(MAX) 

DECLARE @RoutineName varchar(500) 

DECLARE procCursor CURSOR STATIC FORWARD_ONLY READ_ONLY 
FOR 
SELECT 
--TOP 1 
SCHEMA_NAME(schema_id) + '.' + NAME AS ProcedureName, 
OBJECT_DEFINITION(o.[object_id]) AS ProcedureBody 
FROM sys.objects AS o 
WHERE o.[type] = 'P' 
ORDER BY o.[name] 

OPEN procCursor 
FETCH NEXT FROM procCursor INTO @ProcedureName, @ProcedureBody 

WHILE @@FETCH_STATUS = 0 
BEGIN 
-- Might have to play with this logic if you don't have discipline in your create statements 
SET @ProcedureBody = REPLACE(@ProcedureBody, 'CREATE PROCEDURE', 'ALTER PROCEDURE') 

BEGIN TRY 
    EXECUTE(@ProcedureBody) 
    PRINT @ProcedureName + ' -- Succeeded' 
END TRY 
BEGIN CATCH 
    PRINT @ProcedureName + ' -- Failed: ' + ERROR_MESSAGE() 
END CATCH 

FETCH NEXT FROM procCursor INTO @ProcedureName, @ProcedureBody 
END 

CLOSE procCursor 
DEALLOCATE procCursor 

https://brettwgreen.wordpress.com/2012/12/04/find-stored-procedures-that-wont-compile/

1

由於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; 

正如文章出處(Microsoft MSDN Article on Finding Missing Dependencies),「在A '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 ║ 
╚═══════════════════════════════════════════════╩═══════════════════════╩════════════════════════╩═══════════════════════════════════════╩═══════════════╝