The danger: SQL Server uses late binding — views, functions, and procedures that reference a column by name continue to compile after the column is renamed. The failure is silent at rename time and surfaces only when the code path is executed.
Why sp_rename doesn't protect you
EXEC sp_rename 'dbo.Orders.OrderDate', 'order_date', 'COLUMN'; renames the column in the table definition and records the new name in the schema. It does not update any stored procedure, view, function, trigger, or computed column that references the old name. SQL Server's parser doesn't revalidate those objects at rename time — it resolves column names when the object is executed, not when it's compiled or when the schema changes underneath it.
The result: renaming a column silently invalidates every object that referenced the old name, and those objects will error at runtime — potentially in production, potentially days later when a code path that's only hit once a month runs for the first time after the rename.
Step 1: Find every object that references the table
Start broad. sys.sql_expression_dependencies tracks object-to-object references — every stored procedure, view, function, and trigger that names your table will appear here. Column-level tracking in this view is partial (it records some column references but not all), so the safest first step is a table-level blast radius:
SELECT
d.referencing_entity_name,
OBJECT_SCHEMA_NAME(d.referencing_id) AS referencing_schema,
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_entity_name = 'Orders'
AND (d.referenced_schema_name = 'dbo' OR d.referenced_schema_name IS NULL)
ORDER BY o.type_desc, d.referencing_entity_name;
This is your candidate list — every object that touches the table and therefore might reference the column you're about to rename.
Step 2: Get column-level resolution via the DMF
sys.dm_sql_referenced_entities resolves dependencies at call time and returns column-level binding detail via referenced_minor_name. Run it against each object from step 1 that could reference the column:
SELECT
referenced_entity_name,
referenced_minor_name AS referenced_column,
is_selected,
is_updated,
is_select_all
FROM sys.dm_sql_referenced_entities('dbo.MonthlySalesSummary', 'OBJECT')
WHERE referenced_entity_name = 'Orders'
AND referenced_minor_name = 'OrderDate'; -- the column you're renaming
If this returns rows, the object directly references the column by name and will break after the rename. Run this for each high-risk object — particularly views and functions that are themselves called by many other objects.
One operational caveat: sys.dm_sql_referenced_entities throws an error if the object doesn't compile cleanly. On databases with existing broken references, it may error before returning results. If that happens, fall back to step 3.
Step 3: Text search the module definitions
As a belt-and-suspenders check — and to catch dynamic SQL and any references the catalog view couldn't resolve — search the definition text of every SQL module in the database:
SELECT
o.name,
o.type_desc,
m.definition
FROM sys.sql_modules AS m
JOIN sys.objects AS o ON o.object_id = m.object_id
WHERE m.definition LIKE '%OrderDate%'
ORDER BY o.type_desc, o.name;
Scan the definition column in the results. Most matches will be legitimate references to the column name. Watch for:
- Dynamic SQL strings that assemble queries with the column name concatenated or passed as a parameter
- Column aliases that shadow the original name (e.g.,
OrderDate AS order_date— these won't break, but confirm the intent) - Computed column definitions referencing the column
Don't forget: computed columns, indexes, and statistics
Three more places the old column name can live that aren't covered by the queries above:
- Computed columns — a column defined as
AS (OrderDate + 30)references the column by name in its expression. Checksys.computed_columns. - Column-level check constraints and default constraints — less common but worth checking in
sys.check_constraintsfiltered to the table. - Statistics —
sp_renamedoes not update statistics names, though SQL Server doesn't use column names in statistics resolution the same way. Worth noting for documentation purposes.
-- Computed columns referencing the column
SELECT cc.name AS computed_column, cc.definition
FROM sys.computed_columns AS cc
WHERE cc.object_id = OBJECT_ID('dbo.Orders')
AND cc.definition LIKE '%OrderDate%';
After you have the list
Once you know every object that references the column, the rename itself becomes a three-step operation:
- Run
sp_renameon the column - Run
ALTER VIEW/ALTER PROCEDURE/ALTER FUNCTIONon each affected object to update the column name in its definition - Recompile and test each updated object in a non-production environment before applying to production
Doing step 2 before you have a complete list from steps 1–3 above is how you end up with partial fixes and a production incident on a code path you didn't know referenced the old name.
See the full object call graph before any schema change. Skupa maps sys.sql_expression_dependencies as an interactive diagram — click any object to see every caller upstream and every dependency downstream. Free 14-day trial.