Gere script para automatizar a renomeação de restrições padrão

8

Segundo plano: algumas de nossas restrições de coluna padrão foram geradas sem nomes explícitos, por isso, temos nomes divertidos que variam de servidor para servidor, como: DF__User__TimeZoneIn__5C4D869D

Eu preferiria que todos fossem gerenciáveis ​​com nomes consistentes, DF_Users_TimeZoneInfopara que possamos garantir a existência de restrições apropriadas em futuras tabelas de destino (como na comparação do RedGate ou apenas visualmente)

Eu tenho um script que funciona principalmente para o que eu quero:

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[_][_]%'

Mas isso me dá um conjunto de resultados, e não algo que eu possa realmente passar para um executivo ou algo assim.

Como fazer isso para que eu possa executar esses sp_renamescripts sem ter que recorrer a todos os elementos retornados e colá-los em uma nova janela de consulta e executá-los novamente? Tentando salvar o maior número possível de pressionamentos de tecla, para que eu possa corrigir isso em muitos ambientes.

insira a descrição da imagem aqui

jcolebrand
fonte
<facepalm> Você deveria ter me perguntado sobre isso outro dia - tirei minha resposta do script que tenho que faz exatamente isso. :)
Jon Seigel
@ JonSeigel ok, que tal um nível de indreção em torno disso para executar uma vez em cada um dos vários dbs? : D
jcolebrand
Não coloque colchetes em torno do novo nome - eu acabei com um mundo de dor depois de executar este script :)
samjudson

Respostas:

16

Ok, algumas coisas.

  1. sempre use EXECao executar procedimentos armazenados; a abreviação sem EXECfunciona apenas quando é a primeira instrução do lote (e não será o caso aqui).
  2. sempre use terminadores de ponto-e-vírgula - nesse caso, são úteis em vez de retornos de carro e recuo bonitos, mas é sempre bom ter.
  3. use sempre em QUOTENAME()vez de aplicar manualmente colchetes. Nesse caso, você provavelmente está seguro, mas há casos em que a abordagem manual será interrompida.
  4. você pode testar a PRINTsaída, mas ela não estará necessariamente completa se o seu comando total for> 8k (veja esta dica para algumas abordagens alternativas ).

    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;
Aaron Bertrand
fonte
É bom saber sobre o EXEC de cada declaração, eu não sabia disso.
jcolebrand
3
Sim tentar executar este: sp_help; sp_help;.
Aaron Bertrand
3

Com base na sua pergunta .. que você removeu "automatize o mesmo script em alguns bancos de dados da instância"

Abaixo está o código que o ajudará

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; 
Kin Shah
fonte
Eu o removi porque a pergunta anterior estava sem um detalhe importante, pois os nomes das colunas são alterados em cada banco de dados; portanto, preciso executar a consulta interna por contexto do banco de dados individual.
jcolebrand
@jcolebrand obrigado pela atualização. De qualquer forma, o código com minhas alterações ajudará você no que você está procurando.
precisa