2010-02-24 19 views
22

¿Hay alguna herramienta que encuentre todos los objetos en SQL Server (funciones, procs, vistas) que no pueden funcionar porque se refieren a objetos que no existen?Buscar objetos rotos en SQL Server

+1

Hay una serie de cuestiones fundamentales con esto si usted tiene cualquiera de SQL dinámico - que potencialmente podría referirse a cualquier objeto en absoluto, especialmente si se combina con INFORMATION_SCHEMA. ¿Es justo suponer que el uso de SQL dinámico es lo suficientemente raro para que esto no sea un problema? –

+1

Estaría muy feliz de encontrar aquellos que se sabe que faltan estáticamente. El SQL dinámico es un tema con el que no estoy preparado ahora. –

Respuesta

2

En realidad estoy usando el procedimiento sys.refreshmodule ahora envuelto en una secuencia de comandos PowerShell con el servidor SQL Powershell añadir complementos.

Esto funciona mejor porque esta pequeña función de sys útil se deshace de las cosas CREATE vs ALTER. Algunas otras respuestas aquí también usan este enfoque, pero prefiero este que está envuelto en Powershell y tal vez algunos lo encuentren útil.

$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

Usted puede estar interesado en probar los siguientes artículos:

Puede probar solución de Michael J. Swart de la siguiente manera:

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; 

Que devuelve:

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

Eso se ve muy prometedor. Sin embargo, hay una pequeña falla en la cláusula where. Necesita "AND ISNULL (sys.sql_expression_dependencies.referenciado_base_base_datos, 'XXX') = 'XXX' 'si utiliza consultas entre bases de datos –

+1

Respaldo esta solución :-) Tenga en cuenta que se basa en sys.sql_expression_dependencies que es una nueva vista en SQL Server 2008. –

+1

Esto está produciendo un * lote * de falsos positivos en mis bases de datos de prueba - podrían ser entidades en múltiples esquemas, podría ser el uso de sinónimos. La otra secuencia de comandos en una respuesta aquí y la secuencia de comandos en el comentario # 5 del enlace Michael J Swart producen resultados que parecen mejor, pero no estoy de acuerdo - revisaremos los resultados y encontraremos por qué, y en cuáles se puede confiar! – eftpotrm

0

Su mejor opción es comenzar a utilizar una herramienta como Visual Studio Database Edition. Su función es administrar un esquema de base de datos. Una de las muchas cosas que hará es lanzar un error cuando intente construir el proyecto de base de datos y contenga objetos rotos. Por supuesto, hará mucho más que esto. La herramienta es gratuita para cualquier usuario de Visual Studio Team Suite o Visual Studio Developer Edition.

+0

Desgraciadamente eso no funcionará. Ese producto no maneja las referencias circulares entre las bases de datos. –

6

Red Gate Software SQL Prompt 5 tiene una función Find Invalid Objects que puede ser útil en esta situación. La herramienta va a través de la base de datos encontrando objetos que darán un error cuando se ejecuten, que suena exactamente como usted quiere.

Puede descargar una versión de prueba de 14 días gratis, para que pueda probar y ver si ayuda.

Paul Stephenson
director de proyecto de software SQL Prompt
Puerta Roja

+0

An [usuario anónimo comenta] (http://stackoverflow.com/suggested-edits/202231) que su herramienta no funciona correctamente cuando falta una función (que supongo que sería mejor como un informe de error para usted) – Rup

0

Nota la consulta en este hilo encuentra objetos perdidos, no los inválidos.  
SQL Server no encuentra que un objeto de referencia no sea válido hasta que lo ejecute.

realce a esa consulta para manejar objetos de otros esquemas, así como los tipos:

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

Esto es produciendo un falso positivo para mí cuando tienes una referencia de DB cruzada, lo siento. – eftpotrm

6

Las dos soluciones anteriores aquí son interesantes, pero ambos fracasaron en mis bases de datos de prueba.

La secuencia de comandos original de Michael J Swart produjo una gran cantidad de falsos positivos para mí, demasiados para atravesarlos. La solución de Rick V. aquí fue mejor: los únicos falsos positivos que dio fueron referencias cruzadas de bases de datos.

¡Hay un comentario en el artículo de Michael J Swart de RaduSun que ofrece una solución que aún no puedo romper! Esto es, moderadamente ajustado para la legibilidad y mis propósitos, pero acredite a RaduSun por la lógica.

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

Esto es genial, excepto que no maneja referencias a tipos definidos por el usuario. Para una solución rápida y sucia para mí, acabo de agregar 'AND NOT EXISTS (SELECT * FROM sys.types WHERE types.name = nombre_entidad_referencia Y types.schema_id = ISNULL (SCHEMA_ID (referencia_sombre_esquema), SCHEMA_ID ('dbo'))) 'a la cláusula' WHERE', pero probablemente haya una mejor manera. – siride

+0

Gracias por extenderme para manejar eso, no tenía ningún UDT para probarlo en contra de :-) – eftpotrm

+0

He estado usando esta consulta por un tiempo hasta que nos actualicé a SQL 2016. Ahora informa cada activador como no válido debido a referencias a las tablas INSERTED y 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 le dará rota nombre de objetos incluye Stored Procedure, View, Scalar function, DML trigger, Table-valued-function tipo

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

Y la búsqueda de referencias no resueltas below one .. En general, el cual trata como warning, es todavía puede causar algún 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] 

Gracias @SQLMonger .. por darme la clave para hacer que el First query que era mi requisito real

+0

¡Esa primera consulta es PERFECTA! ¡Gracias por eso, es increíble! No puedo creer después de cuántas décadas, MS aún no ha desarrollado algo como esto. ¡Casi quiero tomar esa consulta y concluir y descubrir cómo escribir un plugin de SSMS! – eidylon

+0

@eidylon ... Eso es genial ... también estoy creando ... tendré la actualización pronto ... aquí está el enlace .... https://marketplace.visualstudio.com/items?itemName=MrMKM. Datos maestros – Moumit

1

Escribí un guión hace algunos años que encontrará Stored Proced ures que no se compilarán tirando del texto del proceso e intentando recompilarlo con un bloque try/catch. Es bastante simple y eficaz para encontrar al menos procedimientos que se pueden descartar. Podrías expandirlo fácilmente para obtener vistas.

Tenga en cuenta que solo debe ejecutar esto en un entorno DEV o TEST, ya que en realidad está intentando volver a compilar los procedimientos.

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

A partir de SQL Server 2008, un método mucho más simple es aquí:

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; 

Como se menciona en el artículo fuente (Microsoft MSDN Article on Finding Missing Dependencies), "Un valor 'NULL' en el" objeto encontrado? la columna indica que el objeto no se encontró en sys.objects ".

Ejemplo de salida:

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