セルの値変更を自動で履歴として記録する方法! 変更前・変更後の値を保存するVBA | EXCELトピックス

スポンサーリンク
スポンサーリンク
amazon
スマイルSALE
--:--:--
~
ad. 価格範囲を指定して商品を探せます

セルが変更されたら自動的に履歴を記録する方法

Excelでは、通常はセルの値を変更すると元の値が失われてしまいます。しかし、VBAを使用することで、セルの変更前・変更後の値を「いつ・誰が・どのセルを」変更したのか自動で別シートに記録・保存することが可能です。売上データや共有タスク表の変更追跡、トラブル発生時の監査ログとして非常に役立ちます。

VBAの設定手順

  1. 履歴を記録したいExcelシートを開いた状態で、キーボードの Alt + F11 を押し、VBAエディターを開きます。
  2. 画面左側の「Microsoft Excel Objects」内にある、対象のシート名(例: Sheet1)をダブルクリックしてコードウィンドウを開きます。
  3. 右側の白い画面に、以下のVBAコードをそのまま貼り付けます。
  4. エディターを閉じ、Excelシート側でセルを変更すると、「変更履歴」シートが自動生成され、履歴が1行ずつ蓄積されます。

セルの変更履歴を自動で記録するVBAコード

※このマクロは、対象のシートモジュール(Sheet1など)に直接貼り付けてください。標準モジュールでは動作しません。

Dim OldValues As Object ' 変更前の値を一時保持する辞書オブジェクト

' 1. セルを選択したとき、変更前の値を辞書に記憶するイベント
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Dim cell As Range
    
    ' 辞書が未作成の場合のみ生成
    If OldValues Is Nothing Then
        Set OldValues = CreateObject("Scripting.Dictionary")
    End If
    
    ' 選択されたセルのアドレスと値をペアで記憶
    For Each cell In Target
        If Not IsEmpty(cell.Value) Then
            OldValues(cell.Address) = cell.Value
        Else
            OldValues(cell.Address) = "(空白)"
        End If
    Next cell
End Sub

' 2. セルの値が書き換わったとき、変更履歴シートにログを書き出すイベント
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim cell As Range
    Dim oldValue As String

    ' 変更履歴シートの有無を確認し、なければ新規作成
    On Error Resume Next
    Set ws = ThisWorkbook.Sheets("変更履歴")
    On Error GoTo 0

    If ws Is Nothing Then
        Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
        ws.Name = "変更履歴"
        ' 見出しを設定
        ws.Range("A1:F1").Value = Array("No.", "変更日時", "変更者", "セルアドレス", "変更前の値", "変更後の値")
    End If

    ' 【超重要】履歴書き込みによる不要なイベント連鎖(無限ループ)を防ぐ
    Application.EnableEvents = False
    
    On Error GoTo ErrorHandler

    ' 変更されたセルを1つずつループ処理(複数セルの同時変更・コピペにも対応)
    For Each cell In Target
        ' 変更前の値を取得(辞書になければ空白だったとみなす)
        If Not OldValues Is Nothing Then
            If OldValues.Exists(cell.Address) Then
                oldValue = OldValues(cell.Address)
            Else
                oldValue = "(空白)"
            End If
        Else
            oldValue = "(不明)"
        End If

        ' 履歴シートの最終行の下にデータを書き出す
        lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1
        ws.Cells(lastRow, 1).Value = lastRow - 1
        ws.Cells(lastRow, 2).Value = Now
        ws.Cells(lastRow, 3).Value = Application.UserName
        ws.Cells(lastRow, 4).Value = cell.Parent.Name & "!" & cell.Address(False, False)
        ws.Cells(lastRow, 5).Value = oldValue
        ws.Cells(lastRow, 6).Value = cell.Value
    Next cell

ErrorHandler:
    ' 【超重要】イベント機能を必ず有効に戻す
    Application.EnableEvents = True
End Sub

コードの重要ポイント解説

  • Application.EnableEvents = False / True:この記述が最も重要です。VBA自身が「変更履歴」シートに値を書き込む行為も「セルの変更」にあたるため、これがないと再び自分自身のプログラムが呼び出され、Excelがハングアップ(強制終了)する無限ループに陥ります。それを防ぐために一時的にイベントを停止させています。
  • Worksheet_SelectionChange:ユーザーがセルをクリック(選択)した瞬間の値を内部の「辞書(Dictionary)」にストックしておき、その後に値が書き換わった際に「変更前」のデータとして取り出せるようにしています。
  • cell.Parent.Name & "!" & cell.Address:複数シートで運用する場合に備え、どのシートのどのセルが変更されたのかがひと目で分かる形式(例: Sheet1!A1)で記録します。

動作・出力イメージ

セルが書き換えられると、「変更履歴」シートに以下のように時系列でデータが追加されていきます。

No. 変更日時 変更者 セルアドレス 変更前の値 変更後の値
1 2026/06/24 12:00:15 山田 太郎 Sheet1!A1 150,000 180,000
2 2026/06/24 12:05:42 鈴木 一郎 Sheet1!B5 (空白) 対応中

まとめと運用の注意点

  • VBAのイベント機能を活用すれば、事前のシート準備なしで、セルの「変更前」と「変更後」のログを全自動で取得できます。
  • ブックの保存形式に注意: この機能を維持するため、Excelファイルを保存する際は必ず「Excel マクロ有効ブック(.xlsm)」の形式を選択して保存してください。通常の .xlsx で保存するとマクロコードが消去されてしまいます。