How to find every view, procedure and function that uses a table in SQL Server
You are about to rename a column, change a type, or drop a table, and the question is simple: what else will this break? Foreign keys are one part of the answer. The other part is code: the views, stored procedures, functions and triggers that read the table. SQL Server keeps track of those, up to a point.
The query
sys.sql_expression_dependencies records, for every module, the objects its definition names:
SELECT DISTINCT
OBJECT_SCHEMA_NAME(d.referencing_id) + '.' + OBJECT_NAME(d.referencing_id) AS used_by,
o.type_desc AS kind
FROM sys.sql_expression_dependencies AS d
JOIN sys.objects AS o ON o.object_id = d.referencing_id
WHERE d.referenced_id = OBJECT_ID(N'dbo.Customer')
ORDER BY kind, used_by;
DISTINCT is there because a schema-bound view has one row for the table and another for each
column it uses.
For a quick answer about one object, sys.dm_sql_referencing_entities does the same lookup by
name:
SELECT referencing_schema_name, referencing_entity_name
FROM sys.dm_sql_referencing_entities(N'dbo.Customer', N'OBJECT');
Skip sp_depends. It is deprecated and has missed dependencies for a long time.
Down to the column
If you are changing one column rather than the whole table, ask which modules use that column:
SELECT DISTINCT
OBJECT_SCHEMA_NAME(d.referencing_id) + '.' + OBJECT_NAME(d.referencing_id) AS used_by
FROM sys.sql_expression_dependencies AS d
WHERE d.referenced_id = OBJECT_ID(N'dbo.Customer')
AND d.referenced_minor_id = COLUMNPROPERTY(OBJECT_ID(N'dbo.Customer'), N'Email', 'ColumnId');
This only finds objects created WITH SCHEMABINDING. SQL Server records which columns a module
uses only for schema-bound objects, so an ordinary procedure that reads Email does not appear
here at all. For those, an empty result means nothing. Use the table-level query above and read the
definitions.
What it cannot see
The list is built from the names written in each module's definition when it was created. That leaves gaps worth knowing before you trust an empty result:
- Dynamic SQL. A procedure that builds
'SELECT … FROM ' + @tableand runs it withEXECorsp_executesqlnames no table that SQL Server can see. - Other databases and servers. A three- or four-part name is recorded, but only by name. The other database is not checked, and it cannot report back.
- Code outside the database. Application queries, reports, SSIS packages and scheduled jobs are not modules, so nothing here knows about them.
- Synonyms. A module that reads a synonym depends on the synonym, not on the table behind it.
So the query gives you a floor, not a ceiling. Everything it lists really does use the table. Things it does not list might still.
A quick text search as a second check
For dynamic SQL, a plain search of module definitions catches what the dependency list misses. It also catches comments and unrelated names that happen to match:
SELECT OBJECT_SCHEMA_NAME(m.object_id) + '.' + OBJECT_NAME(m.object_id) AS module
FROM sys.sql_modules AS m
WHERE m.definition LIKE N'%Customer%';
Read each hit rather than trusting the count.
Seeing it as a picture
In WoodFireERD, select the table and set Follow to Referenced by (others → this). The diagram draws the views, procedures and functions that read the table, next to the tables whose foreign keys point at it, and follows that outward as many levels as you choose. It has the same blind spot as SQL Server's own list: a table named only inside dynamic SQL does not appear.