SQL Server 2008中如何查询指定存储过程调用的内部存储过程列表
嘿,在SQL Server 2008里要揪出指定存储过程调用的所有内部存储过程(包括嵌套调用的那些),我给你整理了两个靠谱的方案,都是用系统自带的视图/函数实现的,不用额外工具:
方案1:系统视图 + 递归CTE(支持多层嵌套)
这个方法能遍历所有层级的调用关系,哪怕被调用的存储过程又调用了其他过程,也能一网打尽。关键是用递归CTE来逐层挖掘依赖,还加了循环引用的防护,避免无限递归。
直接用下面的代码,记得替换掉@ProcName和@SchemaName为你实际的存储过程名和架构(比如默认的dbo):
DECLARE @ProcName NVARCHAR(128) = 'YourTargetProcedure'; -- 替换成你的存储过程名 DECLARE @SchemaName NVARCHAR(128) = 'dbo'; -- 替换成对应的架构名 WITH ProcDependencies AS ( -- 第一层:目标存储过程直接调用的存储过程 SELECT referenced_schema_name AS SchemaName, referenced_entity_name AS ProcName, 1 AS Level FROM sys.sql_expression_dependencies sed JOIN sys.sql_modules sm ON sed.referencing_id = sm.object_id JOIN sys.objects o ON sm.object_id = o.object_id WHERE o.name = @ProcName AND o.schema_id = SCHEMA_ID(@SchemaName) AND sed.referenced_entity_name IS NOT NULL AND sed.referenced_class_desc = 'OBJECT' -- 只筛选存储过程类型的依赖 AND OBJECTPROPERTY(OBJECT_ID(sed.referenced_schema_name + '.' + sed.referenced_entity_name), 'IsProcedure') = 1 UNION ALL -- 递归层:被调用的存储过程再调用的其他存储过程 SELECT sed.referenced_schema_name AS SchemaName, sed.referenced_entity_name AS ProcName, pd.Level + 1 AS Level FROM sys.sql_expression_dependencies sed JOIN ProcDependencies pd ON sed.referencing_id = OBJECT_ID(pd.SchemaName + '.' + pd.ProcName) WHERE sed.referenced_entity_name IS NOT NULL AND sed.referenced_class_desc = 'OBJECT' AND OBJECTPROPERTY(OBJECT_ID(sed.referenced_schema_name + '.' + sed.referenced_entity_name), 'IsProcedure') = 1 -- 防止循环引用导致无限递归(比如ProcA调用ProcB,ProcB又调用ProcA) AND NOT EXISTS ( SELECT 1 FROM ProcDependencies pd2 WHERE pd2.SchemaName = sed.referenced_schema_name AND pd2.ProcName = sed.referenced_entity_name ) ) -- 去重后输出,按层级排序 SELECT DISTINCT SchemaName, ProcName, Level FROM ProcDependencies ORDER BY Level, SchemaName, ProcName;
方案2:用sys.dm_sql_referenced_entities函数
这个系统函数专门用来返回指定对象引用的所有实体,用法更简洁。同样结合递归CTE处理嵌套调用:
DECLARE @ProcFullName NVARCHAR(256) = 'dbo.YourTargetProcedure'; -- 替换成你的存储过程全名(架构+名称) WITH RecursiveReferences AS ( -- 初始层:直接调用的存储过程 SELECT referenced_schema_name AS SchemaName, referenced_entity_name AS ProcName, 1 AS Level FROM sys.dm_sql_referenced_entities(@ProcFullName, 'OBJECT') WHERE referenced_class_desc = 'OBJECT' AND OBJECTPROPERTY(OBJECT_ID(referenced_schema_name + '.' + referenced_entity_name), 'IsProcedure') = 1 UNION ALL -- 递归层:嵌套调用的存储过程 SELECT r.referenced_schema_name AS SchemaName, r.referenced_entity_name AS ProcName, rr.Level + 1 AS Level FROM sys.dm_sql_referenced_entities(rr.SchemaName + '.' + rr.ProcName, 'OBJECT') r JOIN RecursiveReferences rr ON 1=1 WHERE r.referenced_class_desc = 'OBJECT' AND OBJECTPROPERTY(OBJECT_ID(r.referenced_schema_name + '.' + r.referenced_entity_name), 'IsProcedure') = 1 AND NOT EXISTS ( SELECT 1 FROM RecursiveReferences rr2 WHERE rr2.SchemaName = r.referenced_schema_name AND rr2.ProcName = r.referenced_entity_name ) ) SELECT DISTINCT SchemaName, ProcName, Level FROM RecursiveReferences ORDER BY Level, SchemaName, ProcName;
一些重要提醒
- 权限:你需要有
VIEW DEFINITION权限才能访问这些系统视图和函数,不然会报错。 - 动态SQL限制:如果存储过程里用了动态SQL调用其他过程(比如
EXEC('dbo.ProcA')),这两种方法都抓不到——因为动态SQL的依赖是运行时才确定的,静态分析没法识别。这种情况得自己解析存储过程的定义文本做字符串匹配,但准确性会打折扣。 - 循环引用:代码里已经加了判断来避免无限递归,如果你的环境里有互相调用的存储过程,不用担心会卡死。
内容的提问来源于stack exchange,提问作者CSK




