【SQL Server】递归CTE查询view/sp/fun中使用的所有表,
在SQL编码中,很多编程人员常会使用嵌套view或者存储过程(sproc)完成代码,虽然出于性能和可维护性的考虑并不推荐使用多层嵌套,但现实中仍然是较为常见的编码习惯(方便呗~~)。那么针对多层嵌套的情况需要找出所有用户自定义表(或其它类型对象)往往就显得不是那么的容易了,当然可以通过一层一层统计获得,那么有没有精确并快速的方法找出所有的表呢。
首先,得从系统表sys.sql_expression_dependencies说起,该系统表主要用于查询SQL Server对象间的依赖关系,例如,在视图定义中引用表时,作为引用实体的视图将依赖于表这个被引用的实体,用户定义实体的每个按名称依赖项在此表中均占一行。
以下SQL 用于查询所有给定对象依赖的所有对象。如给定的对象为视图,则返回当前视图所有依赖的对象(table,view,fun,etc),因此可以查询出视图中所用的实体对象。
SELECT OBJECT_NAME(referencing_id) AS referencing_entity_name,
o.type_desc AS referencing_desciption,
COALESCE(COL_NAME(referencing_id, referencing_minor_id), '(n/a)') AS referencing_minor_id,
referencing_class_desc,
referenced_entity_name,
o2.type_desc AS referenced_desciption,
referenced_server_name,
referenced_database_name,
referenced_schema_name,
COALESCE(COL_NAME(referenced_id, referenced_minor_id), '(n/a)') AS referenced_column_name,
o.type AS referencing_type,
is_caller_dependent,
is_ambiguous
FROM sys.sql_expression_dependencies AS sed
JOIN sys.objects AS o ON sed.referencing_id = o.object_id
JOIN sys.objects AS o2 ON sed.referenced_entity_name = o2.name
WHERE referencing_id = OBJECT_ID(N'Object_Name')
查询所有依赖于给定对象的所有实体对象,如给定一个表,将会返回所有使用该表的view,sp,fun等
SELECT OBJECT_SCHEMA_NAME ( referencing_id ) AS referencing_schema_name,
OBJECT_NAME(referencing_id) AS referencing_entity_name,
o.type_desc AS referencing_desciption,
COALESCE(COL_NAME(referencing_id, referencing_minor_id), '(n/a)') AS referencing_minor_id,
referencing_class_desc,
referenced_entity_name,
referenced_class_desc,
referenced_server_name,
referenced_database_name,
referenced_schema_name,
COALESCE(COL_NAME(referenced_id, referenced_minor_id), '(n/a)') AS referenced_column_name,
o.type AS referencing_type,
is_caller_dependent,
is_ambiguous
FROM sys.sql_expression_dependencies AS sed
JOIN sys.objects AS o
ON sed.referencing_id = o.object_id
WHERE referenced_id = OBJECT_ID(N'Object_Name')
下面的语句将返回所有跨数据库的依赖关系
SELECT OBJECT_NAME (referencing_id) AS referencing_entity_name,
referenced_database_name,
referenced_schema_name,
referenced_entity_name,
referencing_class_desc
FROM sys.sql_expression_dependencies
WHERE referenced_database_name IS NOT NULL;
这里再提一下另外一个系统视图sys.sql_modules,该视图能够实现相同的功能,但是并不要求是实体对象,可以找出所有包含所给关键词的所有对象,甚至关键词出现在注释中也会被查询出来,因此查询返回的结果更多。同样还可以使用sys.syscomments,但不推荐,后续的SQL Server版本可能会删除该视图。
SELECT b.name,
b.type_desc
FROM sys.sql_modules a
JOIN sys.objects b
ON a.object_id = b.object_id
WHERE b.type = 'P'
AND a.definition LIKE '%Object_Name%'
以上的代码只适用于查询当前对象的依赖关系,对于嵌套对象的情况并不支持,例如,查询视图中使用到的所有表,如果视图中还包含其它视图,则返回的对象将包括视图和表,并不会返回内嵌视图中使用的表。针对这样的情况,可以使用以下递归CTE,递归的查找出所有的用户表。设置type可以选择返回的对象,如查询所有的视图等。
WITH RECUR_CTE(referencing_id, referenced_id, referenced_entity_name, referenced_database_name)
AS
(
SELECT referencing_id, referenced_id, referenced_entity_name, referenced_database_name
FROM sys.sql_expression_dependencies AS sed
WHERE sed.referencing_id = OBJECT_ID(N'Object_Name')
UNION ALL
SELECT sed2.referencing_id, sed2.referenced_id, sed2.referenced_entity_name, sed2.referenced_database_name
FROM sys.sql_expression_dependencies AS sed2
INNER JOIN RECUR_CTE rc
ON rc.referenced_id = sed2.referencing_id
)
SELECT DISTINCT
schema_name(o.schema_id) AS schema_name,
o.name AS referencing_entity_name,
o.type_desc AS referencing_object_type,
rc.referenced_entity_name,
o2.type_desc AS referenced_object_type,
ISNULL(rc.referenced_database_name, db_name()) AS referenced_database_name
FROM RECUR_CTE rc
JOIN sys.objects o
ON rc.referencing_id = o.object_id
JOIN sys.objects o2
ON rc.referenced_id = o2.object_id
WHERE o2.type = 'U'
OPTION(MAXRECURSION 10)
该SQL的应用场景,比如系统中某个视图存在性能问题,并且发现很多表的统计信息过旧,为了 找出所有的表并更新统计信息,可以使用上述递归CTE。
SELECT DISTINCT
referenced_database_name,
referenced_schema_name,
referenced_entity_name,
'UPDATE STATISTICS ['+referenced_schema_name+'].'+'['+referenced_entity_name+']' as update_stats_sql
FROM #table_list其中临时表table_list为递归CTE返回的所有用户表。注:需要用户替换以上所有SQL代码中的Object_Name以查询指定的对象依赖