デフォルト制約の名前変更を自動化するスクリプトを生成します


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、返されたすべての要素をコピーして新しいクエリウィンドウに貼り付けて再度実行する必要がなく、スクリプトを実行できますか?多くの環境でこれを修正できるように、できるだけ多くのキーストロークを保存しようとしてます。

ここに画像の説明を入力してください


<facepalm>先日、このことについて質問されたはずです-これを正確に行うスクリプトから私の答えを引き出しました。:)
Jon Seigel 2013年

@JonSeigelわかりました。これを回避するために、いくつかのdbのそれぞれで1回実行する程度のインデククションはどうでしょうか。:D
jcolebrand

新しい名前の前後に角かっこを付けないでください。このスクリプトを実行した後、私は結局傷ついた世界になりました:)
samjudson

回答:


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; 

列名は各dbで変更されるため、前の質問には重要な詳細が欠けていたため、削除しました。個々のdbのコンテキストごとに内部クエリを実行する必要があります。
jcolebrand

@jcolebrand更新に感謝します。いずれにせよ、私の変更を加えたコードは、あなたが探しているものを手助けします。
Kin Shah
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.