Problem
In a previous tip we shared scripts that could be useful for finding SQL Server object dependencies during your application development or database upgrades. The scripts did not include checks for synonyms dependencies, so how can we check SQL Server synonym dependencies especially for cross database situations?
Solution
In this tip we will provide scripts to find specific synonyms and their dependencies. We are looking for the synonyms that have dependent (base) objects with high nest level (3 or more in our examples). We will find synonyms in our database that were created for the views in the same or in another database.
SQL Server Synonyms for nested views in the same database
In most cases you will have synonyms in the same database. The following script finds synonyms with nested views in the same database where the synonym has been created:
DECLARE @schema SYSNAME
-- find default user's schema for the one-part base objects names (no schema name)
SELECT @schema = default_schema_name FROM sys.database_principals WHERE [name] = user_name();
-- find all views with their dependencies
WITH DepTree
AS
(
SELECT o.[name],
s.[name] AS oSchema,
o.[object_id] AS referenced_id ,
o.[name] AS referenced_name,
o.[object_id] AS referencing_id,
o.[name] AS referencing_name,
0 AS NestLevel
FROM sys.objects o JOIN sys.schemas s
ON o.[schema_id] = s.[schema_id]
WHERE o.is_ms_shipped = 0
-- comment out next line if you need to check all object types, not only views
AND o.[type] = 'V'
UNION ALL
SELECT r.[name],
r.oSchema,
d1.referenced_id,
OBJECT_NAME( d1.referenced_id) ,
d1.referencing_id,
OBJECT_NAME( d1.referencing_id) ,
NestLevel + 1
FROM sys.sql_expression_dependencies d1 JOIN DepTree r
ON d1.referenced_id = r.referencing_id
)
,
-- find all synonyms in CURRENT database
Syn
AS
(
SELECT [name],
base_object_name,
LTRIM(RTRIM( REPLACE(REPLACE(REPLACE(REPLACE(base_object_name ,'[',''),']',''), DB_NAME()+'..',''), DB_NAME()+'.',''))) as objectname
FROM sys.synonyms s
WHERE (base_object_name like '%.%.%'
AND LEFT (REPLACE(REPLACE(base_object_name ,'[',''),']',''),
CHARINDEX('.', REPLACE(REPLACE(base_object_name ,'[',''),']',''))-1) = DB_NAME())
OR base_object_name NOT LIKE '%.%.%'
)
SELECT s.[name] AS syn_name,
base_object_name AS syn_base_object,
MAX(NestLevel) AS nest_level
FROM DepTree t JOIN Syn s
ON oSchema + '.' + t.referencing_name =
CASE WHEN s.objectname NOT LIKE '%.%' THEN @schema + '.' + s.objectname
ELSE s.objectname END
GROUP BY base_object_name, s.[name]
-- comment out next line if you want to see all synonyms' dependent objects regardless nest level
HAVING MAX(NestLevel) > 2
ORDER BY MAX(NestLevel) DESC;
GO
The result shows synonyms to the nested views. Note that the synonyms in this example were created inconsistently using one-part, two-part and three-part base object names:

SQL Server Synonyms for nested objects in the different databases
This query will find synonyms for nested objects in another database:
SET NOCOUNT ON;
-- check if a database has synonyms to the objects in another database
IF EXISTS (SELECT base_object_name
FROM sys.synonyms
WHERE base_object_name LIKE '%.%.%'
AND LEFT (REPLACE(REPLACE(base_object_name ,'[',''),']',''),
CHARINDEX('.', REPLACE(REPLACE(base_object_name ,'[',''),']',''))-1) <> DB_NAME()
)
BEGIN
DECLARE @sql NVARCHAR(MAX),
@syn_name NVARCHAR(255),
@db NVARCHAR(255),
@dbid NVARCHAR(20),
@objname NVARCHAR(255)
CREATE TABLE #tempTbl ( syn_name NVARCHAR(255),
syn_base_object NVARCHAR(255),
syn_base_object_db NVARCHAR(255),
nest_level SMALLINT
);
DECLARE SYN_DB CURSOR FOR
-- get list of synonyms to the objects in another database
SELECT DISTINCT [name] AS SYN_NAME,
LEFT (REPLACE(REPLACE(base_object_name ,'[',''),']',''),
CHARINDEX('.', REPLACE(REPLACE(base_object_name ,'[',''),']',''))-1) AS DBNM,
DB_ID(LEFT (REPLACE(REPLACE(base_object_name ,'[',''),']',''),
CHARINDEX('.', REPLACE(REPLACE(base_object_name ,'[',''),']',''))-1)) AS DBID,
RIGHT (REPLACE(REPLACE(base_object_name ,'[',''),']',''),
CHARINDEX('.', reverse(REPLACE(REPLACE(base_object_name ,'[',''),']','')))-1) AS objectname
FROM sys.synonyms
WHERE base_object_name LIKE '%.%.%'
AND LEFT (REPLACE(REPLACE(base_object_name ,'[',''),']',''),
CHARINDEX('.', REPLACE(REPLACE(base_object_name ,'[',''),']',''))-1) <> DB_NAME()
OPEN SYN_DB;
FETCH NEXT FROM SYN_DB
INTO @syn_name, @db, @dbid, @objname;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = '
WITH DepTree
AS
(
SELECT ''' + @db + ''' AS DBNAME,
o.[name],
o.[object_id] AS referenced_id ,
o.[name] AS referenced_name,
o.[object_id] AS referencing_id,
o.[name] AS referencing_name,
0 AS NestLevel
FROM [' + @db + '].sys.objects o
WHERE o.is_ms_shipped = 0
UNION ALL
SELECT ''' + @db + ''' AS DBNAME,
r.[name],
d1.referenced_id,
OBJECT_NAME( d1.referenced_id,' + @dbid + ') ,
d1.referencing_id,
OBJECT_NAME( d1.referencing_id,' + @dbid + ') ,
NestLevel + 1
FROM [' + @db + '].sys.sql_expression_dependencies d1 JOIN DepTree r
ON d1.referenced_id = r.referencing_id
)
INSERT INTO #tempTbl
SELECT ''' + @syn_name + ''' AS syn_name,
''' + @objname + ''' AS syn_base_object,
''' + @db + ''' AS syn_base_object_db,
MAX(NestLevel) AS nest_level
FROM DepTree
WHERE referencing_name = ''' + @objname + '''
GROUP BY referenced_name, DBNAME, referencing_name
ORDER BY MAX(NestLevel) DESC'
EXECUTE (@sql);
FETCH NEXT FROM SYN_DB
INTO @syn_name, @db, @dbid, @objname;
END
CLOSE SYN_DB;
DEALLOCATE SYN_DB;
END ;
SELECT syn_name,
syn_base_object,
syn_base_object_db,
MAX(nest_level) AS nest_level
FROM #tempTbl
GROUP BY syn_name, syn_base_object, syn_base_object_db
-- comment out next line if you want to see all synonyms' dependent objects regardless the nest level
HAVING MAX(nest_level) > 2;
DROP TABLE #tempTbl;
GO
Here are the results of the query above:

Comment out the line with the “HAVING” clause if you want to see synonyms and their dependent objects from another databases regardless the nest level.
Please note that we used “EXECUTE (@sql)” in this query. Use this query with dynamic SQL discretionally and make sure you are familiar with SQL Injection concepts.
Final Thoughts
In one of the previous tips we provided a template to use for the synonyms creation and explained why is it better to have three-part base objects names. Base objects can be referenced using one-part, two-part or three-part names (database_name.schema_name.object_name). Using three-part base objects names would make the scripts above much simpler.
We have created queries that handle specific scenarios. They could be used as base queries that you can modify for your needs.
Next Steps
- Find synonyms to the nested views that might affect your database performance.
- Document existing dependencies.
- Read more tips about synonyms.
- Read these tips about Dynamic SQL.
- In this tip, there are several methods to list object dependencies that were used in previous versions of SQL Server.
- Learn more about Dynamic Management Views and Functions and about Catalog Views.
- Stay tuned for the Part 3 Objects Dependencies tip.

Svetlana has been working in IT for more than 17 years. Most of her career has focused on Database Administration (both SQL Server and Oracle) and Database Development. Databases are Svetlana’s passion, but she also has fun helping co-workers and friends in troubleshooting non-database related issues. Svetlana tries to explore and learn as many SQL Server features as possible. Her favorite SQL Server features are Policy Based Management, SSIS, SSRS and Master Data Services. One of Svetlana’s areas of expertize is cross systems / database integration. Svetlana is currently a hands-on Database Team Lead in Calgary, Canada where she promotes SQL Server.
Svetlana likes to share her knowledge with others and enjoys learning herself. Her hobby is photography, but now she spends her free time away from Database Administration with her little girl who proudly wears her MSSQLTips shirt. Svetlana blogs at http://databaserefresh.com and posts her pictures to https://plus.google.com/u/0/111115767149899859037/posts. Her Twitter account is @magasvs.
- MSSQLTips Awards: Rising Star (50+ tips) – 2018 | Author of the Year Contender – 2015-2017
