Access subtract form value from another query - vba

In MS Access using VBA trying to subtract a calculated value (time between dates) from a total amount of time in another table.
The query holding the total amount of time is QryScsBatchHandler the field I want to subtract the value from is FreezerLifeUsed and the match condtion is BatchID
The query holding the value I want to subtract is QrySCSMaterialFreezerLog or the form is Frm_MaterialFreezerLog.. the value is AccumilatedTime and the Match condition is Batch ID
Private Sub BkInFrzr_Click()
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb()
strSQL = "SELECT FreezerLifeUsed FROM QryScsBatchHandler WHERE [BatchID] = BatchID"
Set rst = db.OpenRecordset(strSQL, dbOpenDynaset)
With rst
.MoveFirst
.Edit
FreezerLifeUsed = -AccumilatedTime
.Update
End With
End Sub
I can’t seem to get this simple subtraction to work… any suggestions on what’s not right?
Any help will be greatly appreciated..

At least 3 issues with code.
concatenate reference to form field/control for dynamic criteria in SQL:
strSQL = "SELECT FreezerLifeUsed FROM QryScsBatchHandler WHERE [BatchID] = " & Me.BatchID
The VBA needs to use dot or bang when referencing controls or fields and qualifying with prefix is advised:
!FreezerLifeUsed
Me.AccumilatedTime
Nothing is subtracted from anything, so consider:
!FreezerLifeUsed = !FreezerLifeUsed - Me.AccumilatedTime
However, if query is expected to return only one record, don't bother with loop. Also, instead of opening a recordset, an UPDATE action would work.

Related

In MS Access, is it possible to add an updatable blank field to a query to calculate it's values programmatically in VBA?

In MS Access, in order to prevent nesting queries, because it has become really slow, I'm trying to calculate programmatically in VBA all calculated fields for my queries using a Loop. In general, the idea is to stop using calculated fields on queries at all, to perform all calculations from the backend.
I am having problems showing the values in a TextBox in a Continuous Form. I'm trying to create a query in VBA with an empty field and then update the field with the calculated values, so then I can set the ControlSource of the textbox to that field for it to show properly. The problem is that since the empty field is a calculated field, I cannot update it's value. Is there any other way to add a field to a query that remains empty and updatable until I can calculate it's values?
An alternative solution would be to create a temporal table instead of a query and update the values, but I would really prefer not to create temporal tables every time an user needs to do a query with calculated fields (especially nested ones).
Is there a way to accomplish this?
Here is what I tried:
Private Sub Form_Load()
Dim SQLQ As string
Dim rs As DAO.Recordset
Dim dbs As DAO.Database
Dim qrydef As DAO.QueryDef
Dim i As Integer
'calcField1 is not a member of Items, and it's intended to be updated later on
SQLQ = "SELECT Items.Price, calcField1 FROM Items;"
Set dbs = CurrentDb()
Set qrydef = dbs.CreateQueryDef("testqry", SQLQ)
'Field is prompted for a value when the query is called and has no source
qrydef!calcField1 = vbNullString
Set rs = qrydef.OpenRecordset()
i = 0
Do Until rs.EOF
rs.Edit
rs!calcField1 = rs!Price *2 'Error here because calcField1 is a Calculated Field
rs.Update
i = i + 1
rs.MoveNext
Loop
Me.TextBox1.ControlSource = "=Price"
Me.TextBox2.ControlSource = "=calcField1"
Set Me.Recordset = rs
Me.Refresh
End Sub
I think it is better to create another table where you can insert the new calculated record with a reference to the original table so they are linked.
for example:
table 1:
item_id, item_desc, price
table 2:
item_id, calculated_value
then, the calculated value can be inserted or modified depending on the purpose of your calculation process.
Can you add the calculated field into a query and use that as the Record Source?
Private Sub Form_Load()
Dim strSQL As string
'calcField1 is calculated
strSQL = "SELECT Items.Price, (Items.Price * 2) AS calcField1 FROM Items;"
Me.TextBox1.ControlSource = "=Price"
Me.TextBox2.ControlSource = "=calcField1"
Set Me.RecordSource = SQLQ
Me.Refresh
End Sub
or if the logic is more complex you can put it into a function
'in the form
Private Sub Form_Load()
Dim strSQL As string
'calcField1 is computed by a function
strSQL = "SELECT Items.Price, MyFunction(Items.Price) AS calcField1 FROM Items;"
Me.TextBox1.ControlSource = "=Price"
Me.TextBox2.ControlSource = "=calcField1"
Set Me.RecordSource = strSQL
Me.Refresh
End Sub
'in a module
Public Function MyFunction(dbl As Double) As Double
MyFunction = dbl * 2
End Function

Setting listboxes in MS access form - row by row

I have a requirement in MS Access where a table is displayed as several rows in the form. I have created one form detail record(several fields) that will repeat for each row in the Table1. Lets say I have five columns in the Table1. Based on Column3 value, I would like to have a list of value for Column4 and Column5 during form_load. I have also created a separate Table2 to establish relationship between Column3, Column4 and Column5. I have set up Event procedure to populate the values using sub function. The challenge I have is, not being able to set up different listbox 'value list' for different rows. Any tips on populationg form fields IMRecomExIns and AmendReasonExIns by processing each row in Table1 would be a great help.
Private Sub IMRecomExIns_Click()
Dim CoverType As String
Dim ListRecomm As String
Dim ListAmend As String
Dim db As DAO.Database
Dim tablevar As Recordset
Set db = CurrentDb
Set tablevar = db.OpenRecordset("Table2")
CoverType = "*" & Me.CoverTypeExIns.Value & "*"
ListRecomm = ""
ListAmend = ""
If tablevar.EOF = False And tablevar.BOF = False Then
tablevar.MoveFirst
Do Until tablevar.EOF
If tablevar!CoverType Like CoverType Then
ListRecomm = tablevar!Recommendation
ListAmend = tablevar!AmendReason
tablevar.MoveLast
End If
tablevar.MoveNext
Loop
End If
Me.IMRecomExIns.RowSourceType = "Value list"
Me.IMRecomExIns.RowSource = ListRecomm
Me.AmendReasonExIns.RowSourceType = "Value list"
Me.AmendReasonExIns.RowSource = ListAmend
End Sub
1) I have stored all the value list in a single cell. For example tablevar!Recommendation will have all the values for Me.IMRecomExIns.RowSource, which means the output is will look like "Rec1";"Rec2";"Rec3";etc... Same applies for tablevar!AmendReason "AR1";"AR2';"AR3";ETC... Understand this is not the normalized form of storing data. I want to POC to work before building a full solution with normalized tables.
2) Answered earlier.. the rowsource will be set with all the possible values at the first match, so no point in going all the way to the end of the table
3) CoverTypeExIns is a string, Table 2 have many different possibilities such as "Mortgage Income" and "Family Income", however the Recommendation and Amendreason are same for all "Income" category that comes from Table1. Thats why the wildcard search.
My problem is not with setting the RowSource for a single row, but setting up RowSource for multiple occurrence in of the same IMRecommmendation and AmendReason in MS Access screen.
Here is the design view of the form. This form is linked to MS Access table. For multiple rows the Detail record will repeat itself as many times.
An example of two rows displayed in the screen.
I'm not sure exactly what you are asking/trying to do here.
I can see at several problems with the code that you have:
You are using tablevar.MoveLast in the loop, whic would automatically take you to the end of the recordset.
Also, you are not concatenating (joining together) ListRecomm/ListAmend, you are just setting them equal to a value, so each loop that matches will overwrite any previous value.
Finally, I am not sure what you are doing with trying to find CoverTypeExIns - you are using LIKE, which would indicate that it is text, but not wrapping the value in single quotes. If it is a numeric value, then you should be using "=".
However, rather than opening a recordset, looping it and checking for a match to build up a list of values, it is better to just set the RowSource of listboxes equal to a SQL string (effectively a query).
Something like (assuming CoverType is numeric):
Private Sub IMRecomExIns_Click()
Dim strSQL As String
strSQL = "SELECT Recommendation FROM Table2 WHERE CoverType=" & Me!CoverTypeExIns
Me!AmendReasonExIns.RowSource = strSQL
End Sub
I prefer to declare a string to hold the SQL statement rather than setting the .RowSource directly, as it makes troubleshooting easier.
Regards,
Based on the new information given, below is some VBA code that opens up a recordset based on the information entered in "Cover", and then sets the .RowSource property of the two combo boxes to be the value lists. In my example, don't bother setting the .RowSourceType, as this should be done at design time:
Private Sub IMRecomExIns_Click()
Dim db As DAO.Database
Dim rsData As DAO.Recordset
Dim strSQL As String
Set db = DBEngine(0)(0)
strSQL = "SELECT Recommendation, AmendReason FROM Table2 WHERE CoverType LIKE '*" & Me!cboCover & "*';"
Set rsData = db.OpenRecordset(strSQL)
If Not (rsData.BOF And rsData.EOF) Then
Me!IMRecomExIns.RowSource = rsData!Recommendation
Me!AmendReasonExIns.RowSource = rsData!AmendReason
End If
rsData.Close
Set rsData = Nothing
Set db = Nothing
End Sub
As I have previously stated, you should really normalize the design of your database now, rather than getting in so far that it requires a major re-write.
Regards,

In access VBA, Is there a way to look-up a record in a table using a combo-box criteria and adding that record to a different table?

I am trying to use unbound comboBoxes and textBoxes where a user a updates the controls and clicks on a button and a new record is created in another tblEntry using some data of the same record from tblItems.
Problem: My code only works on the first record. It creates the new record in the tblEntry using data of the first record in tblItems. Can someone have a look please?
Private Sub addItem_Click()
Dim rs1 As DAO.Recordset
Dim rs2 As DAO.Recordset
Set rs1 = CurrentDb.OpenRecordset("SELECT * FROM tblItems")
Set rs2 = CurrentDb.OpenRecordset("SELECT * FROM tblEntry")
If Not IsNull(Me.combo1) Then
rs2.AddNew
rs2.Fields("Description").Value = rs1.Fields("Description").Value
rs2.Fields("ItemNo").Value = rs1.Fields("ItemNo").Value
rs2.Fields("ItemName").Value = Me.txtItemName.Value
rs2.Fields("entryDate").Value = Me.txtentryDate.Value
rs2.Update
Form.frmItemEntryDatasheet.Requery
End If
rs1.Close
Set rs1 = Nothing
rs2.Close
Set rs2 = Nothing
End Sub
As #June7 says, there probably is no reason to do this. However, what you need to do is to open rs1 up filtered to just show data relating to that selected in combo1. Assuming that the first column in combo1 is the Primary Key from tblItem and called "ItemID":
Set rs1 = CurrentDb.OpenRecordset("SELECT ItemDescription, ItemNo FROM tblItems WHERE ItemID ='" & ItemID.Value & "'")
I have also renamed your field "Description" to "ItemDescription" as it is probably a reserved word within Access and may case problems. I have also just selected the 2 fields that you are going to use - there is no point getting all of the fields. You should be opening both recordsets within the If/End If statement.
Also, when you are opening rs2, you are effectively selecting the whole table. Far better is to use:
Set rs2 = CurrentDb.OpenRecordset("SELECT * FROM tblEntry WHERE 1 = 2")
This opens up a recordset based on tblEntry, but with no records selected, and so therefore has less overhead.
Regards,

How do you use VBA to make a form jump to the nearest future date in Access?

I'm trying to get an MS Access database to open a form either to today's date if it's in the date field in the database, or the nearest date in the future. I tried the code here, but it doesn't work. It just highlights the date field and goes to the first record instead of the nearest one in the future.
The Date field is WorshipDate and the table is wp_elements. (I am a pastor using this table to plan Sunday Worship).
Private Sub Form_Load()
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim strSQL As String
Dim TheDate As Date
Set db = CurrentDb
strSQL = "SELECT TOP 1 * FROM wp_elements WHERE wp_elements.WorshipDate >= Date() ORDER BY wp_elements.WorshipDate;"
Set rst = db.OpenRecordset(strSQL)
TheDate = rst.Fields(0)
WorshipDate.SetFocus
DoCmd.FindRecord TheDate, , True, , True
Set rst = Nothing
Set db = Nothing
'DoCmd.RunCommand acCmdRecordsGoToLast
End Sub
I know the SQL code I included works because I am using it in a Python script that's working quite well.
What am I missing? Or is there some other, easier way to do this?
You should only require one line of code:
me.RecordSet.FindFirst "Date() >= WorshipDate"

simple use recordset to find text box value on report

I'm trying to learn how to use recordsets in VBA and starting here. I want to lookup the value from the ProductVars table and populate to a text box on a report for each record [ProductID].
The value I want is where Field [Name]="Hinging" and I need it to send the value from the Field [Value] to the txtHinge text box on the report.
Here is my current code.
Private Sub Report_Load()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
'Open a table-type Recordset
Set rs = db.OpenRecordset("ProductVars")
'Find the value of Hinging from the Name field Name and populate to txtHinge
for the ProductID
Do Until rs.EOF
Me.txtHinge = rs!Name.Hinging.Value
rs.MoveNext
Loop
End Sub
Any help would be greatly appreciated.
In textbox ControlSource:
=DLookup("[Value]", "PRODUCTVARS", "[Name]='Hinging' AND ProductID=" & [ProductID])
Or if multiple dynamic parameters must be considered:
=DLookup("[Value]", "PRODUCTVARS", "[Name]='" & [Name] & "' AND ProductID=" & [ProductID])
If the latter is the case, possibly could just include the PRODUCTVARS table in the report RecordSource with a compound join.