Home · Blog · Finding table dependencies
How to Find Every Dependency of a SQL Server Table (Before You Change It)
July 2026 · 8 min read
"Is it safe to drop this table?" is one of those questions that sounds simple and isn't. SQL Server does track dependencies — but the information is spread across four different catalog sources, each with its own blind spots. Right-clicking a table in SSMS and choosing View Dependencies shows you a slice of one of them.
This is the working checklist: the queries that together get you close to the truth, what each one catches, and — just as important — what none of them can see.
1. sys.sql_expression_dependencies — the workhorse
Every dependency SQL Server recorded when it parsed a view, procedure, function, or trigger
lands in sys.sql_expression_dependencies. To find everything that references
your table by name:
SELECT
referencing_object = OBJECT_SCHEMA_NAME(d.referencing_id) + '.'
+ OBJECT_NAME(d.referencing_id),
referencing_type = o.type_desc
FROM sys.sql_expression_dependencies AS d
JOIN sys.objects AS o
ON o.object_id = d.referencing_id
WHERE d.referenced_schema_name = 'dbo'
AND d.referenced_entity_name = 'Orders';
What it catches: views that select from the table, procedures and functions that read or write it, triggers that touch it — anything whose definition names the table.
What it misses: references built with dynamic SQL (a proc that assembles
'SELECT … FROM ' + @table records nothing), and anything living outside this
database — more on both below.
2. The DMVs — sys.dm_sql_referencing_entities
The dynamic management functions resolve dependencies at call time rather than reading stored metadata:
SELECT referencing_schema_name, referencing_entity_name
FROM sys.dm_sql_referencing_entities('dbo.Orders', 'OBJECT');
Because resolution happens live, the results are more precise about column-level bindings —
but there are two operational catches. You need VIEW DEFINITION permission on the
referencing objects, and the function throws an error if any object in the chain no longer
compiles (a view pointing at a dropped column, say). On an old database, that error often
arrives before your answer does. The mirror function,
sys.dm_sql_referenced_entities, walks the other direction: everything a given object
depends on.
3. Foreign keys — a second, separate graph
Here's the thing the one-query answers all miss: code dependencies and data dependencies are different graphs. A table can appear in zero view definitions and still be load-bearing, because six other tables point foreign keys at it. Deleting rows — or the table — breaks referential integrity, not code.
-- Who points AT my table (they depend on it)
SELECT fk.name,
parent_table = OBJECT_SCHEMA_NAME(fk.parent_object_id) + '.'
+ OBJECT_NAME(fk.parent_object_id)
FROM sys.foreign_keys AS fk
WHERE fk.referenced_object_id = OBJECT_ID('dbo.Orders');
-- Who my table points at (it depends on them)
SELECT fk.name,
referenced_table = OBJECT_SCHEMA_NAME(fk.referenced_object_id) + '.'
+ OBJECT_NAME(fk.referenced_object_id)
FROM sys.foreign_keys AS fk
WHERE fk.parent_object_id = OBJECT_ID('dbo.Orders');
A real impact analysis merges both graphs. Most homegrown scripts query one and forget the other.
4. Triggers — the dependencies that fire on their own
Triggers show up in sys.sql_expression_dependencies like any other module, but
knowing that a trigger exists isn't enough — you usually need to know when it
fires before you touch the table:
SELECT t.name,
timing = CASE WHEN t.is_instead_of_trigger = 1
THEN 'INSTEAD OF' ELSE 'AFTER' END,
te.type_desc
FROM sys.triggers AS t
JOIN sys.trigger_events AS te ON te.object_id = t.object_id
WHERE t.parent_id = OBJECT_ID('dbo.Orders');
5. What about sp_depends?
If a script you inherited uses sp_depends: retire it. It has been deprecated for
years, and its underlying tracking predates late binding — objects created in the "wrong" order
silently vanish from its answers. Everything it did, the sources above do correctly.
The blind spots nobody's query catches
- Cross-database and linked-server references.
sys.sql_expression_dependenciesexposesreferenced_database_nameandreferenced_server_name— but almost every script on the internet ignores those columns, so the dependency that crosses into another database is silently dropped from the result. It's precisely the edge most likely to page someone at 2 AM. - Dynamic SQL. Nothing assembled at runtime is in the catalog. Only a text
search of module definitions (
sys.sql_modules) even hints at it. - Everything outside the database. ETL jobs, reports, Power BI datasets, Power Automate flows, application code — the catalog cannot testify about readers it has never met. Treat "no dependencies found" as "no dependencies found in this database."
- Depth. All the queries above are one hop. The view that reads your table is itself read by a proc, which feeds a report. Walking that chain needs a recursive query with a depth bound — and the result set grows fast around hub objects.
The honest checklist
| Source | Finds | Misses |
|---|---|---|
sys.sql_expression_dependencies | Views, procs, functions, triggers that name the object | Dynamic SQL; cross-DB unless you read the extra columns |
dm_sql_referencing_entities | Live-resolved references | Errors out on broken objects; needs VIEW DEFINITION |
sys.foreign_keys | The data-integrity graph, both directions | All code dependencies |
sys.triggers + events | What fires, and when | — |
If you do this more than once a month
Running four queries, merging two graphs, remembering the cross-database columns, and walking the chain more than one hop — every time someone asks "what breaks?" — is exactly the kind of ritual that deserves a tool.
That's what Skupa is. It connects to Azure SQL or Synapse strictly read-only (constant catalog SELECTs — you can inspect every query), lists every object instantly, and then traces any object's full dependency neighborhood — code references and foreign keys, upstream and downstream, hop by hop — as a swimlane diagram. Cross-database edges show up as explicit boundary markers instead of silently disappearing, and the whole map exports to Word, PDF, Markdown, or JSON for the migration doc.
Try it free for 14 days — every feature, no account, nothing leaves your machine.
Questions or corrections? sales@skupa.io