2009-12-04 12 views
5

¿Es posible, sin fuente de análisis, seleccionar una lista de todos los nombres de sproc que insertan, actualizan o eliminan registros? Necesito crear un script de utilidad TSQL que haga esto. La eficiencia no es un problema, ya que se ejecutará solo unas pocas veces al año (Cursores, quiero decir, los cursores están bien). Idealmente, esta secuencia de comandos no incluiría actualizaciones a tablas de variables locales o temporales.¿Cómo encuentro todos los procedimientos almacenados que insertan, actualizan o eliminan registros?

Intenté la siguiente consulta en SO Question.

SELECT 
so.name, 
so2.name, 
sd.is_updated 
from sysobjects so 
inner join sys.sql_dependencies sd on so.id = sd.object_id 
inner join sysobjects so2 on sd.referenced_major_id = so2.id 
where so.xtype = 'p' -- procedure 
and 
is_updated = 1 -- proc updates table, or at least, I think that's what this means 

Pero produce falsos negativos.

+0

El enlace que se incluye la respuesta a esta pregunta ... solo tiene que agregar eliminarlo. –

+0

Todavía estoy obteniendo una tasa de falure de alrededor del 5% incluso en sprocs de actualización. –

Respuesta

6

llamada sp_refreshsqlmodule en toda la no-esquema de procedimientos almacenados con destino:

DECLARE @template AS varchar(max) 
SET @template = 'PRINT ''{OBJECT_NAME}'' 
EXEC sp_refreshsqlmodule ''{OBJECT_NAME}'' 

' 

DECLARE @sql AS varchar(max) 

SELECT @sql = ISNULL(@sql, '') + REPLACE(@template, '{OBJECT_NAME}', 
              QUOTENAME(ROUTINE_SCHEMA) + '.' 
              + QUOTENAME(ROUTINE_NAME)) 
FROM INFORMATION_SCHEMA.ROUTINES 
WHERE OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.' 
           + QUOTENAME(ROUTINE_NAME)), 
         N'IsSchemaBound') IS NULL 
     OR OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.' 
            + QUOTENAME(ROUTINE_NAME)), 
          N'IsSchemaBound') = 0 

     EXEC (
       @sql 
      ) 
+0

Gracias ejecutar esto me acerca más. Todavía hay algunos falsos negativos, pero solo algunos. Pude usar mi código original junto con el tuyo para acercarte lo suficiente. Publiqué mi código como una respuesta. –

+0

¿Encontró algún SP que se haya vuelto inválido debido a un cambio subyacente? Eso siempre es divertido ;-) –

1

Ese es el problema con sys.sql_dependencies. SQL no puede rastrear con precisión las dependencias en procedimientos almacenados (hay razones sólidas por las que no puede, pero no permite que vaya allí ahora). Eso es sin siquiera considerar los procedimientos dinámicos de SQL o CLR.

Visual Studio Database Edition tiene algunas capacidades mejores, pero puede rastrear dependencias en scipts, no en una base de datos en vivo. Sin embargo, puede realizar una ingeniería inversa de bases de datos en vivo en scripts y analizar los scripts resultantes, con una precisión superior a la que sys.sql_dependencies puede. No puede manejar SQL dinámico.

0

, gracias a la respuesta de Cade Roux yo era capaz de llegar muy cerca con esto:

DECLARE @RoleName nvarchar(255) 
SET @RoleName = 'READONLYUSER' 

DECLARE @ROUTINE_NAME nvarchar(255) 
DECLARE RoutineList Cursor FOR 
SELECT ROUTINE_NAME 
FROM INFORMATION_SCHEMA.ROUTINES 
WHERE (OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME)), N'IsSchemaBound') IS NULL OR OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME)), N'IsSchemaBound') = 0) 
    AND NOT ROUTINE_NAME like 'sel%' 
    AND NOT ROUTINE_NAME like 'sp_upd%' 
    AND NOT ROUTINE_NAME like 'sp_sel%' 
    AND NOT ROUTINE_NAME like 'sp_ins%' 
OPEN RoutineList 
FETCH NEXT FROM RoutineList 
INTO @ROUTINE_NAME 
WHILE @@FETCH_STATUS = 0 
BEGIN 

    EXEC ('EXEC sp_refreshsqlmodule ''' + @ROUTINE_NAME + '''') 

    FETCH NEXT FROM RoutineList INTO @ROUTINE_NAME 
END 
CLOSE RoutineList 
DEALLOCATE RoutineList 


DECLARE GrantList Cursor FOR 
SELECT DISTINCT 
    so.name AS ROUTINE_NAME 
FROM sysobjects so 
LEFT JOIN (
    SELECT 
     so.name, 
     so2.name AS [table], 
     sd.is_updated 
     FROM sysobjects so 
     INNER JOIN sys.sql_dependencies sd ON so.id = sd.object_id 
     INNER JOIN sysobjects so2 ON sd.referenced_major_id = so2.id 
     WHERE so.xtype = 'p' 
     and is_updated = 1 
) Updates ON so.name = Updates.name 
WHERE 
    so.xtype = 'p' -- procedure 
    AND Updates.name is null 
    AND so.name NOT LIKE '%[_]%' 
ORDER BY so.name 

OPEN GrantList 
FETCH NEXT FROM GrantList 
INTO @ROUTINE_NAME 
WHILE @@FETCH_STATUS = 0 
BEGIN 

    print 'GRANT EXECUTE ON [dbo].['[email protected]_NAME+'] TO ['[email protected] +'] ' 


    FETCH NEXT FROM GrantList INTO @ROUTINE_NAME 
END 
CLOSE GrantList 
DEALLOCATE GrantList 
Cuestiones relacionadas