2010-02-24 4 views
22

Existe-t-il un outil qui trouvera tous les objets dans SQL Server (fonctions, procs, vues) qui ne peuvent pas fonctionner car ils font référence à des objets qui n'existent pas?Trouver des objets brisés dans SQL Server

+1

Il y a une des questions fondamentales avec si vous avez une dynamique SQL - qui pourrait se référer à un objet quelconque, en particulier si elle est combinée avec INFORMATION_SCHEMA. Est-il juste de présumer que votre utilisation du SQL dynamique est assez rare pour que ce ne soit pas un problème? –

+1

Je serais vraiment heureux juste de trouver ceux qui sont statiquement connus pour être manquant. SQL dynamique est un sujet que je ne suis pas prêt à traiter en ce moment. –

Répondre

2

J'utilise en fait la procédure sys.refreshmodule maintenant enveloppé dans un script Powershell avec SQL Server Powershell COLMATAGES.

Cela fonctionne mieux parce que cette petite fonction pratique sys se débarrasse de la substance CREATE vs ALTER. D'autres réponses utilisent également cette approche, mais je préfère celle qui est enveloppée dans Powershell et peut-être que certains la trouveront utile.

$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

Vous pouvez être intéressé à vérifier les articles suivants:

Vous pouvez tester la solution de Michael J. Swart comme suit:

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; 

Quels retours:

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

Cela semble vraiment prometteur. Il y a un léger défaut dans la clause where. Il a besoin de "AND ISNULL (sys.sql_expression_dependencies.reference_database_name, 'XXX') = 'XXX' "si vous utilisez des requêtes inter-base de données –

+1

J'approuve cette solution :-) Gardez à l'esprit qu'elle repose sur sys.sql_expression_dependencies qui est une nouvelle vue dans SQL Server 2008. –

+1

un * lot * de faux positifs sur mes bases de test - peut-être des entités dans plusieurs schémas, pourrait être l'utilisation de synonymes.L'autre script dans une réponse ici et le script dans le commentaire # 5 du lien Michael J Swart produisent tous deux des résultats qui ressemblent mieux mais pas tout à fait d'accord - va passer en revue les résultats et trouver pourquoi, et qui peut être approuvé! – eftpotrm

0

Votre meilleur pari est de commencer à utiliser un outil comme Visual Studio Database Edition. Son rôle est de gérer un schéma de base de données. Une des choses qu'il va faire est de lancer une erreur quand vous essayez de construire le projet de base de données et qu'il contient des objets cassés. Il va bien sûr faire beaucoup plus que cela. L'outil est gratuit pour tout utilisateur de Visual Studio Team Suite ou de Visual Studio Developer Edition.

+0

Hélas cela ne fonctionnera pas Ce produit ne gère pas les références circulaires entre les bases de données –

6

La fonctionnalité SQL Prompt 5 de Red Gate Software comporte une fonctionnalité Find Invalid Objects qui peut s'avérer utile dans cette situation. L'outil parcourt la base de données pour trouver des objets qui donneront une erreur lors de l'exécution, ce qui sonne exactement ce que vous voulez.

Vous pouvez télécharger gratuitement un essai gratuit de 14 jours. Vous pouvez donc essayer et voir si cela vous aide.

Paul Stephenson
Chef de projet SQL Prompt
Red Gate Software

+0

An [commentaires d'utilisateurs anonymes] (http://stackoverflow.com/suggested-edits/202231) que votre outil ne fonctionne pas correctement lorsqu'une fonction est manquante (ce qui serait mieux pour vous un rapport de bogue?) – Rup

0

Notez la requête dans ce thread trouve des objets manquants, et non pas ceux non valides.  
SQL Server ne trouve pas qu'un objet référençant n'est pas valide tant que vous ne l'avez pas exécuté.

Amélioration de cette requête pour manipuler des objets dans d'autres schémas ainsi que les 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 + ']' 
+0

Ceci est produisant un faux positif pour moi quand vous avez une référence de croix-DB, désolé. – eftpotrm

6

Les deux solutions précédentes sont intéressantes ici, mais les deux échoué sur mes bases de données de test.

Le script Michael J Swart original a produit un grand nombre de faux positifs pour moi, beaucoup trop à parcourir. La solution de Rick V. était meilleure ici - les seuls faux positifs qu'elle a donnés étaient pour les références de bases de données croisées.

Il ya un commentaire sur l'article de Michael J Swart par RaduSun qui donne une solution que je ne peux pas encore casser si! Ceci est, légèrement modifié pour la lisibilité et mes objectifs, mais le crédit à RaduSun pour la logique.

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

C'est génial, sauf qu'il ne gère pas les références aux types définis par l'utilisateur. Pour une solution rapide et sale pour moi-même, je viens d'ajouter 'AND NOT EXISTS (SELECT * FROM sys.types WHERE types.nom = nom_réité_référé ET types.schema_id = ISNULL (SCHEMA_ID (nom_schéma_référencé), SCHEMA_ID ('dbo'))) 'à la clause' WHERE', mais il y a probablement un meilleur moyen. – siride

+0

Merci siride pour l'étendre à gérer cela, je n'ai eu aucun UDT pour le tester contre :-) – eftpotrm

+0

J'ai utilisé cette requête pendant un certain temps jusqu'à ce que nous avons mis à niveau vers SQL 2016. Maintenant, il signale chaque déclencheur comme non valide en raison de références aux tables INSERTED et 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 vous donnera le nom d'objets cassés comprend Stored 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 

Et la below one recherche de références non résolues .. En général, qui a traité comme warning, est peut-être encore quelque temps causer 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] 

Merci @SQLMonger .. pour me donner la moindre idée de faire la First query qui était mon exigence réelle

+0

Cette première requête est PARFAITE! Merci pour ça, c'est génial! Je ne peux pas croire après combien de décennies, MS n'a pas encore construit quelque chose comme ça. Je veux presque prendre cette requête et l'emballer et comprendre comment écrire un plugin SSMS! – eidylon

+0

@eidylon ... C'est génial ... j'en crée un aussi ... aura la mise à jour bientôt .. voici le lien .... https://marketplace.visualstudio.com/items?itemName=MrMKM. Données de base – Moumit

1

J'ai écrit un script il y a quelques années qui trouveront des procédures stockées ures qui ne compileront pas en tirant le texte du proc et en essayant de le recompiler avec un bloc try/catch. C'est assez simple et efficace pour trouver au moins des procédures qui peuvent être abandonnées. Vous pourriez facilement l'agrandir pour les vues.

Notez que vous ne devez l'exécuter que sur un environnement DEV ou TEST car il tente réellement de recompiler les procédures.

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

À partir de SQL Server 2008, une méthode beaucoup plus simple est ici:

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; 

Comme mentionné dans l'article source (Microsoft MSDN Article on Finding Missing Dependencies), « Une valeur 'NULL' dans le 'objet trouvé? colonne indique que l'objet n'a pas été trouvé dans sys.objects. "

Exemple de sortie:

╔═══════════════════════════════════════════════╦═══════════════════════╦════════════════════════╦═══════════════════════════════════════╦═══════════════╗ 
║   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 ║ 
╚═══════════════════════════════════════════════╩═══════════════════════╩════════════════════════╩═══════════════════════════════════════╩═══════════════╝ 
Questions connexes