【问题标题】:How to find data table column reference in stored procedures如何在存储过程中查找数据表列引用
【发布时间】:2009-07-10 20:08:27
【问题描述】:

我在我的 SQL Server 2005 数据库的表中更改了列名。我还有一个相当大的存储过程集合,它们可能引用也可能不引用该列。有没有办法找到哪些存储过程引用了该列,而无需实际遍历每个存储过程并手动搜索它?有没有办法自动找到什么存储过程现在会中断或什么?我无法使用像 RedGate 的 SQL Refactor 这样的 SQL 重构工具。

谢谢!

【问题讨论】:

  • 你知道 SQL Refactor 有 14 天的试用期吗?

标签: sql-server-2005 stored-procedures refactoring automation schema


【解决方案1】:

这里有一些可以帮助你的东西。我创建了两个用户存储的过程,它们的功能与您所要求的类似。

  1. usp_depends2 - sp_depends 的扩展版本

  2. usp_FindReferences - 这个使用 usp_depends2 查找表中列的所有引用(我认为这是您需要的)


    /****** Object:  StoredProcedure [dbo].[usp_depends2]    Script Date: 11/18/2009 11:55:01 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


create procedure [dbo].[usp_depends2]  --- 1996/08/09 16:51
@objname nvarchar(776)  /* the object we want to check */
as
declare @objid int   /* the id of the object we want */
declare @found_some bit   /* flag for dependencies found */
declare @dbname sysname

/*
**  Make sure the @objname is local to the current database.
*/


DECLARE @sp_depends_xref table (
   reftype char(2)
 , dep_name nvarchar(256)
 , type   char(16)
 , updated char(7)
 , selected char(8)
 , [column] nvarchar(128))


select @dbname = parsename(@objname,3)

if @dbname is not null and @dbname <> db_name()
 begin
  raiserror(15250,-1,-1)
  return (1)
 end

/*
**  See if @objname exists.
*/
select @objid = object_id(@objname)
if @objid is null
 begin
  select @dbname = db_name()
  raiserror(15009,-1,-1,@objname,@dbname)
  return (1)
 end

/*
**  Initialize @found_some to indicate that we haven't seen any dependencies.
*/
select @found_some = 0

set nocount on

/*
**  Print out the particulars about the local dependencies.
*/
if exists (select *
  from sysdepends
   where id = @objid)
begin
 raiserror(15459,-1,-1)
 INSERT INTO @sp_depends_xref (
    refType
  ,  dep_name
  , type
  , updated
  , selected
  , [column])
 select   'TO', 'name' = (s6.name+ '.' + o1.name),
    type = substring(v2.name, 5, 16),
    updated = substring(u4.name, 1, 7),
    selected = substring(w5.name, 1, 8),
             'column' = col_name(d3.depid, d3.depnumber)
  from  sysobjects  o1
   ,master.dbo.spt_values v2
   ,sysdepends  d3
   ,master.dbo.spt_values u4
   ,master.dbo.spt_values w5 --11667
   ,sysusers  s6
  where  o1.id = d3.depid
  and  o1.xtype = substring(v2.name,1,2) collate database_default and v2.type = 'O9T'
  and  u4.type = 'B' and u4.number = d3.resultobj
  and  w5.type = 'B' and w5.number = d3.readobj|d3.selall
  and  d3.id = @objid
  and  o1.uid = s6.uid
  and deptype < 2

 select @found_some = 1
end

/*
**  Now check for things that depend on the object.
*/
if exists (select *
  from sysdepends
   where depid = @objid)
begin
  raiserror(15460,-1,-1)
 INSERT INTO @sp_depends_xref (
    RefType
  , dep_name
  , type)
 select distinct 'BY', 'name' = (s.name + '.' + o.name),
  type = substring(v.name, 5, 16)
   from sysobjects o, master.dbo.spt_values v, sysdepends d,
    sysusers s
   where o.id = d.id
    and o.xtype = substring(v.name,1,2) collate database_default and v.type = 'O9T'
    and d.depid = @objid
    and o.uid = s.uid
    and deptype < 2

 select @found_some = 1
end

/*
**  Did we find anything in sysdepends?
*/
if @found_some = 0
 raiserror(15461,-1,-1)

 SELECT
    reftype
  , dep_name
  , type
  , updated
  , selected
  , [column]
 FROM @sp_depends_xref


set nocount off


return (0) -- sp_depends
GO

    /****** Object:  StoredProcedure [dbo].[usp_FindReferences]    Script Date: 11/18/2009 11:55:05 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[usp_FindReferences] 
 -- Add the parameters for the stored procedure here
 @tablename nvarchar(500) = 0, 
 @colname nvarchar(500) = 0
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 create table #tempTableDependencies
 (
  reftype nvarchar(20),
  dep_name nvarchar(500),
  type nvarchar(500),
  updated nvarchar(500),
  selected nvarchar(500),
  col nvarchar(500)
 )

 insert into #tempTableDependencies execute usp_depends2 @tablename

 create table #tempDependencies
 (
  reftype nvarchar(20),
  dep_name nvarchar(500),
  type nvarchar(500),
  updated nvarchar(500),
  selected nvarchar(500),
  col nvarchar(500)
 )

 declare @tempFilteredDependencies table
 (
  objectname nvarchar(500),
  reftype nvarchar(20),
  dep_name nvarchar(500),
  type nvarchar(500),
  updated nvarchar(500),
  selected nvarchar(500),
  col nvarchar(500)
 )

 DECLARE @loopcounter INT
 select @loopcounter = COUNT(*) FROM #tempTableDependencies

 DECLARE @dependencyname nvarchar(500)

 WHILE @loopcounter > 0 
 BEGIN
  SELECT TOP 1 @dependencyname = dep_name FROM #tempTableDependencies 
  print 'loop_counter = ' + CAST(@loopcounter as nvarchar(20))
  print 'dependency = ' + @dependencyname

  insert into #tempDependencies execute usp_depends2 @dependencyname
  insert into @tempFilteredDependencies select @dependencyname as objectname, * from #tempDependencies where col = @colname and dep_name like '%' + @tablename
  delete from #tempDependencies
  delete from #tempTableDependencies where dep_name = @dependencyname

  SET @loopcounter = @loopcounter - 1
 END

 select * from @tempFilteredDependencies

 drop table #tempDependencies
 drop table #tempTableDependencies

END

GO

【讨论】:

    【解决方案2】:

    标准答案是“sp_depends”,但在 SQL 7.0 和 2000 中,不能保证它是准确的(即最新的)。我不知道他们是否在 SQL 2005 或 2008 中解决了这个问题,因为我在很久以前推出了自己的解决方法。这并不能完全满足您的要求,但它可以让您更快地到达那里

    它基于这个查询:

    DECLARE @SearchText varchar(100)
    
    SET @SearchText = 'ProductId'
    
    SELECT
       schema_name(ob.schema_id)  SchemaName
      ,ob.name
      ,ob.type_desc
      ,len(mo.definition) CodeLength
      ,mo.definition
     from sys.sql_modules mo
      inner join .sys.objects ob
       on ob.object_id = mo.object_id
     where mo.definition like '%' + @SearchText + '%'
     order by
       case schema_name(ob.schema_id)
         when 'dbo' then 'A'
         else 'B' + str(ob.schema_id, 10)
       end
      ,ob.type_desc
      ,ob.name
    

    这将搜索存储在 sys.objects 中且在 sys.modules 中有数据/定义的所有文本类型数据库对象。这涵盖了存储过程、函数和视图,还可能涵盖了触发器和一些约束(我不知道其中一种方式)。它不跟踪同义词,它们的定义存储在它们自己的系统表中。

    结果将返回包含指定字符串的所有此类对象的列表。它绝不会尝试评估字符串出现的上下文——如果它是一个表、列、变量或注释,它就是一个命中并被包含在内。这意味着您的里程将根据您搜索的字符串的独特程度而有所不同......但另一方面,您可以查找的不仅仅是包含此列的列。

    返回的列是:

    • 架构名称
    • 名称(对象包含 字符串)
    • type_desc(来自 sys.objects)
    • CodeLength(块 o' 有多大 找到字符串的代码)
    • 定义(所述块的副本 代码。嗯,我从没用过这个,也许我 应该拿出来吗?)

    【讨论】:

    • 我得到“Msg 195, Level 15, State 10, Line 6 'schema_name' 不是可识别的函数名。”
    【解决方案3】:

    这是我发现的: Nir 方法是最好的,因为它可以找到真正的依赖关系(不是通过存储过程的文本),但如果不刷新 sql 模块,它将无法正常工作。 nip和Philip的解决方法是一样的——在存储过程代码中找一个字符串,如果多张表的列名相同,就不能正常工作了。

    所以我决定使用 Nir ​​的解决方案并将我的脚本添加到 usp_FindReferences 中以刷新 sql 模块。 这是我的最终脚本:

    USE [Cetgroups3]
    GO
    /****** Object:  StoredProcedure [dbo].[usp_depends2]    Script Date: 03/16/2011 14:38:36 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE procedure [dbo].[usp_depends2]  --- 1996/08/09 16:51 
      @objname nvarchar(776)  /* the object we want to check */ 
    as 
      declare @objid int   /* the id of the object we want */ 
      declare @found_some bit   /* flag for dependencies found */ 
      declare @dbname sysname  /* **  Make sure the @objname is local to the current database. */   
      DECLARE @sp_depends_xref table (
       reftype char(2), 
    dep_name nvarchar(256), 
       type char(16), 
       updated char(7), 
       selected char(8),
       [column] nvarchar(128))   
      select @dbname = parsename(@objname,3)  
      if @dbname is not null and @dbname <> db_name()  
      begin   
       raiserror(15250,-1,-1)   
       return (1)  
      end  
      /* **  See if @objname exists. */ 
      select @objid = object_id(@objname) 
      if @objid is null  
      begin   
       select @dbname = db_name()   
       raiserror(15009,-1,-1,@objname,@dbname)   
    return (1)  
    end  
      /* **  Initialize @found_some to indicate that we haven't seen any dependencies. */ 
      select @found_some = 0  
      set nocount on  
      /* **  Print out the particulars about the local dependencies. */ 
      if exists (select *   from sysdepends    where id = @objid) 
     begin  
       raiserror(15459,-1,-1)  
       INSERT INTO @sp_depends_xref (refType, dep_name   , type, updated, selected, [column])  
    select   'TO', 'name' = (s6.name+ '.' + o1.name), type = substring(v2.name, 5, 16), 
      updated = substring(u4.name, 1, 7), selected = substring(w5.name, 1,8),
    
    
             'column' = col_name(d3.depid, d3.depnumber)   
    from  sysobjects  o1,
          master.dbo.spt_values v2,
          sysdepends  d3,
          master.dbo.spt_values u4,
          master.dbo.spt_values w5, --11667    
          sysusers  s6   
    where o1.id = d3.depid   
          and  o1.xtype = substring(v2.name,1,2) collate database_default 
          and v2.type = 'O9T'   
          and  u4.type = 'B' 
          and u4.number = d3.resultobj   
          and  w5.type = 'B' 
          and w5.number = d3.readobj|d3.selall   
          and  d3.id = @objid   
          and  o1.uid = s6.uid   
          and deptype < 2   
    
    select @found_some = 1 
    

    结束
    /* ** 现在检查依赖于对象的东西。 */ 如果存在(select * from sysdepends where depid = @objid) 开始
    raiserror(15460,-1,-1)
    插入@sp_depends_xref(RefType、dep_name、类型)
    选择不同的 'BY', 'name' = (s.name + '.' + o.name), type = substring(v.name, 5, 16)
    从 sysobjects o, master.dbo.spt_values v, 系统依赖 d,
    系统用户 s
    其中 o.id = d.id
    和 o.xtype = substring(v.name,1,2) collat​​e database_default 和 v.type = 'O9T'
    和 d.depid = @objid
    和 o.uid = s.uid
    和 deptype 选择@found_some = 1 结束
    /* ** 我们在 sysdepends 中找到什么了吗? */ 如果@found_some = 0
    raiserror(15461,-1,-1)

    SELECT reftype, dep_name, type, updated, selected, [column]
    来自@sp_depends_xref

    关闭无计数
    return (0) -- sp_depends

    /** 对象:StoredProcedure [dbo].[usp_FindReferences] 脚本日期:11/18/2009 11:55:05 **/ 设置 ANSI_NULLS ON 去
    设置 QUOTED_IDENTIFIER ON 去
    创建过程 [dbo].[usp_FindReferences]
    -- 在此处添加存储过程的参数
    @tablename nvarchar(500) = 0,
    @colname nvarchar(500) = 0 作为 开始
    -- 添加了 SET NOCOUNT ON 以防止额外的结果集 -- 干扰 SELECT 语句。
    设置编号;
    -- 开始之前--刷新sql模块 将@sql 声明为 nvarchar(max); 设置@sql = ''; 选择@sql = @sql + N'开始尝试 exec sp_refreshsqlmodule @name = ''' + CAST(name as nvarchar(4000)) + N'''; 结束尝试 开始抓 print ''刷新失败' + CAST(name as nvarchar(4000)) + N': '' + ERROR_MESSAGE(); 如果 XACT_STATE() = -1 回滚; 结束捕获; ' from sys.sysobjects where type in ('P', 'V', 'TF', 'FN');-- 按名称排序; 执行 sp_executesql @sql; -- 现在我们可以继续处理新数据 创建表 #tempTableDependencies (
    引用类型 nvarchar(20),
    dep_name nvarchar(500),
    键入 nvarchar(500),
    更新了 nvarchar(500),
    已选择 nvarchar(500),
    col nvarchar(500))

    插入 #tempTableDependencies 执行 usp_depends2 @tablename

    创建表 #tempDependencies (
    引用类型 nvarchar(20),
    dep_name nvarchar(500),
    键入 nvarchar(500),
    更新了 nvarchar(500),
    已选择 nvarchar(500),
    col nvarchar(500))

    声明@tempFilteredDependencies 表(
    对象名 nvarchar(500),
    引用类型 nvarchar(20),
    dep_name nvarchar(500),
    键入 nvarchar(500),
    更新了 nvarchar(500),
    已选择 nvarchar(500),
    col nvarchar(500))

    声明@loopcounter INT
    选择 @loopcounter = COUNT(*) FROM #tempTableDependencies
    声明 @dependencyname nvarchar(500)
    WHILE @loopcounter > 0
    开始
    SELECT TOP 1 @dependencyname = dep_name FROM #tempTableDependencies
    print 'loop_counter = ' + CAST(@loopcounter as nvarchar(20))
    打印'依赖='+@dependencyname
    插入 #tempDependencies 执行 usp_depends2 @dependencyname

    insert into @tempFilteredDependencies 
    select @dependencyname as objectname, * 
    from #tempDependencies 
    where col = @colname 
          and dep_name like '%' + @tablename   
    
    delete from #tempDependencies   
    delete from #tempTableDependencies 
    where dep_name = @dependencyname    
    
    SET @loopcounter = @loopcounter - 1  
    

    结束

    select * from @tempFilteredDependencies 按对象名排序 删除表 #tempDependencies
    删除表 #tempTableDependencies
    结束
    去吧

    【讨论】:

      【解决方案4】:

      类似的东西应该可以解决问题

      SELECT so.name 
          FROM sys.sysobjects so
          JOIN sys.syscomments sc ON so.id = sc.id 
          WHERE sc.text LIKE '%ColumnName%'
          AND so.type = 'P'
      

      【讨论】:

      • 如果过程冗长,这将不起作用。列名可以拆分为多个 syscmets 记录。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-01
      相关资源
      最近更新 更多