i'm wondering if anyone has a solution for an issue i'm currently having with my Access database.
The database has a number of tables. Once a new record is added, i'd like to create a new entry (copying over the account name and phase automatically if it doesnt exist) into another table - saving others having to manually enter it & minimising the risk of incorrect data input.
I've tried an onChange update function, and while this works, it doesn't check if the entry currently exists in the other table, it just adds it.
Any ideas on implementing this?
If you can use VBA, this logic should work.
IF ISNULL(DLOOKUP("FieldName","TableName","WHERE CONDITION")) = True Then
DoCmd.OpenQuery "QUeryNameForAppendRecord"
Else:
DoCmd.OpenQuery "QueryNameForUpdateRecord"
End If
The DLookup is checking to see if the record exists, so substitute the field and table names accordingly. Use the Where condition to specify which record you are looking for and you will need to use it to reference your form controls. See link for further help in syntax/referencing.
DLookup Function
Related
I have a form for entering new records into database. After entering data into one of the controls I would like to check if a record with that data already exists in the database. If it does then I would like to move to that existing record and disable the control above metnioned control since value for this field should not be edited on existing records. All other fields can still be edited.
Now I was thinking of using an OnExit event but I have a hard time writing a proper macro which would check if record with that value already exists, load that existing record and disable the mentioned control.
I'm afraid I have almost no expirience writing macros in Access.
Great news I managed to find a solution to my problem. How did I do it?
Well my first attempt of solving the "does record exist" part of the problem is to go and count all the records that met specific criteria (their field contents match the contents of the input box for that field. Now because I have very poor knowledge of VBA syntax I must shamefully admit that I spent a whole day getting that to work but I did it.
Now here comes even more shameful moment for me. Just about five minutes later when I was tackling the "move to the existing record" part of my problem I realized that I used the dumbest approach for solving my fist part.
Why is the above solution for first part of my problem the dumbest approach?
That is because I was trying to count how many times a record with unique field value exists in database. And that is dumb because if you have unique field the it means that there can either be one or none matching records in the database.
Now instead of using DCount I ended up using FindFirst instead. And the biggest advantage of using FindFirst is that it actually solves both of my problems (does the record exists and move to it if it does) at the same time.
So I ended up with this little neat code
Private Sub TKlasifikacijska_številka_Exit(Cancel As Integer)
Set rst = Me.RecordsetClone
'Find existing record
rst.FindFirst "Klasifikacijska_številka = " & "'" & [TKlasifikacijska_številka] & "'"
'Recod found
If Not rst.NoMatch Then
'Undo last editing in order to avoid duplicates error after moving to existing record
Me.Undo
'Move to the existing record
Me.Bookmark = rst.Bookmark
'Record wasn't found
Else
'Don't do nothing - keep user editing new record
End If
End Sub
For clarification:
Klasifikacijska_številka is my unique field in the data table
TKlasifikacijska_številka is my unique field edit box
Probably not the best naming pattern and will come bite me in the future. But at the moment most importantly to me is that it works.
Oh as for the last part of my problem (disabling edit control on existing records) I figured out that it is much better to use different event and that is forms OnCurrent event. That event is fired every time a record position is changed and you can easily check to see if the record is already stored in database or is still a new record using this simple code.
Private Sub Form_Current()
'Existing record
If Not Me.NewRecord Then
'Disable the unique field edit box to prevent editing data of that field since
'such data should not be edited on existing records
Me.TKlasifikacijska_številka.Enabled = False
'Change header label caption to let user easily know that he is on an existing record
Me.Oznaka16.Caption = "Obstoječi zapis"
Else
'Enable the unique field edit box to enable user to enter data into it
Me.TKlasifikacijska_številka.Enabled = True
'Change header label caption to let user easily know that he is on a new record
Me.Oznaka16.Caption = "Nov zapis"
End If
End Sub
Any way I hope this would come useful to somebody.
I am at a loss as to why I am getting a run time error message saying that the record set is not updatable for a simple table which I created and sourced in a new form not dependent on anything else. Is it possible the database settings have somehow changed causing me this strange issue. How is this possible?
Some more details would be needed.
Anyway, how are you trying to modify the recordset? Via VBA?
I suggest some things you can try:
Open form properties --> Data tab and check that Allow modifications is set to Yes as far as Allow Additions and so on
1) You are trying to access the record before updating
2) In VBA you didn't invoke the .Edit method before trying to modify the record.
3) The form has a query as record source and the query is not updatable
The case 3) is the most complex of the three. It can be due, for example, to:
- Presence of total clauses like GROUP BY, COUNT, SUM that means that a record represents a set
- A calculated field that can't be updated
- Lack of permission to modify the table / query
Whenever a record is deleted or updated on a form, I want to save its old values in a history table (let's call it Revised). I guess I have to do the following:
For record changes:
use the BeforeUpdate event to save the data somewhere (collection ? array ? or to a recordset -the Revised table- without saving-yet ?)
use the AfterUpdate event to add/save that data to the Revised table
For Deletions:
use the OnDelete event to save the data - but again how ? several records could be deleted at once since the form (a subform in fact) is in datasheet view
use the AfterDelConfirm to add that data to the Revised table.
Do you have any clues, comments or links for this ?
This is all in a "pure Access" (no SQL Server) at the moment.
Many thanks !
Edit: as usual, properly asking the question gaves me ideas:
option 1
use the BeforeUpdate or the OnDelete to build the SQL statement, and use the AfterUpdate or the AfterDelConfirm to Execute the SQL statement. But that won't work for multiple deletions ?
option 2
have the Revised recordset defined at form level, insert the record "Before" but only Update "After". Again, problem with multiple deletes.
I've successfully used a variation of Allen Browne's approach in a couple of different projects. Check out his website for more details:
Creating an Audit Log
His solution uses temp tables and four generic function calls to handle the issue with multiple deletes.
Another approach I have considered more recently, but have not had an opportunity to actually implement, would be to use transactions to perform the change tracking. The basic algorithm would be:
use BeginTrans on the workspace prior to making any changes
in the OnDelete event
perform the deletions in code executing Delete queries against the workspace from step 1
add a record to your change auditing table
in the BeforeDelConfirm event
set Cancel = True
display your own Confirmation dialog
if user confirms then CommitTrans on workspace
otherwise Rollback the transaction on the workspace
Similar approach for Updates/Inserts. This would avoid the need for temporary tables/arrays/collections, etc. but I haven't fully thought through everything. The devil may be in the details.
An "easy" and generic solution, which could be implemented for multiple tables, would be to have a tracking table, made of the following:
Track_Table
==================================================
id_track as primary key
id_table as name of the table which has been updated
id_primaryKey as the record identifier (the PK of the updated record)
changeType, being either DEL or UPDATE
changeDate, as dateTime value
fieldName, as text
oldValue, as text or memo
newValue, as text or memo
if you have to identify the user who did the update, just add
userId
in your table ...
You could then create some generic "before update" and "after update functions" to be called on selected form's beforeUpdate and afterUpdate events. The beforeUpdate fonction will store the old value in a variable, while the afterUpdate function will populate the missing data and insert a new record in the track table.
You will have to find a way to find out the right\corresponding table name and field name. This could be difficult if you are using views or field aliases to display your data in forms.
Of course, all tables to be followed must have a primary key so you can follow changes at the record level. PKs set on multiple fields will surely be problematic ....
oldValues and newValues will have to be converted as text so you can store them in a text or memo field
I have two tables named [Insert_Record] and [Delete_Record] in MS Access. Both tables have the same fields but one table has records whereas another table has no record.
Question: I want, whenever I delete any record from the table [Insert_Record] that entire record should automatically insert into another table, i.e: [Delete Record].
How can I accomplish this?
Access 2010 introduced event-driven Data Macros that are similar to triggers. The process described in the question can easily be done with an After Delete data macro on the [Insert_Record] table:
As I understand it, Access doesn't have triggers.
The best you can probably do is put this sort of logic into the forms that edit the table. In other words, handle the deleted event at the form level and put your insert logic there.
If you want triggers, you'll want to use a proper RDMS that supports them (MySQL, MS SQL, Oracle, many others).
EDIT: Another way to do this (which may or may not work for you) would be to add a boolean column 'IsDeleted'. That way, you can just logically delete a record instead of moving it to another table. The downside of this approach is the deleted records stay in the main table which could cause performance woes if there are lots of deletes.
Create an append query, to add records into the second table, that is executed in the On Delete Confirm event of the form you are using to delete the record from the first table.
I imagine this 'Delete' is button driven...
So program the button to first Insert the record into one table before deleting it.
Just add the VBA for the insert above the delete.
Another method which nullifies your need for another table entirely is just one column that is a boolean... Active Yes/No (Default to yes.)
If Active then it is not actually deleted when they hit delete, just set the flag to False then nothing is actually deleted, no SQL code is required and there is no risk, you can even have a column with the user who updated it print in another column
Me.Active = False
Me.UserName = 'CurrentUser Location here
Me.RecordSet.Requery
Then there is no risk of actually losing anything is there and you have a record of who flagged it last.
In the continuous form just add the Where flag Active = True then no false flags will show and it looks to the user base as if it was deleted.
I am adding a part name to the database using a form, What code do I put behind the Add part button to validate against duplicate part names? (part number is the primary key) I think I need another recordset to search and compare the table but i'm a bit lost, any help would be great.
Private Sub btn_add_Click()
rs_parts.AddNew
With rs_parts
!partrno = lbl_partno.Caption
!Name = txt_name
rs_parts.update
end with
I've discussed my approach to this before, and given an example form for adding a new record.
I use an unbound form to collect the information needed to create the new record, and have it check for duplicates, and present a list of them to the user so the user can decide what to do.
In this case, it sounds like a unique index is in order, so you won't really need to worry about close matches. I would probably still use an unbound form to capture the new value and run the check before even attempting to add it. In that case, I'd just notify the user that it's a dupe.
Should you add a unique index to the part name field?
If you want, you can create a query on your part table with one column for the name and a parameter for the criteria they've entered in txt_name. Then pass the value they entered as a parameter to the query and see if you get any results.