Articles

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:

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.

An unhandled error has occurred. Reload 🗙