最可靠方法是查询 sys.sql_modules 的 definition 字段,用 like 匹配带方括号的表名或列名(如 '%[orders]%'),并筛选 type = 'p' 且 is_ms_shipped = 0 的用户存储过程,避免动态 sql 和注释干扰。

直接查 sys.sql_modules 最可靠,别信 SSMS 的“查找所有引用”——它不扫描动态 SQL、字符串拼接或注释里的表名。
查存储过程中是否引用了某个表名
SQL Server 不会把表依赖关系自动维护在 sys.dm_exec_describe_first_result_set 或 sys.sql_expression_dependencies 里(尤其对动态 SQL),所以得翻源码文本。核心是查 sys.sql_modules 的 definition 字段:
- 用
LIKE模糊匹配时,加空格或括号边界更安全,比如查表Orders,写成'%[Orders]%' OR '% Orders %' OR '%.Orders.%',避免误中OrderStatus - 注意大小写:如果数据库是区分大小写的(
COLLATE设置为_CS_),LIKE也区分;建议统一用LOWER(definition)转小写再查 - 排除系统对象:加上
AND o.type = 'P'(P表示存储过程)和AND o.is_ms_shipped = 0
SELECT DISTINCT o.name AS procedure_name, o.create_date, o.modify_date FROM sys.sql_modules m INNER JOIN sys.objects o ON m.object_id = o.object_id WHERE m.definition LIKE '%[Orders]%' AND o.type = 'P' AND o.is_ms_shipped = 0;
查存储过程中是否硬编码了某个列名
列名比表名更容易误匹配(比如 ID 出现在注释、变量名、字符串里),所以得更谨慎:
- 优先查带方括号的写法:
'%[CustomerID]%',因为 T-SQL 中规范列引用都带[] - 避免只查裸名
'CustomerID',否则会命中@CustomerID参数、CustomerID_New列、甚至注释里的-- CustomerID is required - 如果列名较短(如
ID),可组合上下文,例如查'SELECT.*[ID]'或'UPDATE.*SET.*[ID]'(用.*模拟任意字符)
SELECT o.name, m.definition FROM sys.sql_modules m JOIN sys.objects o ON m.object_id = o.object_id WHERE m.definition LIKE '%[ShipDate]%' AND o.type = 'P' AND o.is_ms_shipped = 0;
为什么 COL_LENGTH 和 sys.columns 查不到存储过程里的列?
这两个东西只管「物理表结构」,不管「代码里写了什么」:
-
COL_LENGTH('Orders', 'ShipDate')只返回表Orders是否真有这列,跟存储过程内容完全无关 -
sys.columns是描述表/视图字段的元数据,不是代码文本索引器 - 想确认某列是否被某个存储过程“用到”,唯一办法就是搜它的定义文本——没有捷径
真正容易被忽略的是动态 SQL:如果存储过程里有 EXEC('SELECT * FROM '+@table_name),那无论你搜多少遍 sys.sql_modules 都找不到具体表名。这种只能靠人工审阅逻辑或运行时抓取实际执行的语句(比如用 sp_whoisactive 或 Extended Events)。











