Generar script para automatizar el cambio de nombre de las restricciones predeterminadas

8

Antecedentes: algunas de nuestras restricciones de columna predeterminadas se generaron sin nombres explícitos, por lo que obtenemos nombres divertidos que varían de un servidor a otro como: DF__User__TimeZoneIn__5C4D869D

Preferiría que todos sean manejables con un nombre consistente como DF_Users_TimeZoneInfopara que podamos asegurarnos de que existan las restricciones apropiadas en las tablas de destino futuras (como en la comparación de RedGate, o incluso solo visualmente)

Tengo un script que funciona principalmente para lo que quiero:

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

Pero esto solo me da un conjunto de resultados, y no algo que realmente pueda pasar a un ejecutivo o lo que sea.

¿Cómo puedo hacer esto para poder ejecutar esos sp_renamescripts sin tener que recurrir a copiar todos los elementos devueltos y pegarlos en una nueva ventana de consulta y ejecutarlos nuevamente? Intento guardar tantas pulsaciones de teclas como sea posible para poder corregir esto en muchos entornos.

ingrese la descripción de la imagen aquí

jcolebrand
fuente
<facepalm> Deberías haberme preguntado sobre esto el otro día: saqué mi respuesta del guión que tengo que hace exactamente esto. :)
Jon Seigel
@ JonSeigel ok, ¿qué tal un nivel de indrección alrededor de esto para ejecutarse una vez en cada uno de varios dbs? : D
jcolebrand
No ponga corchetes alrededor del nuevo nombre - Terminé con un mundo de dolor después de ejecutar este script :)
samjudson

Respuestas:

16

Ok, un par de cosas

  1. siempre se usa EXECal ejecutar procedimientos almacenados; la taquigrafía sin EXECsolo funciona cuando es la primera instrucción del lote (y ese no será el caso aquí).
  2. siempre use terminadores de punto y coma ; en este caso, son útiles en lugar de retornos de carro bonitos y sangría, pero siempre es aconsejable tenerlos.
  3. siempre use en QUOTENAME()lugar de aplicar corchetes manualmente usted mismo. En este caso, probablemente esté a salvo, pero hay casos en los que el enfoque manual se romperá.
  4. puede probar la PRINTsalida, pero no necesariamente estará completa si su comando total es> 8k (consulte este consejo para conocer algunos enfoques alternativos ).

    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
fuente
Es bueno saber sobre el EXEC para cada declaración, no sabía sobre eso.
jcolebrand
3
Sí tratar de ejecutar esta: sp_help; sp_help;.
Aaron Bertrand
3

Según su pregunta ... que ha eliminado "automatice el mismo script en algunas de las bases de datos de la instancia"

A continuación se muestra el código que lo ayudará.

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
fuente
Lo eliminé porque a la pregunta anterior le faltaba un poco de detalle clave, ya que los nombres de las columnas cambian en cada base de datos, por lo que necesito ejecutar la consulta interna por contexto de la base de datos individual.
jcolebrand
@jcolebrand gracias por la actualización. En cualquier caso, el código con mis cambios te ayudará con lo que estás buscando.
Kin Shah