How do I update a single field of a single record with data from another table with VBA in MS Access - vba

In MS Access, I have a table called "Products". It contains quality testing parameters, as well as fields for "Part_No" and "Last_Test_Date". The "Last_Test_Date" field being the last time that the specific product was tested.
I have another table (Trend001) that is live updated with the actual test data from a hydraulic test machine, as well as the "Part_No" being tested and a current "Time_Stamp".
I would like to update the "Last_Test_Date" of the specific "Part_No" being tested with the "Time_Stamp" from the "Trend001" table.
That way the user knows the last time that the Part was tested.
I found this on Stackoverflow, but I don't know enough about the language to apply it to my project.
Updating existing records and adding new records in table (MS Access VBA)
'''
Public Sub UpdateExistingRecords()
On Error GoTo ErrTrap
Dim rs As DAO.Recordset
Set rs = CurrentDb().OpenRecordset("SELECT * FROM tblTempData", dbOpenSnapshot)
Set rsCommon = CurrentDb().OpenRecordset("SELECT * FROM tblCommon", dbOpenDynaset)
Dim idx As Long
For idx = 1 To rs.RecordCount
If ExistsInCommon(rs![Item ID]) Then
If Not Update(rs) Then
MsgBox "Failed to update.", vbExclamation
GoTo Leave
End If
'''

You don't need VBA to do the update, just use a SQL update. This SQL will update all the parts in the Products table that exist in the Trend001 table.
UPDATE Products INNER JOIN Trend001 ON Products.Part_No = Trend001.Part_No
SET Products.Last_Test_Date = Trend001.Time_Stamp;
PLEASE - Remember to back up your database before running this update. A small typo could delete your data.

Related

Most efficient way to query 1 of 4 large Access tables based on condition (using VBA module)

For the past couple weeks I've been working on a very unconventional solution to a problem for my job. I'm almost there, but I need to know the most efficient way to do the last step. I will dumb it down so I don't have to write an essay describing the insane nature of the problem I've been working on.
I have four large local tables in MS Access with a total of over 500,000 records.
Each table represents a different type of product.
The productID for table1 always starts with "9"
The productID for table2 always starts with "8"
The productID for table3 always starts with "4"
The productID for table4 always starts with "3"
I have a vba procedure written that does exactly what I need it to do except I have it querying information using only table1 thus far. Basically, a user inputs a productID and the procedure searches the table for that record and sends the information to a sharepoint list. Speed of execution is HIGHLY important in my situation. So, what is the fastest way to have it run? Should I write a statement that says "If the ID starts with 9 then search this table, ElseIF ..... and so on." Or, should I combine all the tables into one and not have it look at the first digit of the ID?
I know this sounds like a simple issue but trust me, this is a wild over simplification of the real issue and it would take 2,000 words to explain how ridiculous it actually is; I'm not kidding. However, I am fairly confident that the answer to the above question will give me all the information I need to finish this project successfully. I have come so far and all I have left is to figure out the most efficient way to apply it to the 3 other tables.
Thanks!
As the tables are local, use the Seek method which is extremely fast:
Recordset.Seek method (DAO)
If the tables were linked, you could still using Seek by opening the backend database. This is an example:
Function SeekTable()
Const cstrTable As String = "tblValue01"
Const cstrAttached As String = ";DATABASE="
Dim wks As Workspace
Dim dbs As Database
Dim tdf As TableDef
Dim rst As Recordset
Dim strConnect As String
Dim strTablename As String
Set wks = DBEngine(0)
Set dbs = wks(0)
Set tdf = dbs.TableDefs(cstrTable)
strConnect = tdf.Connect
strTablename = tdf.SourceTableName
Set tdf = Nothing
If InStr(1, strConnect, cstrAttached, vbBinaryCompare) = 1 Then
strConnect = Mid(strConnect, Len(cstrAttached) + 1)
' Open database shared and read-only.
Set dbs = wks.OpenDatabase(strConnect, False, True)
Set rst = dbs.OpenRecordset(strTablename)
'
' Perform Seek operation. Example.
rst.Index = "ID"
rst.Seek "=", 10010
Debug.Print rst!Value
'
rst.Close
Set rst = Nothing
End If
dbs.Close
Set dbs = Nothing
Set wks = Nothing
End Function

SQL Select statement suddenly retrieving wrong value only when selecting form another query

I have a order creation form in an Access database where the user selects a product and VBA code is triggered with SQL select statement to retrieve the current availability of that product. This is how it's set up:
I have a Packages table where products batches are added to inventory.
I have an OrderDetail table where items from product batches are allocated to orders.
I have a InventoryPrep query with a the total packaged per batch and field that sums the number of allocated products per batch from the OrderDetail table.
Then I have an Inventory query that that has a calculated field that takes the TotalPackaged field from the InventoryPrep query and subtracts the TotalAllocated field from the InventoryPrep query.
Here is the VBA code in my form, triggered by an update to the [Batch] combo box:
Dim VBatch As String
VBatch = Me.Batch.Value
Dim VAvail As Double
Dim mySQL As String
Dim conn1 As ADODB.Connection
Set conn1 = CurrentProject.Connection
Dim rs1 As New ADODB.Recordset
rs1.ActiveConnection = conn1
mySQL = "SELECT Available FROM Inventory WHERE BatchID = " & "'" & VBatch & "'"
rs1.Open mySQL
rs1.MoveFirst
VAvail = rs1.Fields("Available").Value
Forms!ChangeOrders.ChangeOrderSubform.Form.Availability.Value = VAvail
rs1.Close
conn1.Close
Set rs1 = Nothing
Set conn1 = Nothing
This has been working just fine for weeks, retreiving the correct available amount as packaged items are added to the Packages table and orders are being added in the OrderDetail table. Yesterday it started returning the Packaged field from the InventoryPrep query instead.
I tried a bunch of things and then created a table from the query and used the SELECT statement to look it up in the table. That worked. There is something about my query set up that has caused it to stop recognizing my calculated field. I need help!
This is my first time posting and I hope this is enough information. I'm pretty new to Access and VBA but I've learned a lot from reading in this forum. I hope someone can help or let me know what other information could shed light on the problem.
To read a single value from a table or query, your code is a bit over the top.
For this scenario, Access has the DLookup function.
VAvail = DLookup("Available", "Inventory", "BatchID = '" & VBatch & "'")
Forms!ChangeOrders.ChangeOrderSubform.Form.Availability.Value = VAvail
That's all that is needed.

loop through records and add record or create if none exists to new table depending on multiple criteria

I'm new to access/vba and trying to set up a project database. I have a table ("Updates") that is generated when changes are made to certain fields on a form (used for project updates by the end user). It has the primary key UpdateID, foreign key ProjectID as well as UTimeStamp, OldValue, NewValue, History. I use the history key to identify which type of update was made (for example for Status, History=1). I want to then count the number of projects for each status at the end of each month, keeping historical data to allow users to track the changes from month to month (or even compare data from months apart). I'm trying to write a code (in VBA for access) that would take into account that there are sometimes multiple status updates in each month and I don't want them to get counted twice, also some months no updates are made but I still want them included in the count (using the last updated status before that month as the status).
I was thinking of using a combination of looping through the records and checking to see if a value exists for that specific ProjectID and month and inserting the last value (most recent) into a new table "StatusTracking" and if no record exists then using the INSERT INTO function to add a new record. "StatusTracking" will have the fields ID, ValueMonth, ValueYear, (since ideally I want to track over the course of more than a year) Status, ProjectID. However, I am very new to this and am having trouble getting started as I'm not sure the best way to loop through both the months and ProjectID.
Public Function getStatus()
Dim varMonth As Integer
Dim ReportStatus As String
Dim RS As DAO.Recordset
Dim db As DAO.Database
Dim sqlStr As String
sqlStr = "SELECT Updates.ProjectID, Format(Month([UTimeStamp])) AS UpdateMonth, ProjectList.Status, Updates.NewValue, Updates.UTimeStamp" & _
"FROM Updates RIGHT JOIN ProjectList ON Updates.ProjectID = ProjectList.ProjectID" & _
"WHERE (((Updates.History) = 1))" & _
"GROUP BY Updates.ProjectID, Format(Month([UTimeStamp])), ProjectList.Status, Updates.NewValue, Updates.UTimeStamp"
Set db = CurrentDb
Set RS = db.OpenRecordset(sqlStr)
With RS
.MoveLast
.MoveFirst
While (Not .EOF)
'Cycle through each month
For varMonth = 1 To 12 Step 1
ReportStatus = DLast("NewValue", RS, "UpdateMonth = " & varMonth)
RS.Fields ("Status") <> RS.Fields("NewValue")
End Function
Any help is appreciated!
DCount is useful for counting unique occurrences in a specified field. The link I provided should put you on the right track there. Note that that only returns the count itself, and not the records. If you need to populate a recordset, you can use SELECT DISTINCT in your query to return only the records that have, well, distinct values in your criteria.
I recently worked on a project that involved building a history table for tracking purposes. Since it was based around forms, I opted for using .addnew and .update rather than INSERT INTO. Of course, use what's best for the situation at hand; I used .addnew and .update for the main reason that I had a lot of controls in my form and it was simpler in my mind to do it that way. There's lots of ways to do it, this worked best for me. I've also provided a snippet of the code I wrote for that project as another example.
Hope this helps!
'Example
'Assuming recordset and database variables are already declared
'rec = recordset, db = currentdb
set rec = db.openrecordset(<source table, name of existing query, or SQL query>)
if <condition is met> then
'populate table with values in form controls
rec.addnew
rec("Destination Table Field") = Me.Controls("Name of Form Control").Value
.
.
.
rec.update
set rec = nothing
set db = nothing
'clearing rec and db after done using
end if
Code from my project:
Set db = CurrentDb
Set rec = db.OpenRecordset("Select * from tbl_maintenanceOrders")
Set recHist = db.OpenRecordset("Select * from tbl_umoHistory")
msgConfirm = MsgBox("Correct values confirmed?", vbYesNo, "Continue")
'enter record in maintenance order table
If msgConfirm = vbYes Then
rec.AddNew
recHist.AddNew
rec("openTimestamp") = Now()
rec("openedBy") = Me.Controls("cbo_originator").Value
rec("assetID") = Me.Controls("cbo_asset").Value
rec("assetDesc") = Me.Controls("txt_assetDesc").Value
rec("priority") = Me.Controls("cbo_priority").Value
rec("umoProblemDesc") = Me.Controls("txt_issueDesc").Value
rec("umoSpecifics") = Me.Controls("txt_issueDetails").Value
rec("umoState") = "open"
rec("umoStatus") = "new"
rec.Update
'add UMO history entry
recHist("umoID") = rec("orderID")
recHist("activity") = "opened"
recHist("umoState") = "open"
recHist("umoStatus") = "new"
recHist("activityDesc") = "UMO Requested"
recHist("initiatorID") = Me.Controls("cbo_originator").Value
recHist("timeStamp") = Now()
recHist("updater") = Me.Controls("cbo_originator").Value
recHist.Update
End If
'cleanup
Set rec = Nothing
Set recHist = Nothing
Set db = Nothing

How do take the value from a combobox and use it to run an SQL query

I am trying to take the value from a combo box (in this case 'cboFullName' located on form 'frmMasterNotebook') and cross reference it to table 'tblSearchEngine01' so that an update gets made to column 'query05contactselect' for all records where in column 'contact' the value matches to that selected by the combobox ('cboFullName'). Below is my code but I am getting a syntax error message.
Private Sub cboFullName_AfterUpdate()
st_sql = "UPDATE tblSearchEngine01, SET tblSearchEngine01.Query05ContactSelect = '1' WHERE (((tblSearchEngine01.[contact])=([forms]![frmmasternotebook]![cbofullname]))))"
Application.DoCmd.RunSQL (st_sql)
Your code builds an UPDATE statement which includes a comma after the table name ...
UPDATE tblSearchEngine01, SET
^
Remove that comma and see whether Access complains about anything else.
However I suggest you start by creating and testing a new query in Access' query designer. Paste this statement into SQL View of your new query ...
UPDATE tblSearchEngine01
SET Query05ContactSelect = '1'
WHERE [contact] = [forms]![frmmasternotebook]![cbofullname];
After you revise and test the statement so that Access executes it without complaint, then you can revise your VBA code to produce the exact same statement text which works in the query designer.
Using DAO this is another way to resolve my issue:
Private Sub cboFullName_AfterUpdate()
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("tblSearchEngine06", dbOpenTable)
rst.AddNew
rst!Contact = Me.cboFullName.Text
rst!ContactID = Me.cboFullName
rst.Update
rst.Close
Set rst = Nothing

Access SQL How to select randomly a group of contiguous rows

can this be done, say I have rows (1,2,3,4,5) and I want to grab three rows, select one randomly and then get it's neighbors, so maybe the random selection is row (3), I can also grab (2,4) if I wanted its neighbors, do I just pick one at random and then look for the unique key before and after like this or can I do it all in one sql statement.
I was going to use ADO from excel to pull records (so VBA connects to access, opens a recordset with sql instructions and so on).
Hope I was clear!
I would love to just do this all in a SQL statement
I am not sure Access is capable of all the SQL commands such as SQL Server, so this may be a bit of a problem. If you have a primary key though, you can easly generate a Select query in VBA and then pass open recordset with this SQL.
Dim sSQL as String
Dim lRand as Long
Dim rs as ADODB.Recordset 'or DAO.Recordset'
lRand = VBA.Int(VBA.Rnd() * TableRecordCount) ' TableRecordCount is the number of records in the table that you need to get somehow'
sSQL = "SELECT * FROM TableName WHERE (ID>=" & lRand - 1 & " AND ID <=" & lRand + 1
set rs = CurrentDB.OpenRecordset(sSQL, ...)
I am now not absolutely sure of what you want to use and depending on ADODB or DAO choice, you need to open the recordset accordingly with wither Call rs.Open or Set rs = DB.OpenRecordset