Published on

September 20, 2024

Понимание зависимостей синонимов в SQL Server

При работе с SQL Server важно понимать зависимости между объектами в вашей базе данных. В предыдущем совете мы обсудили, как найти зависимости объектов с помощью скриптов. Однако, эти скрипты не включали проверку зависимостей синонимов. В этом совете мы предоставим скрипты для поиска конкретных синонимов и их зависимостей, особенно в случае работы с несколькими базами данных.

Поиск синонимов с вложенными представлениями в одной базе данных

В большинстве случаев у вас будут синонимы в одной базе данных. Следующий скрипт можно использовать для поиска синонимов с вложенными представлениями в одной базе данных:

DECLARE @schema SYSNAME

-- найти схему пользователя по умолчанию для объектов с одной частью имени (без имени схемы)
SELECT @schema = default_schema_name FROM sys.database_principals WHERE [name] = user_name();

-- найти все представления с их зависимостями
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
  -- закомментируйте следующую строку, если вам нужно проверить все типы объектов, а не только представления 
 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
)
,
-- найти все синонимы в ТЕКУЩЕЙ базе данных
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]
-- закомментируйте следующую строку, если вы хотите видеть все зависимые объекты синонимов независимо от уровня вложенности
HAVING MAX(NestLevel) > 2 
ORDER BY MAX(NestLevel) DESC;

Результат этого скрипта покажет синонимы, связанные с вложенными представлениями в одной базе данных.

Поиск синонимов для вложенных объектов в разных базах данных

Если вам нужно найти синонимы для вложенных объектов в другой базе данных, вы можете использовать следующий запрос:

SET NOCOUNT ON;

-- проверить, есть ли в базе данных синонимы для объектов в другой базе данных
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  

 -- получить список синонимов для объектов в другой базе данных
 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
-- закомментируйте следующую строку, если вы хотите видеть все зависимые объекты синонимов независимо от уровня вложенности
HAVING MAX(nest_level) > 2; 

DROP TABLE
Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.