以下の左側のシートに用意された表の値を変更すると、「変更履歴」シートの変更履歴表に変更内容が自動で記録されます。

※こちらで開発したファイルは、記事の最後にて配布しています。
このような、予め指定した範囲内のセルの値を変更した際に、変更履歴表に自動で記録する仕組みの実現方法について解説していきます。
1. 開発準備
今回は、予め指定した範囲内のセルの値を変更すると同時に、変更履歴表に自動で記録する仕組みを作っていきます。
そのように、該当するシートの特定のセルを編集すると同時に何かしらの処理を実行するには、「シートモジュール」の「イベントプロシージャ」を活用します。
シートモジュールは、該当するシートのタブ上で右クリックし、[コードの表示]を選択することで表示できます。

選択すると、以下のエディタ画面(VBE)が表示されます。
また、該当するシートのシートモジュールが表示された状態になります。
「Option Explicit」は、VBEの設定内容次第では表示されません。「Option Explicit」についての解説はこちらでは省略します。

次に、該当するシートのセルを編集すると同時に処理が実行される特殊なプロシージャ(イベントプロシージャ)を用意する必要があります。
そのためには、シートモジュールの左上のリストから「Worksheet」を選択します。

「Worksheet」を選択すると、自動で「Worksheet_SelectionChange」というプロシージャが表示されます。
このプロシージャは、該当するシート上のいずれかのセルが選択されると同時に処理が実行されるイベントプロシージャになります。

ただ、今回使用するイベントプロシージャは、セルを編集すると同時に処理が実行されるものになります。
そのため、右上のリストから「Change」を選択します。

表示された「Worksheet_Change」というプロシージャを活用します。
「Worksheet_SelectionChange」というプロシージャに関しても、今回は使用するため残しておきます。

2. コードの記述
以下のコードを記述します。
Dim oldValue As Variant
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.CountLarge = 1 And _
Target.Row >= 2 And _
Target.Column <= 3 Then
With Worksheets("変更履歴")
.Rows(2).Insert CopyOrigin:=xlFormatFromRightOrBelow
.Range("A2").Value = Now
.Range("B2").Value = Target.Address(False, False)
.Range("C2").Value = oldValue
.Range("D2").Value = Target.Value
End With
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.CountLarge = 1 Then
oldValue = Target.Value
End If
End Sub
では、コードについて解説していきます。
Private Sub Worksheet_Change(ByVal Target As Range)
'省略
End Sub
「Worksheet_Change」というプロシージャの引数の「Target」に、編集されたセルの情報が渡されます。
そのセルの情報を用いて、「変更履歴」シートに記録していくのですが、引数の「Target」から取得できる情報は、編集されたセルの情報のみのため、変更前のセルの値を取得することができません。
そのため、変更前のセルの情報を次の処理で、予め取得して保持しておく必要があります。
Dim oldValue As Variant
'省略
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.CountLarge = 1 Then
oldValue = Target.Value
End If
End Sub
「Worksheet_SelectionChange」というプロシージャの引数の「Target」に、選択されたセルの情報が渡されます。
セルの値を変更する前にセルを選択するという動作があります。
そのため、「Worksheet_SelectionChange」のプロシージャが実行された時点では、変更前のセルの情報(Target)を取得することができます。
そのセルの情報(Target)から、変数「oldValue」に変更前のセルの値を格納しています。
変数「oldValue」は、「Worksheet_SelectionChange」のプロシージャだけでなく、「Worksheet_Change」のプロシージャからでも参照できるようにする必要があります。
そのため、プロシージャの外に変数を宣言しています。
セルの値を格納する用の変数のため、数値や日付など色んな型を格納できるようにVariant型で宣言しています。
プロシージャの外に宣言した変数(モジュールレベルの変数)に格納した値は、プロシージャの処理が終了した後でも保持されます。
そのため、常に変更前のセルの値を保持することができます。
今回の場合は、単体のセルが変更されたときのみに変更履歴を記録するようにしているため、選択されているセルが1つであることを「If Target.CountLarge = 1 Then」で確認しています。
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.CountLarge = 1 And _
Target.Row >= 2 And _
Target.Column <= 3 Then
'省略
End If
End Sub
「Worksheet_Change」のプロシージャでは、変更履歴を記録する処理を行います。
そのため、変更履歴を記録する対象の範囲内が変更されたかどうかを確認しています。
今回の場合は、変更されたセルが1つであり、行番号が2以上、列番号が3以下であることを前提としています。
これは、「商品管理」シートに用意された表のデータの範囲になります。

この条件を満たしたときに、Ifの中の処理を実行します。
With Worksheets("変更履歴")
.Rows(2).Insert CopyOrigin:=xlFormatFromRightOrBelow
.Range("A2").Value = Now
.Range("B2").Value = Target.Address(False, False)
.Range("C2").Value = oldValue
.Range("D2").Value = Target.Value
End With
先ほどのIfの中の処理です。
こちらは、「変更履歴」シートの変更履歴表の先頭行に、変更履歴を記録する内容になっています。
そのため、「With」で「変更履歴」シートを指定して囲み、「With」から「End With」までの範囲内では、「変更履歴」シートの情報を省略して記述できるようにしています。
「.Rows(2).Insert CopyOrigin:=xlFormatFromRightOrBelow」で、「変更履歴」シートの2行目に行を挿入し、下の行(3行目)の書式を引き継いでいます。
そして、挿入した2行目の個々のセルに、以下の値を入力しています。
・セルA2:Now // 現在日時
・セルB2:Target.Address(False, False) // 更新されたセルの相対参照のアドレス
・セルC2:oldValue // 変更前のセルの値
・セルD2:Target.Value // 変更後のセルの値
3. 完成
以上の内容で実現できます。
予め指定した範囲内のセルの値を変更すると、「変更履歴」シートの変更履歴表に変更内容が自動で記録されます。
また、最後に変更した内容が、変更履歴表の先頭に記録されるようになっています。

▼サンプルファイル▼



































































































