【问题标题】:How do I find all stored procedures that insert, update, or delete records?如何找到所有插入、更新或删除记录的存储过程?
【发布时间】:2023-03-18 20:58:01
【问题描述】:

是否可以在不解析源的情况下选择插入、更新或删除记录的所有存储过程名称的列表?我需要创建一个 TSQL 实用程序脚本来执行此操作。效率不是问题,因为它每年只运行几次(Curse'rs 我的意思是 Cursors 还可以)。理想情况下,此脚本不包括对临时表或局部变量表的更新。

我尝试了在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 

但它会产生假阴性。

【问题讨论】:

  • 您提供的链接包含此问题的答案...只需添加删除即可。
  • 即使只更新 sprocs,我仍然有大约 5% 的失败率。

标签: sql-server tsql


【解决方案1】:

这就是 sys.sql_dependencies 的问题。 SQL 不能准确地跟踪存储过程中的依赖关系(有充分的理由为什么它不能,但现在不要去那里)。这甚至没有考虑动态 SQL 或 CLR 过程。

Visual Studio 数据库版有一些更好的功能,但它可以跟踪 scipts 中的依赖关系,而不是实时数据库中的依赖关系。它可以将实时数据库逆向工程为脚本并分析生成的脚本,比 sys.sql_dependencies 更准确。它无法处理动态 SQL。

【讨论】:

    【解决方案2】:

    在所有非模式绑定存储过程上调用sp_refreshsqlmodule

    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
                )
    

    【讨论】:

    • 感谢运行这让我更接近。仍然有一些假阴性,但只有少数。我能够使用我的原始代码和你的代码来足够接近。我发布了我的代码作为答案。
    • 您是否发现任何因基础更改而变得无效的 SP?这总是很有趣;-)
    【解决方案3】:

    感谢 Cade Roux 的回答,我能够非常接近:

    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].['+@ROUTINE_NAME+'] TO ['+@RoleName +']   '  
    
    
        FETCH NEXT FROM GrantList INTO @ROUTINE_NAME
    END
    CLOSE GrantList
    DEALLOCATE GrantList
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-03
      • 2014-06-23
      • 1970-01-01
      • 1970-01-01
      • 2019-04-09
      • 1970-01-01
      • 2021-12-03
      相关资源
      最近更新 更多