473,395 Members | 1,623 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

How to create Audit Trail on a Form ( MS-Access 2007)

satifali
I have a database shared with 5 users & want track who is changing what as they keep blaming each other for the changes. Please help.
Jan 22 '15 #1

✓ answered by jforbes

That is hilarious. I’ve been in your position and it’s not fun.

There are multiple ways of going about this depending on the level of reportability you are looking for.
If you are using SQL Server as your backend, you can create a trigger to take care of this with a large amount of flexibility. If you have SQL SEVER and want an example, let us know.
If you are using Access only, the easiest and most basic way that I’ve found is to create a table to store logging information. Then populate it on the Form_BeforeUpdate (or AfterUpdate, up to you) Event from any Form that contains Tables you want to monitor.

I mocked up some of this with some code I had lying around. Here is the basic table structure. Some people get really bent out of shape with reserved words, so you might want to rename Table to something not reserved.
Expand|Select|Wrap|Line Numbers
  1. Name: LastUpdate
  2. Field Name    Data Type
  3. ----------      ---------
  4. LastUpdateID    AutoNumber
  5. LastUpdate    Date/Time
  6. LastUpdateBy    Short Text
  7. Table        Short Text
  8. TableID        Short Text
There are multiple versions of the following code all over the internet that gets the currently logged in Windows User. If you don't have one already paste this into a code Module. (The top line needs to be outside of any methods):
Expand|Select|Wrap|Line Numbers
  1. Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
  2.  
  3. Public Function GetWindowsComputerName() As String
  4.     Dim strComputerName As String
  5.     Dim lngBuffSize As Long
  6.  
  7.     strComputerName = Space$(255)
  8.     lngBuffSize = Len(strComputerName)
  9.     If GetComputerName(strComputerName, lngBuffSize) Then
  10.         strComputerName = Left$(strComputerName, lngBuffSize)
  11.     End If
  12.  
  13.     GetWindowsComputerName = strComputerName
  14. End Function
  15.  
Also in that module, past the following function. This is the code that will insert the Logging record:
Expand|Select|Wrap|Line Numbers
  1. Public Function trackLastUpdate(ByRef sTable As String, ByRef sTableID As String) As Boolean
  2.     Dim sSQL As String
  3.  
  4.     trackLastUpdate = False
  5.  
  6.     sSQL = sSQL & "INSERT INTO LastUpdate ("
  7.     sSQL = sSQL & "  [Table] "
  8.     sSQL = sSQL & ", [TableID]"
  9.     sSQL = sSQL & ", [LastUpdate]"
  10.     sSQL = sSQL & ", [LastUpdateBy]"
  11.     sSQL = sSQL & ") VALUES ("
  12.     sSQL = sSQL & " '" & sTable & "'"
  13.     sSQL = sSQL & ", '" & sTableID & "'"
  14.     sSQL = sSQL & ", #" & Now() & "#"
  15.     sSQL = sSQL & ", '" & GetWindowsUser() & "'"
  16.     sSQL = sSQL & ")"
  17.  
  18.     CurrentDb.Execute sSQL
  19.  
  20.     trackLastUpdate = True
  21. End Function
Now from any Form that you would like to implement logging, edit the BeforeUpdate to something like this:
Expand|Select|Wrap|Line Numbers
  1. Private Sub Form_BeforeUpdate(Cancel As Integer)
  2.      Cancel = (Not trackLastUpdate(Me.RecordSource, Me!ID))
  3. End Sub
Or...
Expand|Select|Wrap|Line Numbers
  1. Private Sub Form_BeforeUpdate(Cancel As Integer)
  2.      Call trackLastUpdate(Me.RecordSource, Me!ID)
  3. End Sub
You may have to tweak this a bit to get it to match your fields. Also you can hard code the "Me.RecordSource" to the table name, especially if your recordsource is a query of sorts. Also, also you don't have to Cancel the update, it's just an option.

There are additional things you can do, like including what fields were changed. You can find out what is changed by inspecting the OldValue Property of a Control.

Lastly, you can see what has happened easier by creating Queries to link the LastUpdate Table back to logged Table. There are a lot of options, but here is a basic example:
Expand|Select|Wrap|Line Numbers
  1. SELECT Test.Test, Test.Category, Test.[Select], LastUpdate.LastUpdate, LastUpdate.LastUpdateBy
  2. FROM LastUpdate INNER JOIN Test ON val(LastUpdate.TableID) = Test.ID
  3. WHERE [Table]='Test'

1 2008
jforbes
1,107 Expert 1GB
That is hilarious. I’ve been in your position and it’s not fun.

There are multiple ways of going about this depending on the level of reportability you are looking for.
If you are using SQL Server as your backend, you can create a trigger to take care of this with a large amount of flexibility. If you have SQL SEVER and want an example, let us know.
If you are using Access only, the easiest and most basic way that I’ve found is to create a table to store logging information. Then populate it on the Form_BeforeUpdate (or AfterUpdate, up to you) Event from any Form that contains Tables you want to monitor.

I mocked up some of this with some code I had lying around. Here is the basic table structure. Some people get really bent out of shape with reserved words, so you might want to rename Table to something not reserved.
Expand|Select|Wrap|Line Numbers
  1. Name: LastUpdate
  2. Field Name    Data Type
  3. ----------      ---------
  4. LastUpdateID    AutoNumber
  5. LastUpdate    Date/Time
  6. LastUpdateBy    Short Text
  7. Table        Short Text
  8. TableID        Short Text
There are multiple versions of the following code all over the internet that gets the currently logged in Windows User. If you don't have one already paste this into a code Module. (The top line needs to be outside of any methods):
Expand|Select|Wrap|Line Numbers
  1. Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
  2.  
  3. Public Function GetWindowsComputerName() As String
  4.     Dim strComputerName As String
  5.     Dim lngBuffSize As Long
  6.  
  7.     strComputerName = Space$(255)
  8.     lngBuffSize = Len(strComputerName)
  9.     If GetComputerName(strComputerName, lngBuffSize) Then
  10.         strComputerName = Left$(strComputerName, lngBuffSize)
  11.     End If
  12.  
  13.     GetWindowsComputerName = strComputerName
  14. End Function
  15.  
Also in that module, past the following function. This is the code that will insert the Logging record:
Expand|Select|Wrap|Line Numbers
  1. Public Function trackLastUpdate(ByRef sTable As String, ByRef sTableID As String) As Boolean
  2.     Dim sSQL As String
  3.  
  4.     trackLastUpdate = False
  5.  
  6.     sSQL = sSQL & "INSERT INTO LastUpdate ("
  7.     sSQL = sSQL & "  [Table] "
  8.     sSQL = sSQL & ", [TableID]"
  9.     sSQL = sSQL & ", [LastUpdate]"
  10.     sSQL = sSQL & ", [LastUpdateBy]"
  11.     sSQL = sSQL & ") VALUES ("
  12.     sSQL = sSQL & " '" & sTable & "'"
  13.     sSQL = sSQL & ", '" & sTableID & "'"
  14.     sSQL = sSQL & ", #" & Now() & "#"
  15.     sSQL = sSQL & ", '" & GetWindowsUser() & "'"
  16.     sSQL = sSQL & ")"
  17.  
  18.     CurrentDb.Execute sSQL
  19.  
  20.     trackLastUpdate = True
  21. End Function
Now from any Form that you would like to implement logging, edit the BeforeUpdate to something like this:
Expand|Select|Wrap|Line Numbers
  1. Private Sub Form_BeforeUpdate(Cancel As Integer)
  2.      Cancel = (Not trackLastUpdate(Me.RecordSource, Me!ID))
  3. End Sub
Or...
Expand|Select|Wrap|Line Numbers
  1. Private Sub Form_BeforeUpdate(Cancel As Integer)
  2.      Call trackLastUpdate(Me.RecordSource, Me!ID)
  3. End Sub
You may have to tweak this a bit to get it to match your fields. Also you can hard code the "Me.RecordSource" to the table name, especially if your recordsource is a query of sorts. Also, also you don't have to Cancel the update, it's just an option.

There are additional things you can do, like including what fields were changed. You can find out what is changed by inspecting the OldValue Property of a Control.

Lastly, you can see what has happened easier by creating Queries to link the LastUpdate Table back to logged Table. There are a lot of options, but here is a basic example:
Expand|Select|Wrap|Line Numbers
  1. SELECT Test.Test, Test.Category, Test.[Select], LastUpdate.LastUpdate, LastUpdate.LastUpdateBy
  2. FROM LastUpdate INNER JOIN Test ON val(LastUpdate.TableID) = Test.ID
  3. WHERE [Table]='Test'
Jan 22 '15 #2

Sign in to post your reply or Sign up for a free account.

Similar topics

6
by: Raphael Gluck | last post by:
Hi, Is it possible for one to program one's pages as such that when a database table is updated over the web, via a form, that an e-mail confirmation is sent to a specified address, notifying...
3
by: Me | last post by:
Hi... A much lamented question, I guess.. I'm trying to create a simple audit trail. log the changes to an SQL 2000 table, so that they are written into a mirror table. The entire record, only...
3
by: Zlatko Matić | last post by:
Hello. I tried to implement audit trail, by making an audit trail table with the following fileds: TableName,FieldName,OldValue,NewValue,UpdateDate,type,UserName. Triggers on each table were...
13
by: Jim M | last post by:
I've been playing with Allen Browne's audit code and found it very useful. I need to track record insertions, deletions, and edits for several tables. I am planning to replace Access with Microsoft...
6
by: Parag | last post by:
Hello, I have been assigned the task to design the audit trail for the ASP.NET web application. I don't know what the best practices for such audit trails are. Our application one dedicated user...
0
by: hary08 | last post by:
I have a module copied ftom this site, here it is: Option Compare Database Option Explicit Public Function AuditTrail() On Error GoTo Err_Audit_Trail 'ACC2000: How to Create an Audit...
3
by: hary08 | last post by:
im doing a database for Hospital Admission, I have a log in form which prompt user for a password. The source of log in is to look for the values in my Table tblEmployees and match user name and...
6
by: babamc4 | last post by:
I have a main form (mainformlung) with 5 subforms (followupacute, followuplate, biochemresults, haemresults and pftresults). I have copied Allen Browne's Audit Trail code (thanks to Allen Browne)...
16
by: zandiT | last post by:
hello i'm using the microsoft audit trail example ACC2000: How to Create an Audit Trail of Record Changes in a Form and im having a problem with my recordset. in the example they are using a...
20
by: Bellina | last post by:
Hi, My knowledge in Access is very limited but I have managed to build a pretty good-wroking database for my department based on help and assistance of experts from forums like this one. A bit of...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.