Access VBA - OpenRecordset Saving Unwanted Old Data - ms-access

I am creating a form in my Access 2010 Database to input employee users. The code also is used to edit existing users.
To avoid confusion - the column names I will be talking about (which exist in the table 'Employees') are LastName and FirstName, while the input fields on my form are First and Last.
The form I am creating is for insertion OR updating of employee data. When the user types into the First field, Last is auto-populated with a list of values from the LastName column where FirstName = Me.First. If the administrator selects a last name that was populated in the box (rather then typing one in themselves), than the existing record is opened for editing.
My SQL for the Last combobox
SELECT DISTINCT Last
FROM [Employees]
WHERE First = Forms![Employees]!First;
My Code for after the Last combox is updated (Full = "LastName, FirstName")::
Private Sub Last_AfterUpdate()
Dim records As Recordset
Dim tmp As String
Dim db As Database
Set db = CurrentDb
If (DCount("Full", "Employees", "Full='" & Me.Last & "," & Me.First & "'") >= 1) Then
tmp = Me.Last & "," & Me.First
Set records = db.OpenRecordset("SELECT * from [Employees] WHERE Full = '" & tmp & "'")
Me.Recordset.FindFirst "ID1=" & records.Fields("ID1")
End If
If (DCount("Full", "Employees", "Full='" & Me.Last & ", " & Me.First & "'") >= 1) Then
tmp = Me.Last & ", " & Me.First
Set records = db.OpenRecordset("SELECT * from [Employees] WHERE Full = '" & tmp & "'")
Me.Recordset.FindFirst "ID1=" & records.Fields("ID1")
End If
End Sub
MY ISSUE:
If an existing record is found, than the record is opened correctly. Before the record is opened, however, a new one is saved with the data the administrator has input thus far. This is the issue, I don't want the data saved, but I don't know exactly why it is occurring in the first place. Is there a way to stop the old record from saving, aside from deleting it programmatically?

Related

How to get an Access Userform to update an existing record

I'm trying to get an access userform button to run an update query.
The parameters I have are:
Invoice number (should update Current ICB.Invoice number)
Material Code (should update Current ICB.Material Code)
Amount USD (Should update current ICB.Amount USD)
Username (Should update current ICB.Owner)
Vendor Code (Should update current ICB.Vendor code)
Record Number (Should = current ICB.ID)
I want to use a button on the form to check for a record that has the same record number and update the fields listed above with the values entered into the userform. I would use an update query but writing SQL into VBA is not my strong point. Any ideas?
In the OnClick event of the button, do something like this:
Dim db as Database
Dim rec as Recordset
Set db = CurrentDb
Set rec = db.OpenRecordset("Select * from MyTable where RecordNumber = " & ICB.ID & "")
rec.Edit
rec("InvoiceNumber") = ICB.Invoice_number
rec("MaterialCode") = ICB.Material_Code
etc...
rec.update
rec.close
Use your actual table and field names, but that's the general idea.
If you absolutely insist on using a query, then you need to write the SQL in code in a similar way and use DoCmd.RunSQL. Something like this:
txtSQL = "UPDATE MyTable SET InvoiceNumber = " & ICB.Invoice_number & ", " & _
" MaterialCode = " & ICB.Material_Code & "" & _
etc...
" WHERE RecordNumber = " & ICB.ID & ""
DoCmd.RunSQL txtSQL
This assumes you're only using integers. If you're storing the data as text, it needs to be surrounded by single quotes.
" MaterialCode = '" & ICB.Material_Code & "'" & _

SQL SUM statement in VBA function

My database has three tables, Holder, Product (which is an account) and Transaction. I have set up a form from the Holder table that has a subform from the Product table and the Product subform has the Transaction table as a subform. On the Holder portion of the form, I have put an Outstanding unbound text field that should display the total amount and tax fields of transactions from the transaction table that have not been paid (indicated by a checkbox on the Transaction table). I have set the control source of the unbound text box to =calcOutstanding() and written the following function for the form.
Public Function calcOutstanding()
Dim db As Database
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT SUM(tblTransaction.TxAmount + tblTransaction.TxTax) As Outstanding" _
& "FROM tblTransaction" _
& "INNER JOIN tblProduct ON tblTransaction.fkProductID = tblProduct.ProductID" _
& "INNER JOIN tblHolder ON tblProduct.fkHolderID = tblHolder.HolderID" _
& "WHERE tblTransaction.TxPaid = False" _
& "AND tlbHolder.HolderID = Me.HolderID;"
DoCmd.RunSQL strSQL
calcOutstanding = Outstanding
End Function
The field now just shows #Error. What am I doing wrong?
There's a bunch wrong with your approach:
DoCmd.RunSQL is just for action queries (INSERT, UPDATE, DELETE).
You cannot return a value from DoCmd.RunSQL like you are attempting to and push it into a variable.
Your concatenation for the where clause is incorrect.
As HansUp mentioned, Access is very picky about parentheses in JOINs in its SQL.
Assuming the SQL is correct, this code lives on the parent form, and you dno't get multiple rows back in your query, maybe something like this would work:
Public Function calcOutstanding() As Currency
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT SUM(tblTransaction.TxAmount + tblTransaction.TxTax) As Outstanding " _
& "FROM (tblTransaction " _
& "INNER JOIN tblProduct ON tblTransaction.fkProductID = tblProduct.ProductID) " _
& "INNER JOIN tblHolder ON tblProduct.fkHolderID = tblHolder.HolderID " _
& "WHERE tblTransaction.TxPaid = False " _
& "AND tlbHolder.HolderID = " & Me.HolderID
Set rst = db.OpenRecordset(strSQL, dbForwardOnly)
calcOutstanding = rst![Outstanding]
Set rst = Nothing
set db = Nothing
End Function
Notice the concatenation in the WHERE clause to get the value from the form's data source (otherwise the SQL couldn't reconcile Me.HolderID within the scope of the SQL itself). Also, we push the returning dataset into a recordset and read from that. Something along these lines should work, I think. (Not in front of Access now, so sorry if any non-compiling statements.)
EDIT: Added the function return type as integer for specificity's sake.
EDIT 2: Added the function return type as currencyfor specificity's sake. Doh.
Right off the bat, I see a problem in the code you posted:
strSQL = "SELECT SUM(tblTransaction.TxAmount + tblTransaction.TxTax) As Outstanding" _
& "FROM tblTransaction" _
& "INNER JOIN tblProduct ON tblTransaction.fkProductID = tblProduct.ProductID" _
& "INNER JOIN tblHolder ON tblProduct.fkHolderID = tblHolder.HolderID" _
& "WHERE tblTransaction.TxPaid = False" _
& "AND tlbHolder.HolderID = Me.HolderID;"
There should be a space either at the end of each line Outstanding " _ or at the beginning of each line like " FROM tblTransaction otherwise your string will read OutstandingFROM tblTransaction when parsed, which will give you an error.
I doubt you need an external function to do this. MS Access allows you to reference fields from subform simply by Me.Subform!FieldName.Value
This means, you could simply access the subform fields that are related to your current record. Even perform IIF(condition, truevalue, falsevalue) on that field
read more about accessing forms and subforms here: http://access.mvps.org/access/forms/frm0031.htm
EDIT:
in your third subform (tbl_transaction), create a new unbound TextBox called (txt_outstanding) and assign this expression
=IIF([txPaid]=false, sum(txAMount +TxTax),0)
now you can access this field in your parent form something similar to this:
me.txt_someTextbox.value = nz(me.tbltransactionsubform!txt_outstanding.value,"")

Order of records that DLookup uses to return first value (Access VBA)

long time stalker but first time poster here so apologies for any social faux pas I make.
I am trying to use DLookup to search for a record in a table using VBA. The specific record I am after is the one closest in date to sdate (a user specified date) which also meets some other criteria. There are likely to be a couple of records with dates prior to sdate which meet the same criteria, and I am only interested in the one which is chronologically closest to sdate.
The following is a simplified example of the code I am using to try and achieve this. I use baseTestString as there are quite a few similar DLookup expressions so it saves typing and clarifies the code slightly (to me at least).
DoCmd.OpenTable ("Results")
DoCmd.SetOrderBy "[Survey_Date] Desc"
DoCmd.Close acTable, ("Results")
'set a new criteria for baseline testing using Dlookup
basetestString = "[Equipment_ID] = '" & equipID & "' AND [Baseline?] = True _
AND format([Survey_Date],""ddmmyyyy"") < format(" _
& sdate & ",""ddmmyyyy"")"
'set variables
[Forms]![results]![text_A] = Nz(DLookup("[Input]", "[results]", _
basetestString))
I believed (perhaps naively) that DLookup returns the first record it finds that matches the criteria specified. So, my code was designed to sort the table into chronological order, thinking that this would be the order that DLookup would cycle through the records.
However, each time I run the code, I am returned the lowest possibly date that matches the criteria rather than the one closest to sdate. After some playing around, I believe that DLookup uses the primary key as its basis for cycling through the records (the earlier dates are entered earlier, and hence given a primary key using autonumber which is lower than later dates).
This leads to me my questions...
1) I am correct in believing this is what is happening when I am returned the wrong record?
2) Is there a way to use DLookup in the way I am attempting? Can I choose which field is used to order the records for DLookup? Assigning the date field as the primary key is not possible as the dates might not always be unique.
3) Is there any other way I can achieve what I am trying to do here?
Thank you very much
It is always unsafe to rely on an order of records in a relational database. You could use DMax to get the date you need, but I think that in this case a recordset would be quicker.
Dim rs As DAO.Recordset
Dim db As Database
Dim ssql As String
Set db = CurrentDB
ssql=" SELECT input" _
& " FROM results" _
& " WHERE results.[baseline?] = true" _
& " AND results.equipment_id = '" & equipID & "'" _
& " AND results.survey_date = (SELECT" _
& " Max(results.survey_date) " _
& " FROM results" _
& " WHERE results.[baseline?] = true" _
& " AND results.equipment_id = '" & equipID & "'" _
& " AND results.survey_date <#" & Format(sdate,"yyyy/mm/dd") & "#)"
Set rs = db.OpenRecordset(ssql)
strInput = rs("Input")
Debug.Print strInput
You can also check the number of records returned, in case of an error.

MS access to view all record history data with the specific input field value but it is showing only first record of criteria

I tried to display a list of all requests from a specific dept of my table
So I created a form with all the tbl fields that I want to display on the form view of "details" section like this .
dept name Totalnum req# ticket
Then I have created a combo box with pre-defined values as 'depttest' field.
Then I used the following code on change value of field but form is displaying only the first record of the category and not showing all the records .... can some one please help me with this logic..
Option Compare Database
Option Explicit
'Set default record source of form
Const strsql = "SELECT tbl.dept,tbl.name,tbl.[Totalnum],tbl.[req#],tbl.[Ticket] FROM tbl"
Private Sub depttest_Change()
Dim strFilterSQL As String
strFilterSQL = strsql & " Where [dept] = 'me.depttest.value';"
Me.RecordSource = strFilterSQL
'DoCmd.RunSQL strFilterSQL
Me.Requery
End Sub
You are passing me.depttest.value as a string not a value. Try:
strFilterSQL = strsql & " Where [dept] = '" & me.depttest.value & "';"

How can I check for null values in Access?

I am new to Access. I have a table full of records. I want to write a function to check if any id is null or empty. If so, I want to update it with xxxxx.
The check for id must be run through all tables in a database.
Can anyone provide some sample code?
I'm not sure if you are going to be able to find all tables in the database with Access SQL. Instead, you might want to write up some VBA to loop through the tables and generate some SQL for each table. Something along the lines of:
update TABLE set FIELD = 'xxxxxx' where ID is null
Check out the Nz() function. It leaves fields unaltered unless they're null, when it replaces them by whatever you specify.
For reasonable numbers and sizes of tables, it can be quicker to just
open them
sort by each field in turn
inspect for null values and replace manually
It's good practice to find out where the nulls are coming from and stop them - give fields default values, use Nz() on inputs. And have your code handle any nulls that slip through the net.
I'm calling it the UpdateFieldWhereNull Function, and shown is a Subroutine which calls it (adapted from http://www.aislebyaisle.com/access/vba_backend_code.htm)
It updates all tables in the DbPath parameter (not tested, handle with care):
Function UpdateFieldWhereNull(DbPath As String, fieldName as String, newFieldValue as String) As Boolean
'This links to all the tables that reside in DbPath,
' whether or not they already reside in this database.
'This works when linking to an Access .mdb file, not to ODBC.
'This keeps the same table name on the front end as on the back end.
Dim rs As Recordset
On Error Resume Next
'get tables in back end database
Set rs = CurrentDb.OpenRecordset("SELECT Name " & _
"FROM MSysObjects IN '" & DbPath & "' " & _
"WHERE Type=1 AND Flags=0")
If Err <> 0 Then Exit Function
'update field in tables
While Not rs.EOF
If DbPath <> Nz(DLookup("Database", "MSysObjects", "Name='" & rs!Name & "' And Type=6")) Then
'UPDATE the field with new value if null
DoCmd.RunSQL "UPDATE " & acTable & " SET [" & fieldName & "] = '" & newFieldValue & "' WHERE [" & fieldName & "] IS NULL"
End If
rs.MoveNext
Wend
rs.Close
UpdateFieldWhereNull = True
End Function
Sub CallUpdateFieldWhereNull()
Dim Result As Boolean
'Sample call:
Result = UpdateFieldWhereNull("C:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb", "ID", "xxxxxx")
Debug.Print Result
End Sub