ユーザーフォームでの履歴管理:変更ログを残すアプローチ

nanikatoaccess

以下では、「ユーザーフォームでの履歴管理:変更ログを残すアプローチ」をテーマに、Access上で入力されたデータの変更履歴(いつ・誰が・何をどのように更新したか)を記録し、後から確認できるようにする方法を解説します。複数ユーザーが同じテーブルを編集するときや、監査ログが求められる業務シナリオで役立つアプローチです。


1. なぜ履歴管理(変更ログ)が必要か?

  • 入力ミスや不正変更の追跡
    – 業務上、どのタイミングで誰がどの項目を変更したかが分かると、間違いをすぐ訂正できたり、不正アクセスに早期気づけたりします。
  • 監査要件対応
    – コンプライアンスや監査上、更新履歴を一定期間保管しなければならないケースがある。
  • 過去バージョンへのリストア
    – 事故やトラブルで誤更新された場合、ある程度のロールバックが履歴から可能になる。

Accessは標準機能として変更履歴を自動保存する仕組みはありませんが、BeforeUpdate/AfterUpdateイベントトリガーテーブルなどを工夫することで実現できます。


2. 代表的な履歴管理の手法

以下に、Accessでログを残す主な手法を紹介します。それぞれのやり方に長所・短所があります。

ないものはない!お買い物なら楽天市場

2.1 テーブル別にログテーブルを用意(レコード単位のスナップショット)

  1. tbl_顧客 の更新履歴を tbl_顧客ログ に記録するイメージ
  2. 各更新の前後で、レコード全体をコピーしたり、変更された列だけを記録
  3. 項目例:
    – ログID (オートナンバー)
    – 顧客ID (どの顧客が対象か)
    – 更新日時 / 更新者ID
    – 変更内容(旧値 / 新値) or レコードスナップショット

長所: 後から顧客IDや日時で検索しやすい
短所: 変更が頻繁だとログが膨大になる

2.2 全更新を1つの監査テーブルに集約(列名/旧値/新値)

  1. tbl_変更監査 を作り、すべてのテーブルの更新履歴をまとめて1つのテーブルに保存
  2. 項目例:
    – 監査ID (オートナンバー)
    – テーブル名 / フィールド名
    – レコードID (主キー値)
    – 旧値 / 新値
    – 更新日時 / 更新者
  3. 更新対象が増えても、テーブルを新規作る必要はなく、統一フォーマットでログを集約できる

長所: テーブルの追加や変更があってもログテーブルは1つで済む
短所: フィールドが多いDBやリレーションが複雑な場合、解析に手間がかかる


3. フォームイベントを使った実装例

最も手軽な方法は、フォームのBeforeUpdateイベントにコードを仕込み、変更前/後の値を検知してログテーブルにINSERTするやり方です。

3.1 テーブル例:変更ログテーブル (tbl_変更ログ)

フィールド名データ型説明
ログIDオートナンバー主キー
テーブル名短いテキスト例: “tbl_顧客”
レコードID数値など例: 変更対象の顧客ID, 商品IDなど
フィールド名短いテキストどのフィールドが変わったか
旧値 (OldValue)短いテキスト更新前の値
新値 (NewValue)短いテキスト更新後の値
更新日時日付/時刻型Now() などで更新時刻を記録
更新者短いテキストWindowsログイン名やユーザーIDなど

3.2 BeforeUpdateイベントで差分を判定

Private Sub Form_BeforeUpdate(Cancel As Integer)
Dim fld As DAO.Field
Dim db As DAO.Database
Dim strSQL As String
Dim oldVal As String, newVal As String

Set db = CurrentDb

' 顧客IDなど主キー値を取得 (例: 主キーが 顧客ID だとする)
Dim lngID As Long
lngID = Me.顧客ID ' フォーム上の主キー

' テーブル名は固定か、フォームのRecordSourceを参照するなど
Dim strTable As String
strTable = "tbl_顧客"

' フォームで編集された各フィールドを巡回
For Each fld In Me.Recordset.Fields

' フィールド単位で OldValue と Value(=NewValue) の差分をチェック
If fld.Name <> "顧客ID" Then ' 主キーは除外
If Nz(Me(fld.Name).OldValue, "") <> Nz(Me(fld.Name).Value, "") Then

oldVal = Nz(Me(fld.Name).OldValue, "")
newVal = Nz(Me(fld.Name).Value, "")

' ログテーブルにINSERT
strSQL = "INSERT INTO tbl_変更ログ " & _
"(テーブル名, レコードID, フィールド名, 旧値, 新値, 更新日時, 更新者)" & _
" VALUES(" & _
"'" & strTable & "', " & lngID & ", " & _
"'" & fld.Name & "', " & _
"'" & Replace(oldVal, "'", "''") & "', " & _
"'" & Replace(newVal, "'", "''") & "', " & _
"'" & Format(Now(), "yyyy-mm-dd hh:nn:ss") & "', " & _
"'" & Environ("Username") & "');"

db.Execute strSQL, dbFailOnError
End If
End If

Next fld

Set db = Nothing
End Sub

ポイント解説:

  • Me.Recordset.Fields でフォームバインドされている各フィールドを回す
  • OldValueValue (または NewValue) を比較し、違いがあればログテーブルにInsert
  • Replace(oldVal, "'", "''") でシングルクォートのエスケープ(SQLインジェクション対策)
  • Environ("Username") でWindowsユーザー名を取得し、更新者として記録(他の方法でユーザーID管理する場合も)

このようにBeforeUpdateイベントで書くと、レコード単位の更新時点でログが残り、未変更のフィールドはログを追加しないように管理できます。


4. 運用とデメリットを意識しよう

  1. ログが肥大化
    • 頻繁に更新されるフィールドがあると、ログテーブルが爆発的に増える可能性あり
    • 定期的なアーカイブや上限管理が必要
  2. すべてのフォームを対象にしないと漏れる
    • テーブルへ直接クエリでUPDATEしているケースや別フォーム更新などはカバーしにくい
    • 全更新を対象にしたい場合はトリガー(SQL Server) を使うか、あらゆる経路でログ書き込みを徹底する
  3. 参照整合性
    • ログテーブル内のレコードIDが削除された本体レコードと整合しなくなる
    • レコード削除時にもログを残すかどうか検討
  4. パフォーマンス
    • 更新のたびにINSERTが走るため、大量データを高速更新する場合にはオーバーヘッドになる
    • DBのメンテナンスや適切なインデックス管理を行う

5. 全クエリ・テーブル操作に対応するには?

BeforeUpdateイベントフォームを介した更新に強いですが、クエリ操作や他モジュールなどから直接更新が行われる場合はログが取れません。この場合、以下のアプローチが考えられます:

  1. すべての更新をフォーム経由に限定
    • ポリシーとして「クエリやテーブル直接編集は禁止」とし、ユーザーが更新時は必ずフォームを介させる
  2. SQL Serverのトリガーを使う(バックエンドがSQL Serverの場合)
    • テーブルにAFTER INSERT/UPDATE/DELETEトリガーを仕込み、ログテーブルへ書き込み
    • AccessでなくDBサーバー側で集中管理できる
  3. Accessクエリを拡張
    • アクションクエリ(UPDATE/DELETE)をマクロ/VBAでラップし、実行前後でログを記録する

6. ログの活用:検索・ロールバック】

  1. ログ閲覧フォーム
    • tbl_変更ログを元に「いつ/誰が/何を変更したか」を一覧表示
    • 顧客IDや日付でフィルタリングできるようにしておくと便利
  2. 差分リストア(半手動)
    • もし誤更新が判明したら、ログに残る旧値を確認し、手動で戻す
    • プログラム的に一括ロールバックする仕組みは複雑なので、通常はログから該当変更を調べて修正するケースが多い

7. まとめ:フォームでの履歴管理が現場での安心感を高める

  • フォームイベント + ログテーブルで「誰が、いつ、どの列を、どう変えたか」を記録できる
  • 単一フォームだけなら実装はそこまで難しくないが、複数の更新経路があるなら統一的なログ仕組みを整え、運用にブレが生じないよう配慮
  • ログテーブル管理ストレージ肥大化メンテナンスを視野に入れて長期運用を計画する

エンドユーザーから「誰がいつ変更したか分かるようにして!」という要望があった際には、上記の手法を応用すればスムーズに対応可能です。初めはフォームのBeforeUpdateで簡易的に差分を取るところから始め、必要に応じてトリガーやその他高度な仕組みに発展させていきましょう。


関連記事

今回紹介した変更ログのアプローチを導入すれば、Accessでも監査ログトレーサビリティを確保でき、信頼性の高いシステム運用が可能になります。ぜひ試してみてください。

DMM
ABOUT ME
管理人
管理人
駆け出しブロガー
入社した会社では、Accessを活用した基幹システムが長年運用されていました。しかし、開発者の高齢化により保守が困難となり、システムの維持・更新が急務に。 ほぼAccessに触れたことのなかった私は、ゼロから学びながら基幹システムを再構築してみることに。ついにはAccessによるシステム開発エンジニアとしてのスキルを身につけるまでに成長。 元々の業務のノウハウとそれを効率化するためのツール(Access)によって業務効率化システムをいくつも開発してきました。 みなさんの”なにか(業務のノウハウ)”とAccessで業務効率化を実現するお役に立てれば幸いです。
googleアドセンス
記事URLをコピーしました