開発のヒント

Accessのバックアップを取る

Access Tips [VBA自作関数]

Accessのバックアップは、SQL ServerやOracle と違って通常はデータが入っているAccdbをコピーする、言ってみれば非常に手軽なもので、必要に応じてサーバーの特定のフォルダやバックアップ用の外付けハードディスク等に「コピー、貼り付け」するだけです。
ただし手軽な半面、手作業の場合は「いつバックアップするのか」「誰がバックアップするのか」「忘れる可能性がある」等、考慮しなければならないことはあります。
「ファイルコピー用スクリプトを作成して、タスクスケジューラで実行する」「Windowsのバックアップ機能を利用する」といったことも考えられますが、ここではAccessでバックアップする例を記載します。

概要・ルール
  • 曜日別に毎日バックアップを取る。
  • 曜日別に最新のバックアップのみ残す。
  • 毎日、最初にAccess(プログラム用Accdb)を起動した人(今回の例ではAccess起動後表示されるログイン画面を最初に開いた人)によって自動的にバックアップを取る。
  • バックアップ後、データ用Accdbの最適化を行う。
  • 他の人によりバックアップを行っている最中にAccessを起動した場合は起動を中断し、しばらくしてから再度起動する。
呼び出されるコード
Option Compare Database
Option Explicit

'**********************************************************************
' 機能:バックアップ処理
' 引数:なし
' 戻値:処理結果 (0=正常終了、1=バックアップ処理中、-1=異常終了)
'**********************************************************************
Public Function DbBackup() As Integer
On Error GoTo trap
    
    Dim retCode             As Integer
    Dim Youbi               As String   ' 曜日のアルファベット先頭3文字
    Dim BkFileName          As String   ' 今回のバックアップで作成されるバックアップファイル名
    Dim BkFileName_Old      As String   ' 同じ曜日の前回に作成されたバックアップファイル名
    
    Dim FSO                 As Object
    Dim file                As Object
    
    Const C_WorkFolder      As String = "XXXXX"           ' データ用Accdb格納先フォルダ
    Const C_BkFolder        As String = "XXXXX"           ' バックアップ先のフォルダ
                                                          ' フォルダの最後にはを付けます。
    Const C_DbName          As String = "SampleDb.accdb"  ' データ用Accdbの名前
    Const C_TmpDbName       As String = "db1.accdb"       ' 一時Accdb名
    Const C_CheckFileName   As String = "bk_check.txt"    ' バックアップチェック用ファイル
    
    ' バックアップ処理中を示すテキストファイルの存在チェック
    ' 存在していたら他の人がバックアップ処理中であるとみなす。
    If Len(Dir(C_WorkFolder & C_CheckFileName)) > 0 Then
        DbBackup = 1
        Exit Function
    End If
    
    ' 本日の曜日を取得
    Youbi = GetYobi
    
    ' バックアップファイル名を生成(曜日 + 年月日時分秒 + _db.bak)
    BkFileName = Youbi & Format(Now(), "yyyymmddhhnnss") & "_db.bak"
    
    ' 同じ曜日の前回のバックアップのパス
    BkFileName_Old = Dir(C_BkFolder & "*.bak", vbNormal)
    
    ' 今回作成しようとしているバックアップファイルと先頭11桁が同じファイルの存在チェック
    Do While BkFileName_Old <> ""
    	
        ' 同じものが存在したら、本日のバックアップは処理済みとみなす。
        If Left(BkFileName_Old, 11) = Left(BkFileName, 11) Then
            DbBackup = 0
            Exit Function
        End If
        
        BkFileName_Old = Dir
    Loop
    
    ' バックアップ中のメッセージ表示用フォームを開く
    DoCmd.OpenForm "BackUpMsg"
    DoEvents
    
    ' バックアップ処理中を示すテキストファイルの作成
    retCode = CheckFileCreator(C_WorkFolder & C_CheckFileName)
    If retCode = -1 Then
        DbBackup = -1
        Exit Function
    End If
    
    Set FSO = CreateObject("Scripting.FileSystemObject")
    
    ' 今回作成しようとしているバックアップファイルと先頭3桁が同じファイルを削除する。
    ' ( = 同じ曜日の前回のバックアップファイルを削除)
    BkFileName_Old = Dir(C_BkFolder & "*.bak", vbNormal)
    
    Do While BkFileName_Old <> ""
    	
        If Left(BkFileName_Old, 3) = Left(BkFileName, 3) Then
            Set file = FSO.Getfile(C_BkFolder & BkFileName_Old)
            file.Delete
            Exit Do
        End If
        
        BkFileName_Old = Dir
    Loop
    
    ' バックアップ処理
    FSO.copyfile C_WorkFolder & C_DbName, C_BkFolder & BkFileName
    
    ' 最適化処理
    retCode = CompDb(C_WorkFolder & C_DbName, C_WorkFolder & C_TmpDbName)
    If retCode = -1 Then
        DbBackup = -1
        Exit Function
    End If
    
    ' バックアップ処理中を示すテキストファイルを削除
    If Len(Dir(C_WorkFolder & C_CheckFileName)) > 0 Then
        Set file = FSO.Getfile(C_WorkFolder & C_CheckFileName)
        file.Delete
    End If
    
    ' バックアップ中のメッセージ表示用フォームを閉じる
    DoCmd.Close acForm, "BackUpMsg"
    
exit_trap:
    Exit Function
    
trap:
    MsgBox "[" & Err.Number & "] " & Err.Description & " => DbBackup"
    DbBackup = -1
    Resume exit_trap
    
End Function

'**********************************************************************
' 機能:バックアップ処理中を示すテキストファイルの作成
' 引数:テキストファイルのパス
' 戻値:処理結果 (0=正常終了、-1=異常終了)
'**********************************************************************
Private Function CheckFileCreator(ByVal FilePath As String) As Integer
On Error GoTo trap
    
    Dim U_Name              As String
    Dim C_Name              As String
    Dim WSH                 As Object
    
    '==============================
    ' [ファイルの中身] ※中身は空でも良い。
    '   1. "バックアップ中"という文字列
    '   2. 現在日時
    '   3. ログインユーザー名
    '   4. コンピュータ名
    '==============================
    
    ' テキストファイルに書き込む情報のうち、ログインユーザー名とコンピュータ名を取得する。
    Set WSH = CreateObject("WScript.Network")
    U_Name = WSH.UserName
    C_Name = WSH.ComputerName
    Set WSH = Nothing
    
    Open FilePath For Output As #1
    Write #1, "バックアップ中", Now(), U_Name, C_Name
    Close #1
    
exit_trap:
    Exit Function
    
trap:
    MsgBox "[" & Err.Number & "] " & Err.Description & " => CheckFileCreate"
    Close #1
    CheckFileCreator = -1
    Resume exit_trap
    
End Function

'**********************************************************************
' 機能:最適化処理
' 引数:DBのパス
' 引数:一時DBのパス
' 戻値:処理結果 (0=正常終了、-1=異常終了)
'**********************************************************************
Private Function CompDb(ByVal DbPath As String, _
                        ByVal TmpDbPath As String) As Integer
On Error GoTo trap
    
    Dim FSO                 As Object
    Dim file                As Object
    
    ' 最適化の一時mdbが存在している場合は削除(念の為)
    If Dir(TmpDbPath) <> "" Then
        Kill TmpDbPath
    End If
    
    ' 最適化 (最適化したaccdbは一時ファイル名にする。ここでは「db1.accdb」)
    DBEngine.CompactDatabase DbPath, TmpDbPath
    
    ' 元のAccdbを削除する (ここでは「SampleDb.accdb」)
    Set FSO = CreateObject("Scripting.FileSystemObject")
    Set file = FSO.Getfile(DbPath)
    file.Delete
    
    ' 一時ファイルのAccdbを正式なファイル名に変更 (db1.accdb → SampleDb.accdb)
    Name TmpDbPath As DbPath
    
exit_trap:
    Exit Function
    
trap:
    MsgBox "[" & Err.Number & "] " & Err.Description & " => CompDb"
    CompDb = -1
    Resume exit_trap
    
End Function

'**********************************************************************
' 機能:本日の曜日を取得
' 引数:なし
' 戻値:取得した曜日の略称
'**********************************************************************
Private Function GetYobi() As String
    
    Dim Youbi               As String
    
    Select Case WeekdayName(WeekDay(Date))
        
        Case "日曜日"
            Youbi = "SUN"
        Case "月曜日"
            Youbi = "MON"
        Case "火曜日"
            Youbi = "TUE"
        Case "水曜日"
            Youbi = "WED"
        Case "木曜日"
            Youbi = "THU"
        Case "金曜日"
            Youbi = "FRI"
        Case "土曜日"
            Youbi = "SAT"
        
    End Select
    
    GetYobi = Youbi
    
End Function
呼び出し元:この例ではログイン画面のフォーム
Option Compare Database
Option Explicit

'**************************************************
' 開く時
'**************************************************
Private Sub Form_Open(Cancel As Integer)
    
    Dim retCode             As Integer
    
    With Me
        
        
        ' 開く時に必要なコード
        
        
        '==============================
        ' バックアップ処理
        '==============================
        retCode = DbBackup
        
        If retCode = -1 Then
            Cancel = True
            Exit Sub
        ElseIf retCode = 1 Then
            MsgBox "バックアップ処理中です。" & vbCrLf _
                 & "しばらくしてから再度Accessを起動して下さい。", 
                    vbOKOnly + vbCritical, "バックアップチェック"
            DoCmd.Close acForm, .Name
            Exit Sub
        End If
        
        
        ' 開く時に必要なコード
        
        
    End With
    
End Sub