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

The honest checklist

SourceFindsMisses
sys.sql_expression_dependenciesViews, procs, functions, triggers that name the objectDynamic SQL; cross-DB unless you read the extra columns
dm_sql_referencing_entitiesLive-resolved referencesErrors out on broken objects; needs VIEW DEFINITION
sys.foreign_keysThe data-integrity graph, both directionsAll code dependencies
sys.triggers + eventsWhat 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