SQL Projectsでテーブル名・スキーマ変更時の再作成を防ぐ方法|VS CodeのRefactorとrefactorlog

SQL Database Projects extension for Visual Studio Codeでテーブル名やスキーマを変更するときは、SQLファイルを直接書き換えるのではなく、VS CodeのRename SymbolまたはRefactor > Move to Schemaを使うことが重要です。

これらの操作を使うと、変更内容が.refactorlogに記録されます。デプロイ時には、旧テーブルの削除と新規作成ではなく、sp_renameやALTER SCHEMA ... TRANSFERが生成されるため、既存データのコピーや再投入を避けられます。(Microsoft Developer Blogs)

ただし、データが保持されることと、アプリケーションを無停止で更新できることは別問題です。プロジェクト外のSQL、アプリケーション、ETL、レポートなどの参照は自動更新されないため、生成されたデプロイ計画と外部依存関係を必ず確認する必要があります。

目次

VS CodeのSQL Projectsで再作成を避ける方法

テーブル名やスキーマを変更する際の正しい操作は、次のとおりです。

変更内容VS Codeで使う操作デプロイ時の主な処理データコピー
テーブル名の変更Rename Symbolsp_rename原則不要
列名の変更Rename Symbolsp_rename原則不要
テーブルのスキーマ移動Refactor > Move to SchemaALTER SCHEMA ... TRANSFER原則不要
SQL定義を直接書き換える手動編集旧オブジェクト削除+新規作成と判断される可能性発生する可能性あり

SQL Database Projectsは、プロジェクトに記述された「完成後のデータベース定義」と対象データベースを比較し、必要な変更を動的に計画する宣言型の仕組みです。

そのため、次のようにオブジェクト名だけを書き換えても、ツール側は名前変更だと判断できません。

-- 変更前
CREATE TABLE [SalesLT].[SalesOrderDetail]
(
    [SalesOrderID] INT NOT NULL
);

-- 変更後
CREATE TABLE [SalesLT].[SalesOrderLine]
(
    [SalesOrderID] INT NOT NULL
);

変更意図が記録されていなければ、デプロイ側からは「SalesOrderDetailがなくなり、SalesOrderLineが追加された」ように見えます。その結果、旧テーブルの削除と新規テーブルの作成として処理される可能性があります。

.refactorlogは、この差分が削除と追加ではなく、同じオブジェクトの名前変更やスキーマ移動であることを伝える役割を持ちます。(Microsoft Learn)

refactorlogが名前変更の意図をデプロイへ伝える

.refactorlogは、データベースオブジェクトに対して実施したリファクタリング操作を記録するXMLファイルです。

処理の流れは次のようになります。

  1. VS Codeでテーブル名変更やスキーマ移動を実行する
  2. SQLファイル内の定義と参照が更新される
  3. 操作内容が.refactorlogへ追加される
  4. ビルド時にrefactorlogが.dacpac内のrefactor.xmlへ格納される
  5. デプロイ時に対象データベースの適用状況が確認される
  6. 未適用の場合だけsp_renameやALTER SCHEMA ... TRANSFERが実行される
  7. 操作キーがdbo.__RefactorLogへ記録される

この仕組みにより、開発環境、検証環境、本番環境など、適用状況が異なる複数のデータベースへ同じ.dacpacを展開できます。各データベースでは、操作ごとに一意なキーを使って適用済みかどうかが判断されます。(Microsoft Learn)

refactorlogはソース管理に必ず含める

VS Codeでリファクタリングを実行すると、一般的には次のようなファイルが作成または更新されます。

MyDatabase.refactorlog

このファイルは、通常のSQLファイルや.sqlprojと一緒にGitへコミットしてください。

refactorlogを削除すると、まだ変更が適用されていない環境へデプロイするときに、過去の名前変更を判定できなくなります。その結果、旧オブジェクトの削除と新規作成として処理され、データ損失につながる可能性があります。(Microsoft Learn)

手動でrefactorlogを追加する場合は、.sqlprojにも対象ファイルを登録します。

<ItemGroup>
  <RefactorLog Include="MyDatabase.refactorlog" />
</ItemGroup>

ただし、操作キーにはリファクタリングごとに新しいGUIDが必要です。オブジェクト種別、旧名、操作順序などを誤ると、ビルドやパッケージ化に失敗する可能性があります。通常はXMLを手で作成せず、VS Codeのリファクタリング機能に生成させる方が安全です。(Microsoft Learn)

リファクタリング前に確認すること

本番データベースで作業する前に、次の準備を行います。

  • SQLプロジェクトが現在のデータベース構成を正しく表しているか確認する
  • Schema Compareで意図しない差分がないか確認する
  • リファクタリング専用のブランチを作成する
  • 本番相当のデータを持つ検証環境を用意する
  • アプリケーションとデータベースの更新順序を決める
  • 外部システム、バッチ、レポートからの参照を洗い出す

プロジェクトと対象データベースの間に大きなドリフトがある状態で名前変更を始めると、リファクタリングとは無関係な変更まで同じデプロイ計画へ含まれます。

最初にSchema Compareを実行し、現在の差分を整理してから作業するのが安全です。VS CodeのSchema Compareでは、名前変更やスキーマ移動として認識されたオブジェクトも比較結果上で確認できます。(Microsoft Learn)

Rename Symbolでテーブル名を変更する手順

ここでは、次のテーブル名を変更する例で説明します。

変更前:SalesLT.SalesOrderDetail
変更後:SalesLT.SalesOrderLine

テーブル名変更の操作

  1. VS CodeでSQL Database Projectsのビューを開く
  2. 対象テーブルのSQLファイルを開く
  3. CREATE TABLE内のテーブル名を右クリックする
  4. Rename Symbolを選択する
  5. 新しい名前としてSalesOrderLineを入力する
  6. すぐに適用せず、可能であれば変更プレビューを開く
  7. 更新対象となるビュー、ストアドプロシージャ、関数などを確認する
  8. 問題がなければ変更を適用する
  9. .refactorlogが更新されていることを確認する
  10. SQLプロジェクトをビルドする

Rename Symbolはテーブル定義だけでなく、SQLプロジェクト内で解決できる参照もまとめて更新します。テーブル本体ではなく、そのテーブルを参照しているビューの定義上からリファクタリングを開始することもできます。(Microsoft Developer Blogs)

デプロイスクリプトには、次のような処理が生成されます。

EXECUTE sys.sp_rename
    @objname = N'[SalesLT].[SalesOrderDetail]',
    @newname = N'SalesOrderLine',
    @objtype = N'OBJECT';

@newnameにはスキーマ名を含めず、新しいオブジェクト名だけを指定します。テーブル名の変更では既存テーブルをその場で改名するため、通常は全レコードを別テーブルへコピーする処理は発生しません。(Microsoft Learn)

SQLファイル名だけを変えてもリファクタリングにはならない

たとえば、次のファイル名を変更しただけでは、データベース上のテーブル名変更として記録されません。

SalesOrderDetail.sql
↓
SalesOrderLine.sql

SQLプロジェクトでは、ファイル名ではなく、ファイル内のデータベース定義が比較対象になります。

先にRename Symbolでオブジェクト名を変更し、その後、必要に応じてファイル名やフォルダーを整理してください。

列名も同じ方法で変更できる

列名についても、対象列を右クリックしてRename Symbolを実行します。

生成される処理は、次のようなsp_renameです。

EXECUTE sys.sp_rename
    @objname = N'[SalesLT].[SalesOrderLine].[OrderQty]',
    @newname = N'Quantity',
    @objtype = N'COLUMN';

ただし、列名変更には注意点があります。SELECT *を使っている非スキーマバインドのビューや関数は、定義内に旧列名が直接書かれていないため、参照更新だけではメタデータが更新されない場合があります。

Microsoftは、このような場合にsp_refreshviewやsp_refreshsqlmoduleによるメタデータ更新を案内しています。生成されたデプロイスクリプトに必要な更新処理が含まれているか確認してください。(Microsoft Learn)

Refactorでテーブルを別スキーマへ移動する手順

ここでは、次のようにテーブルを移動する例で説明します。

変更前:SalesLT.ProductDescription
変更後:ProductCatalog.ProductDescription

新しいスキーマをプロジェクトへ追加する

移動先のスキーマが存在しない場合は、最初にプロジェクトへ追加します。

  1. Database Projectsビューでプロジェクトを右クリックする
  2. Add item...を選択する
  3. テンプレートからSchemaを選択する
  4. スキーマ名としてProductCatalogを入力する

作成される定義は、次のようになります。

CREATE SCHEMA [ProductCatalog];

Move to Schemaを実行する

  1. 移動対象テーブルのSQLファイルを開く
  2. CREATE TABLE内のテーブル名を右クリックする
  3. Refactorを選択する
  4. Move to Schemaを選択する
  5. 移動先としてProductCatalogを選択する
  6. Refactor Previewで変更内容を確認する
  7. テーブル定義と参照先の更新を確認する
  8. .refactorlogの変更を確認する
  9. 問題がなければ適用する

VS Codeでは、SQLプロジェクト内に定義されているユーザースキーマが選択肢として表示されます。変更プレビューには、テーブル定義、関連オブジェクトの参照、refactorlogへの追加内容が表示されます。(Microsoft Developer Blogs)

デプロイ時には、次のような処理が生成されます。

CREATE SCHEMA [ProductCatalog];
GO

ALTER SCHEMA [ProductCatalog]
TRANSFER [SalesLT].[ProductDescription];
GO

ALTER SCHEMA ... TRANSFERは、既存テーブルを別のスキーマへ移動する処理です。新しいテーブルを作ってデータをコピーする方式ではありません。(Microsoft Developer Blogs)

スキーマ移動では権限を必ず確認する

ALTER SCHEMA ... TRANSFERでオブジェクトを移動すると、そのオブジェクトに直接付与されていた権限は削除されます。

たとえば、次のようなテーブル単位の権限です。

GRANT SELECT
ON OBJECT::[SalesLT].[ProductDescription]
TO [ReportingRole];

必要な権限はSQLプロジェクト側にも定義し、生成されたデプロイスクリプトに新しいオブジェクト名への再付与が含まれているか確認してください。

作業前の権限は、次のようなクエリで確認できます。

SELECT
    USER_NAME(grantee_principal_id) AS grantee_name,
    permission_name,
    state_desc
FROM sys.database_permissions
WHERE major_id = OBJECT_ID(N'[SalesLT].[ProductDescription]');

データベース上だけで手作業により付与された権限は、SQLプロジェクトが把握していない可能性があります。スキーマ移動前に、対象オブジェクトのGRANT、DENY、REVOKEを必ず確認してください。(Microsoft Learn)

また、ALTER SCHEMAはスキーマレベルのロックを使用します。データコピーが発生しなくても、実行中にほかの処理が待機する可能性があるため、アクセスの多い本番環境ではロック待ちを含めて事前検証が必要です。(Microsoft Learn)

自動更新される参照と手動確認が必要な参照

VS Codeのリファクタリング機能が更新できるのは、基本的にSQLプロジェクト内で認識できる参照です。

参照元自動更新の期待確認方法
プロジェクト内のビュー高いRefactor Previewとビルド
プロジェクト内のストアドプロシージャ高いRefactor Previewと全文検索
プロジェクト内の関数・トリガー高いRefactor Previewとビルド
SQL文字列として組み立てる動的SQL低い旧名称の全文検索
アプリケーション内のSQL対象外ソースコード検索
ORMのテーブルマッピング対象外エンティティ設定やマイグレーション確認
SQL Server Agentジョブ対象外の場合ありジョブステップ確認
ETL・データ連携対象外ADF、SSIS、スクリプトなどを確認
Power BIや帳票対象外データセットとクエリ確認
別データベースからの参照対象外の場合あり接続先ごとに検索
外部ベンダーの連携処理対象外利用仕様と実行ログ確認

SQL Serverのsp_renameやALTER SCHEMA自体には、すべての参照を自動修正する機能はありません。SQL Projectsが更新するのは、プロジェクト内で依存関係を解決できた定義です。(Microsoft Learn)

データベース内の静的な依存関係は、sys.sql_expression_dependenciesでも調査できます。

SELECT
    OBJECT_SCHEMA_NAME(referencing_id) AS referencing_schema,
    OBJECT_NAME(referencing_id) AS referencing_object,
    referenced_schema_name,
    referenced_entity_name
FROM sys.sql_expression_dependencies
WHERE referenced_schema_name = N'SalesLT'
  AND referenced_entity_name = N'SalesOrderDetail';

ただし、文字列連結で生成される動的SQLや、アプリケーション側から送信されるSQLは、このビューだけでは把握できません。

最低でも、リポジトリ全体で次の表記を検索してください。

SalesOrderDetail
SalesLT.SalesOrderDetail
[SalesLT].[SalesOrderDetail]

コメントやテストコードだけでなく、JSON、YAML、PowerShell、CI/CD設定、ORMマッピングなども検索対象に含めます。

デプロイ前にGenerate Scriptで計画を確認する

SQL Projectsのリファクタリングは、操作した時点ではまだデータベースへ反映されません。

本番へPublishする前に、VS Codeからデプロイスクリプトを生成します。

  1. Database Projectsビューでプロジェクトを右クリックする
  2. Publishを選択する
  3. 対象サーバーとデータベースを指定する
  4. Generate Scriptを選択する
  5. 生成されたSQLを確認する
  6. 問題がなければ検証環境へ適用する
  7. 検証後に本番環境へPublishする

VS CodeのPublish画面では、データベースへ直接反映する前にデプロイスクリプトを生成できます。プロジェクトと対象データベースを比較した結果が反映されるため、単なるビルド成功だけでなく、実際の対象環境に対する処理を確認できます。(Microsoft Learn)

生成スクリプトの確認ポイント

確認対象期待する内容危険な兆候
テーブル名変更sp_renameDROP TABLEとCREATE TABLE
スキーマ移動ALTER SCHEMA ... TRANSFER新規テーブル作成とデータコピー
refactorlogdbo.__RefactorLogと操作キーrefactorlog由来の処理がない
参照オブジェクト新名称への変更旧名称が残っている
権限新しい完全修飾名へのGRANT必要な再付与がない
データ処理原則として移送処理なし大量のINSERT SELECT
削除処理意図したものだけ無関係なテーブルや列の削除

生成されたSQLでは、次の文字列を検索すると確認しやすくなります。

sp_rename
ALTER SCHEMA
__RefactorLog
DROP TABLE
CREATE TABLE
INSERT INTO

refactorlogが正しくパッケージ化されていれば、生成スクリプト内には操作キーを示すメッセージと、dbo.__RefactorLogへの記録処理が含まれます。(Microsoft Developer Blogs)

BlockOnPossibleDataLossを無効化して解決しない

名前変更を手動編集した結果、データ損失の可能性があるとしてデプロイが停止することがあります。

このとき、次の設定を無効化して強制的に通す方法は推奨できません。

BlockOnPossibleDataLoss=False

BlockOnPossibleDataLossは、データ損失につながる可能性があるスキーマ変更を検出して停止するための安全装置です。既定値はTrueです。(Microsoft Learn)

名前変更でブロックされた場合は、安全装置を外すのではなく、Rename SymbolまたはMove to Schemaを使ってrefactorlogを正しく生成してください。

refactorlogをPre-Deployment Scriptで代用しない

「Pre-Deployment Scriptで先にsp_renameを実行すればよい」と考えるケースがありますが、単純な代用にはなりません。

SQL Projectsでは、Pre-Deployment Scriptが実行される前にデプロイ計画が計算されます。そのため、Pre-Deployment Scriptでテーブル名を変更しても、すでに作成済みのデプロイ計画には変更後の状態が反映されず、後続処理と競合する可能性があります。(Microsoft Learn)

名前変更やスキーマ移動の意図は、Pre-Deployment Scriptではなくrefactorlogを通じてデプロイモデルへ伝えるのが基本です。

Pre-Deployment Scriptは、モデル比較だけでは表現できないデータ準備や、デプロイ前に必要な補助処理へ使います。

データ移動がなくても無停止とは限らない

sp_renameやALTER SCHEMA ... TRANSFERは、大量データのコピーを避けられるため、テーブルを新規作成して全レコードを移す方法より短時間で完了しやすい処理です。

一方で、旧テーブル名を使っているアプリケーションが稼働中の場合、名前変更直後からSQLエラーが発生します。

つまり、次の2点は分けて考える必要があります。

  • データを保持したまま変更できるか
  • 旧アプリと新アプリを同時に稼働できるか

運用条件ごとの判断基準

運用条件推奨する方法
メンテナンス停止が可能アプリ停止後に直接リファクタリング
DBとアプリを同時更新できる同一リリースとして順序を管理
新旧アプリが一定期間混在する旧名のsynonymや互換ビューを検討
複数の外部システムが直接参照するすぐに改名せず段階的に廃止
テーブルを直接参照させたくないストアドプロシージャを契約層として利用
24時間稼働で停止できないExpand-and-Contract方式を検討

Microsoftの公式ブログでも、互換性を維持する方法として、ストアドプロシージャによるアクセス契約、旧名称のsynonym、データベースバージョンを使ったアプリ側の分岐などが挙げられています。(Microsoft Developer Blogs)

新旧アプリを併存させる展開例

無停止に近い更新が必要な場合は、次のように段階を分けます。

  1. 新旧両方のデータベース構成に対応したアプリを先行配信する
  2. 必要に応じて旧名称のsynonymや互換ビューを用意する
  3. SQL Projectsからテーブル名やスキーマを変更する
  4. 新名称を使うアプリへ切り替える
  5. 実行ログやエラーを監視する
  6. 旧バージョンがなくなった後に互換レイヤーを削除する

synonymや互換ビューを使う場合は、SELECTだけでなくINSERT、UPDATE、DELETE、権限、ORMの動作まで検証してください。

SQL Projectsのリファクタリングで失敗しやすいポイント

失敗例起こり得る問題対策
SQL内の名前を直接編集した削除と新規作成として認識されるRename Symbolを使う
スキーマ名を直接書き換えたテーブル再作成や予期しない差分Move to Schemaを使う
refactorlogをGitへ追加しなかったCI/CDや別環境で変更意図が消えるSQLファイルと一緒にコミット
過去のrefactorlogを削除した未適用環境でデータ損失の可能性すべての対象環境への適用状況を確認
XMLをコピーして操作キーを使い回した適用済み判定が不正になる操作ごとに一意のGUIDを使用
プロジェクト内だけ確認したアプリやETLが停止するリポジトリと外部システムを調査
スキーマ移動後の権限を確認しなかった利用者やバッチがアクセス不能になる権限をプロジェクトで宣言管理
Generate Scriptを省略した本番で予期しないDROPが実行される対象DBに対する計画を事前確認
Pre-Deployment Scriptだけで改名した事前計算済みの計画と競合するrefactorlogを使用
データ損失チェックを無効化した本当に危険な変更まで実行される原因となる差分を修正

Refactorを使わず段階的移行を選ぶべきケース

次のケースでは、単純な名前変更よりも段階的なデータベース移行が適しています。

  • 1つのテーブルを複数テーブルへ分割する
  • 複数テーブルを統合する
  • 主キーやデータ型を大きく変更する
  • データの変換やクレンジングが必要
  • 外部システムの参照先をすぐに変更できない
  • 旧アプリと新アプリを長期間併存させる
  • スキーマ変更時のロックを許容できない
  • CDC、レプリケーション、監査機能への影響が大きい

この場合は、新しい構造を追加して一定期間併存させ、アプリケーションの切り替え後に旧構造を削除するExpand-and-Contract方式を検討します。

また、ストアドプロシージャ、ビュー、関数、トリガーなどのモジュールは、sp_renameやALTER SCHEMAを使っても定義内の名称が適切に変わらない場合があります。Microsoftも、これらのオブジェクトについては削除と新しい名称での再作成を推奨しています。テーブルや列と同じ感覚で処理せず、生成されたデプロイ計画を個別に確認してください。(Microsoft Learn)

まとめ

SQL Database Projects extension for Visual Studio Codeでテーブル名やスキーマを安全に変更するには、SQL定義を直接書き換えず、VS Codeのリファクタリング機能を使います。

テーブル名や列名はRename Symbol、スキーマ移動はRefactor > Move to Schemaから実行してください。変更内容が.refactorlogへ記録されることで、デプロイ時にはsp_renameまたはALTER SCHEMA ... TRANSFERが生成され、テーブルの再作成や大量のデータ移動を避けられます。

実際の作業では、次の順序で進めるのが安全です。

  1. プロジェクトと対象データベースの差分を整理する
  2. VS CodeのRefactorから変更する
  3. .refactorlogをSQLファイルと一緒にコミットする
  4. Generate ScriptでDROP TABLEがないことを確認する
  5. プロジェクト外の参照とオブジェクト権限を確認する
  6. 本番相当環境でデプロイを検証する
  7. アプリケーションとの更新順序を決めて本番へ展開する

refactorlogは単なる履歴ファイルではなく、データを保持したまま変更するためのデプロイ指示です。作成後も削除せず、CI/CDで使用する.dacpacに確実に含めて管理してください。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次