Access形式でバックアップしてSQL Serverに手軽に戻すC#な方法

SQL Server Management Studio の「データのエクスポート」を使うと、SQL Server から手軽にバックアップが取れる。バックアップというよりも、どこかに移動したいときに使うわけだが、Access 形式で取るのが一番手軽だと思う。

image

問題

顧客の 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("保存しました");
}
カテゴリー: 開発, C# パーマリンク