Ensure Unique Records in Form (MS Access) - vba

Using a Form in MS Access, I need to ensure only unique records are entered into the table.
It's unfortunately in a situation where I can't enforce unique records via the table's primary keys.
I have the following code in the BeforeUpdate for the Form, but it is not working. Any help would be greatly appreciated!
Private Sub Form_BeforeUpdate(Cancel As Integer)
If DCount("*", "[Role_Details]", "[Role] = " & Me.[ComboRole] & " AND [Session] = " & Me.[ComboSession]) > 0 Then
MsgBox "Duplicate!"
Cancel = True
Me.[ComboSession].SetFocus
Exit Sub
End If
End Sub
Note: The table name is "Role_Details". Field names are "Role" and "Session". With "ComboRole" and "ComboSession" being the Form Field Labels.
Any thoughts on where I've gone wrong here?
Updates##
When I open the DataSheet Form, it presents a popup box saying "Enter Parameter Value" and "frm_Role_Details.Session". I'm not sure why this is, but I can enter past it and open the Form.
Then, them i'm entering a record an error pops up saying "Run-time error '2465': Can't find the field '|1' referred to in your expression. Both Fields are Text Strings. I'm at a loss!

When concatenating in VBA, text fields require apostrophe delimiters for inputs.
If DCount("*", "[Role_Details]", "[Role] = '" & Me.[ComboRole] & "' AND [Session] = '" & Me.[ComboSession] & "'")> 0 Then
Date/Time fields use # delimiter.
Number fields do not use any delimiter.

Related

I want to move a data entry form in microsoft access to an existing record if a matching record already exists

I have a unique index of fields in my table in microsoft access. The fields are Shift, Operator, Date_Field, and Machine. I have a data entry form with combobox selections for these fields, except for the date which autopopulates today's date. I want to be able to navigate the form te the record that matches the existing Shift/Operator/Date/Machine combo if it already exists. I have a DLookup function that checks to see if such a record exists already, but now I need to know how to change the form so it is entering the data on that record instead of a new one.
Here's what I have so far. It is being activated in the AfterUdate of one of the last combobox in the tab order.
Dim int_ID As Integer
With Me
'checks if duplicate record exists and stores it as int_ID variable
int_ID = Nz(DLookup("ID", "Tracking", "Shift= " & Val(.ShiftCbo) & " And Operator='" & .OpCbo.Column(1) & "' And Date_Field=#" & .DateBox & "# And Machine='" & .MachineCbo.Column(1) & "'"), 0)
End With
If int_ID <> 0 Then
'I need to know what to put here to take the form to the existing record.
End If
I've tried to use Cmd.GoToRecord but that doesn't work.
One of my favorite (and simplest) methods is using Me.Recordsource
Once you have your code working correctly which defines the filter criteria, try something like this:
Me.Recordsource= "select * from UnderlyingFormMainQuery where TextColumnName='" & varString & "' or NumericColumnName=" & intSomething
Me.Requery

Find data location based on Primarykey ID

I am very new to access and vba so apologies in advance for glaring conceptual gaps.
Basically I have a button that, when clicked, prompts a user to enter an ID number. The ID entered will correspond to one of my primary keys in a specific table (I have some checks in place to make sure the entered ID is valid).
I need my code to identify the row number of the ID entered and be able to populate a specific column in that row. I know Access does not refer to data locations using rows/cols but that is the best way I thought to describe it.
I am using Index/Seek/NoMatch to make sure the entered ID number is valid and I have been trying to find a way to also use those functions to generate the data location but have not had any luck. Any help would be greatly appreciated.
I think DLookup() function will work for your case. Suppose you have following dataset in table tblEmpInfo where EmpID is primary key field.
If you want to return employee name by entering employee id in a inputbox then use DLookup() like below-
Private Sub cmdDataLookup_Click()
Dim strEmpName As String, InputID As String
InputID = InputBox("Enter employee ID:", "Input ID")
strEmpName = DLookup("EmpName", "tblEmpInfo", "EmpID= '" & InputID & "'")
MsgBox strEmpName
End Sub
If you want to update any name by entering EmpID then use UPDATE SQL statement. Try below.
Private Sub cmdUpdateInfo_Click()
Dim strSQL As String, InputID As String
InputID = InputBox("Enter employee ID:", "Input ID")
strSQL = "UPDATE tblEmpInfo Set EmpName= 'Updated Value' WHERE EmpID= '" & InputID & "'"
CurrentDb.Execute strSQL
End Sub
Note: There is no direct way to get row number and column number of a Field in access but you can apply some trick by VBA to get row and column number of a Field. I will suggest to ask a separate question to get that.

find duplicate with if statement then delete duplicate

I have a table (BERTHAGE) that tracks the location of vessels when they are in the port.
When a vessel moves from one location to another location I process the move through a form which is tied into a combo box.
I use one combo box (tied into a query) to give me the current list of vessels in port.
From there I select the vessel that is moving.
Once the vessel is selected I use another combo box to select the new location.
From there I click the Save button and the record is saved in the appropriate table with the vessel now tied into the new location.
The issue I am having is that the prior location record still exists in the same table (BERTHAGE).
So now I have two records for one vessel in the same week, this becomes an issue when it comes to invoicing.
What I’m trying to do is eliminate one of the entries and of course it must be the older entry/former location of the vessel.
Because each entry is assigned an auto-number (primary key) the newest entry, the movement of the vessel from one location to another, will always have the higher auto number.
I have been trying to come up with a way to find the duplicate in the table (BERTHAGE), based on the vessel name and then delete the older entry with the duplicate vessel name.
It seems the only way to go about this is a series of queries (find duplicate, append) and this ends in over writing the entire table each time. I’m trying to avoid this and stick with the goal of only deleting any duplicates that are occurring that week when a vessel moves from one spot to another.
Though my scripting is average, I can’t help but to think that the best way to achieve this goal will be through something akin to an IF statement tied into the save button. I was hoping Access would have something similar to Excel's .RemoveDuplicates, but to date I have found not found it.
Looking for any pointers people may have.
Private Sub Form_Load()
DoCmd.RunCommand acCmdRecordsGoToLast
End Sub
Private Sub cmd_Clear_Click()
Me.Boat_New_Loc = ""
Me.CrNum.value = ""
Me.CrDockValue.value = ""
Me.CrFloatValue.value = ""
Me.CrOriValue.value = ""
Me.SelectNewLoc.value = ""
Me.cmd_berthed.value = ""
Me.NewFloatValue.value = ""
Me.NewDockValue.value = ""
Me.NewOrieValue.value = ""
End Sub
Private Sub Boat_New_Loc_Change()
Me.CrNum.value = Me.Boat_New_Loc.Column(4)
Me.CrDockValue.value = Me.Boat_New_Loc.Column(5)
Me.CrFloatValue.value = Me.Boat_New_Loc.Column(6)
Me.CrOriValue.value = Me.Boat_New_Loc.Column(7)
End Sub
Private Sub SelectNewLoc_Change()
Me.NewFloatValue.value = Me.SelectNewLoc.Column(1)
Me.NewDockValue.value = Me.SelectNewLoc.Column(2)
Me.NewOrieValue.value = Me.SelectNewLoc.Column(3)
End Sub
Private Sub Save_Code_But_Click()
DoCmd.RunSQL "UPDATE BERTHAGE SET BERTHAGE.LOCATION=False WHERE LOCATION=" & Me!CrNum _
& " AND LOCATION <>" _
& Me!SelectNewLoc & _
" AND BERTHAGE.LOCATION=True;"
DoCmd.Save acForm, "Change_Boat_Location3"
cmd_Clear_Click
End Sub
Rather than deleting the record, I would advise setting a flag in the table to indicate that it is not active. This means that you can recreate historical data if needed.
In my examples, I am going to assume that the table Berthage has a primay key field called ID that is an Autonumber, a field VesselID that is a numeric foreign key from a Vessel table that gives information about the vessels, and also has BerthageActive, which is a Yes/No field.
If you are able to do the update before saving the new information in the Berthage table, then you can use:
CurrentDb.Execute "UPDATE Berthage SET BerthageActive=False WHERE VesselID=" & Me!VesselID & " AND BerthageActive=True;"
If the new data already exists in the Berthage table, then you can use:
CurrentDb.Execute "UPDATE Berthage SET BerthageActive=False WHERE VesselID=" & Me!VesselID & " AND ID<>" & Me!ID & " AND BerthageActive=True;"
Regards,

How to make a field in access show the current value in the table, and accept input, but not update the table

I have been tasked with designing an Access front end for a SQL database I built. Unfortunately my VBA and Access knowledge are not as strong as they should be and I have run into a roadblock.
Currently I'm working on a script that will identify and flag high dollar assets that are entered into the database through the form. I have the update code written, but when I enter in a high value in the field the act of updating the value in the form and the update script itself clash and there is a 'Write Conflict'.
I can unbind the field in the form and that resoles the write conflict, but then the user first browsing to the record won't see the current value in the table.
My question: is there a way to have a field in a form show the value in a table, accept input, but not write the input to the table and leave the writing to the update query. If it helps I have included the update action I have written.
Private Sub Cost_AfterUpdate()
Dim CostCheck As String
CostCheck = "Update dbo_Purchasing SET Capitolasset = -1, COST = " & Me.Cost & " " & _
"Where itemMaster = " & Me.ItemMaster & " and " & Me.Cost & " >= " & 5000 & ""
DoCmd.RunSQL CostCheck
Me.Refresh
End Sub
It seems that you are trying to set the Capitolasset flag of the current record to -1 if the Cost entered is >= 5000. If so, you don't need to run an extra query, just update the Capitolasset value according to the Cost entered:
Private Sub Cost_AfterUpdate()
If IsNumeric(Me.Cost) Then
If Me.Cost >= 5000 Then
Me.Capitolasset = -1
Else
Me.Capitolasset = 0
End If
End If
End Sub
This will update the field before the record is saved.

Filtering Records in a Form with an Inner Join Query in Access

My Access 2013 database has two main tables; Customers and Sites. The Sites table has a foreign key pointing to a Customer record. I am building a search box into a Sites Form with an unbound text box and a command button. Once the button is pressed, it should filter the records based on the search criteria and VBA code. I need to be able to search by the Customer name, located in a separate table linked through a foreign key. So far, this is the code I have for the button:
Private Sub cmdSearch_Click()
Dim strSQL As String
strSQL = "SELECT * FROM tblMainSites " & _
"INNER JOIN tblMainCustomers " & _
"ON tblMainSites.Customer=tblMainCustomers.CustomerID " & _
"WHERE tblMainCustomers.Customer LIKE '*" & Me.txtSearch & "*'"
If IsNull(Me.txtSearch) Then
Me.Filter = ""
Me.FilterOn = False
Else
Debug.Print strSQL
Me.Filter = strSQL
Me.FilterOn = True
End If
End Sub
The problem is that every time I try to filter the records, I get the following:
"Run Time Error 3075, Syntax Error in Query Expression"
Using the Debug Print, it looks like the query expression I wrote is fine, and looks just like a working query I built within Access:
SELECT * FROM tblMainSites INNER JOIN tblMainCustomers ON tblMainSites.Customer=tblMainCustomers.CustomerID WHERE tblMainCustomers.Customer LIKE '*Affinity*'
My question is this: Am I using the Me.Filter method correctly? I cannot find any examples using a full SQL string. I've also tried using the DoCmd.OpenForm method with OpenArgs as the string, also to no avail.
Asking another way, is there a way to filter records in an Access form using a JOIN query?
My goal is to be able to search for a record in the Sites table while referencing the Customer name in the Customers table, since searching for the customer name in the Sites table fails due to it being the foreign key pointing to the Customers table.
Thanks in advance for your assistance!
Ok, after a lot more Googling, I found a site that told me I cannot use more than one table in a form without basing the form on a query.
Here's what I did:
I made a query called qrySites and it does this:
SELECT * FROM tblMainSites INNER JOIN tblMainCustomers ON tblMainSites.Customer = tblMainCustomers.CustomerID;
This gives me a recordset where the CustomerID is associated with the Customer name. I then changed the Record Source of the form frmSites to this new query, and updated the appropriate Control sources.
Then, the Search function filters records like this:
Private Sub cmdSearch_Click()
Dim strFilter As String
strFilter = "tblMainCustomers.Customer LIKE ""*" & Me.txtSearch & "*"""
If IsNull(Me.txtSearch) Then
Me.Filter = "" 'Clears filter if text box is blank when searching
Me.FilterOn = False
Else
Me.Filter = strFilter
Me.FilterOn = True
End If
End Sub
This gives the Me.Filter method the proper input, which is just the Where clause of the SQL query string.
I tested it, and the search works. The form also passes any changes through the query to the appropriate table, though I did have to check my control sources and some of the fields shared names in the tables.