SQL Server Management Studio の「データのエクスポート」を使うと、SQL Server から手軽にバックアップが取れる。バックアップというよりも、どこかに移動したいときに使うわけだが、Access 形式で取るのが一番手軽だと思う。
問題
顧客の SQL Server なデータを、開発用の SQL Server に吸い上げて、検証環境を作ることはよくやる。確実な方法は、SQL Server のバックアップをコピーするのがベストなのだけど、残念ながらバージョンが違うとこれがうまくいかない。バージョンが違うのだから、バージョンを揃えた環境を整えるのが筋なんだけど、古めのデータベース(SQL Server 7 とか)とか微妙な差異があって、いろいろなバージョンを揃えておくのも以外と面倒くさい。できれば、開発環境の SQL Server をそのまま使っておきたい。
SSMS の「データのインポート」がそのまま動けばいいのだが、Access 形式にエクスポートしたときにカラムの型が違ってしまっていて、インポート時にエラーになる。それに PK の扱いもややこしくて、ちまちま設定をしながらインポートをしないといけない。ひとつふたつのテーブルならば、手作業でもいいのだけど、
- 大量のテーブル(20以上ある)をインポートするのに、いちいち手作業は大変
- 何度もインポートするので手作業は大変
解決方法
ということで、緩い感じで、Access から SQL Server へインポートできないものか?と考えていた。で、結局 C# でスクリプト的なものを書くことにする。
顧客 SQL Server → Access → 開発 SQL Server
という流れなので、SQL Server 同士の型は一緒になっている。最初の「顧客 SQL Server → Access 」は問題がないので、後の「Access → 開発 SQL Server」をスクリプト化する。
public class DBBackup
{
public string AccessMdbPath { get; set; }
public string SqlServerConnectionString { get; set; }
public bool Restore( string tableName )
{
// Accessから読み込み
OleDbConnection cn = new OleDbConnection();
cn.ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + AccessMdbPath; // MDB名など
var dt = new DataTable();
var da = new OleDbDataAdapter($"select * from {tableName}", cn);
da.Fill(dt);
// SQL Severへ書き出し
var cnn = new SqlConnection(SqlServerConnectionString);
// 指定テーブル内を消去
var cmd = new SqlCommand($"TRUNCATE TABLE {tableName}", cnn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
// バルクコピーで挿入
var bc = new SqlBulkCopy(cnn);
cnn.Open();
bc.DestinationTableName = tableName;
bc.WriteToServer(dt);
cnn.Close();
return true;
}
}
こんな感じに
- OleDb で Access MDB ファイルから読み込む
- SqlBulkCopy を使って、SQL Server にバルクコピーする
バルクコピーが一番早いし、こうじゃないと実行時に時間が掛かってしまう。
使い方
テーブル名は Access でも SQL Server でも一緒なので、DBBackup::Restore を使ってがしがしと戻していく。テーブル名は自動で取得できるけど、今回の場合は、移行不要なテーブルもあるので、必要なものだけピックアップしている。
private void clickLoadAccess(object sender, RoutedEventArgs e)
{
var dbb = new DBBackup()
{
AccessMdbPath = @"営業管理_20190304.mdb",
SqlServerConnectionString = "Data Source=.;Initial Catalog=営業管理2;Integrated Security=True;",
};
var tables = new List()
{
"タイトルファイル2",
"タイトルファイル属性",
"プログラム一覧",
"パスワード",
"ユーザマスタ",
...
};
foreach ( var name in tables )
{
dbb.Restore( name );
System.Diagnostics.Debug.WriteLine("テーブル: " + name);
}
MessageBox.Show("保存しました");
}