Создать скрипт для автоматизации переименования ограничений по умолчанию

8

Справочная информация: некоторые из наших ограничений на столбцы по умолчанию были созданы без явных имен, поэтому мы получаем забавные имена, которые варьируются от сервера к серверу, например: DF__User__TimeZoneIn__5C4D869D

Я бы предпочел, чтобы все они управлялись с единообразными именами, DF_Users_TimeZoneInfoчтобы мы могли гарантировать наличие соответствующих ограничений для будущих целевых таблиц (как в сравнении RedGate или даже просто визуально).

У меня есть скрипт, который в основном работает для того, что я хочу:

select 'sp_rename N''[' + s.name + '].[' + d.name + ']'', 
   N''[DF_' + t.name + '_' + c.name + ']'', ''OBJECT'';'
from sys.tables t
    join
    sys.default_constraints d
        on d.parent_object_id = t.object_id
    join
    sys.columns c
        on c.object_id = t.object_id
        and c.column_id = d.parent_column_id
    join sys.schemas s
        on t.schema_id = s.schema_id
WHERE d.NAME like 'DF[_][_]%'

Но это просто дает мне набор результатов, а не то, что я могу фактически передать в exec или что-то еще.

Как я могу сделать это, чтобы я мог просто выполнить эти sp_renameсценарии, не прибегая к копированию всех возвращенных элементов и вставке их в новое окно запроса и их повторному запуску? Пытаясь сохранить как можно больше нажатий клавиш, чтобы я мог исправить это во многих средах.

введите описание изображения здесь

Jcolebrand
источник
<facepalm> Ты должен был спросить меня об этом на днях - я взял свой ответ из сценария, который у меня есть, который делает именно это. :)
Джон Зигель
@JonSeigel хорошо, а как насчет того, чтобы обойтись этим, чтобы запустить один раз на каждом из нескольких БД? : D
Jcolebrand
Не ставьте квадратные скобки вокруг нового имени - я
заполнил мир болью

Ответы:

16

Хорошо, пара вещей.

  1. всегда использовать EXECпри выполнении хранимых процедур; сокращение без EXECработает только тогда, когда это первый оператор в пакете (и это не будет иметь место здесь).
  2. всегда используйте терминаторы точки с запятой - в этом случае они полезны вместо красивых возвратов каретки и отступов, но они всегда имеют смысл.
  3. всегда используйте QUOTENAME()вместо того, чтобы вручную применять квадратные скобки. В этом случае вы, вероятно, в безопасности, но есть случаи, когда ручной подход сломается.
  4. вы можете проверить PRINTвывод, но он не обязательно будет полным, если ваша общая команда> 8k (см. этот совет для некоторых альтернативных подходов ).

    DECLARE @sql nvarchar(max) = N'';
    
    SELECT @sql += N'EXEC sys.sp_rename N''' 
        + QUOTENAME(s.name) + '.' + QUOTENAME(d.name) 
        + ''', N''DF_' + t.name + '_' + c.name + ''', ''OBJECT'';'
      FROM sys.tables AS t
      INNER JOIN sys.default_constraints AS d
         ON d.parent_object_id = t.object_id
      INNER JOIN sys.columns AS c
         ON c.object_id = t.object_id
        AND c.column_id = d.parent_column_id
      INNER JOIN sys.schemas AS s
         ON t.schema_id = s.schema_id
      WHERE d.NAME LIKE N'DF[_][_]%';
    
    PRINT @sql;
    -- EXEC sys.sp_executesql @sql;
    
Аарон Бертран
источник
Полезно знать о EXEC для каждого утверждения, я не знал об этом.
Jcolebrand
3
Ага попробуй выполнить это sp_help; sp_help;.
Аарон Бертран
3

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

Ниже приведен код, который поможет вам

set nocount on
DECLARE @table TABLE 
  ( 
     dbname VARCHAR(30) 
  ) 

INSERT INTO @table 
            (dbname) 
VALUES      ( 'dev_construct1' ), 
            ('dev_construct2'), 
            ('dev_construct3' ); 

DECLARE @sql NVARCHAR(max) = N''; 
DECLARE @dbname VARCHAR(30) 

/*  
Added by Kin : While loop and an extra @dbname variable 
*/ 
SELECT @dbname = Min(dbname) 
FROM   @table 

WHILE @dbname IS NOT NULL 
  BEGIN 
      SELECT @sql = N'USE ' + tt.dbname + Char(10) + N' GO;'
      FROM   @table tt 
      WHERE  @dbname = dbname 

      SELECT @sql += Char(10) + N'EXEC sp_rename N''' 
                     + Quotename(s.name) + '.' + Quotename(d.name) 
                     + ''', N''DF_' + t.name + '_' + c.name 
                     + ''', ''OBJECT'';' 
      FROM   sys.tables AS t 
             JOIN sys.default_constraints d 
               ON d.parent_object_id = t.object_id 
             JOIN sys.columns c 
               ON c.object_id = t.object_id 
                  AND c.column_id = d.parent_column_id 
             JOIN sys.schemas s 
               ON t.schema_id = s.schema_id 
             JOIN @table tt 
               ON tt.dbname = tt.dbname 
      WHERE  d.name LIKE 'DF[_][_]%'; 

      PRINT @sql 

      SELECT @dbname = Min(dbname) 
      FROM   @table 
      WHERE  dbname > @dbname 
  END 
-- EXEC sp_executesql @sql; 
Кин Шах
источник
Я удалил его, потому что в предыдущем вопросе отсутствовал ключевой элемент детализации, поскольку имена столбцов меняются в каждой БД, поэтому мне нужно выполнить внутренний запрос для контекста отдельной БД.
Jcolebrand
@jcolebrand спасибо за обновление. В любом случае код с моими изменениями поможет вам в том, что вы ищете.
Кин Шах