Recordset Edits and Updates the Wrong Record - vba

I have the following code to loop through two tables and merge them into a new table:
Public Function MyFunction()
Dim Db As DAO.Database
Dim rst(1 To 3) As DAO.Recordset
Dim fld As DAO.Field
Dim fldname, fldtype As String
Dim PxID As Integer
Dim Iter, Counter As Integer
Set Db = CurrentDb
Set rst(1) = Db.OpenRecordset("Table1")
Call PrepTable ' Creates table named Test
rst(1).MoveFirst
Do While Not rst(1).EOF
PxID = rst(1)!PersonID
Set rst(2) = Db.OpenRecordset("SELECT * FROM Table2 WHERE PersonID=" & PxID)
If rst(2).RecordCount > 0 Then
rst(2).MoveLast
'set limit to 4 records if recordcount > 4
Iter = IIf(rst(2).RecordCount > 4, 4, rst(2).RecordCount)
rst(2).MoveFirst
For Counter = 1 To Iter
For Each fld In rst(2).Fields
If fld.OrdinalPosition = 0 Then
fldname = "PersonID"
Else
fldname = fld.Name & Trim(Str(Counter))
End If
If Not IsNull(fld.Value) Then
Set rst(3) = Db.OpenRecordset("Test")
'create new record on Test only if on new record on Table2
If (fldname = "PersonID" And Counter = 1) Then
rst(3).AddNew
Else
rst(3).Move 0
rst(3).Edit
End If
rst(3)(fldname).Value = fld.Value
rst(3).Update
rst(3).Bookmark = rst(3).LastModified 'not sure about this at all
End If
Next
rst(2).MoveNext
Next
rst(3).Close
End If
rst(2).Close
Set rst(2) = Nothing
Set rst(3) = Nothing
rst(1).MoveNext
Loop
rst(1).Close
Set rst(1) = Nothing
Debug.Print "Done."
Db.TableDefs.Refresh
DoCmd.OpenTable "Test", acViewNormal
End Function
Table1 contains 10 records. This function correctly creates 10 records on the Test table. However, only the first record is being updated (causing new data to overwrite the old). The last 9 records are blank save for the autonumber field of table Test and the PersonID field.
The basic question is: How do I move to the next row for the edit and update?

What you are trying to accomplish is really not entirely clear.
From what I understand, you are trying to transpose the first 4 records of Table2 into columns in table Temp.
Here, you are opening your rs(3) every for every field you loop through, but you never close it within that loop; you close it outside of the loop, at a level where it may not even be open...
So, first thing is to move that Set rst(3) = Db.OpenRecordset("Test") outside of all the loops.
Then it's not clear why you are doing with the rst(3).Move 0 and the rst(3).Bookmark = rst(3).LastModified.
Once you have added a new record, you do not need to call Edit on it again, or move around records and bookmakrs. All you need to do is make sure you call rst(3).Update after you copied all the field data.
Public Function MyFunction()
Dim Db As DAO.Database
Dim rst(1 To 3) As DAO.Recordset
Dim fld As DAO.Field
Dim fldname, fldtype As String
Dim PxID As Integer
Dim Iter, Counter As Integer
Set Db = CurrentDb
Set rst(1) = Db.OpenRecordset("Table1")
Call PrepTable ' Creates table named Test
rst(1).MoveFirst
Set rst(3) = Db.OpenRecordset("Test")
Do While Not rst(1).EOF
PxID = rst(1)!PersonID
Set rst(2) = Db.OpenRecordset("SELECT * FROM Table2 WHERE PersonID=" & PxID)
If rst(2).RecordCount > 0 Then
rst(2).MoveLast
'set limit to 4 records if recordcount > 4
Iter = IIf(rst(2).RecordCount > 4, 4, rst(2).RecordCount)
rst(2).MoveFirst
For Counter = 1 To Iter
For Each fld In rst(2).Fields
If fld.OrdinalPosition = 0 Then
fldname = "PersonID"
Else
fldname = fld.Name & Trim(Str(Counter))
End If
If Not IsNull(fld.Value) Then
'create new record on Test only if on new record on Table2
If (fldname = "PersonID" And Counter = 1) Then
rst(3).AddNew
End If
rst(3)(fldname).Value = fld.Value
End If
Next
If rs(3).EditMode <> dbEditNone Then
rst(3).Update
End If
rst(2).MoveNext
Next
End If
rst(2).Close
Set rst(2) = Nothing
rst(1).MoveNext
Loop
rst(3).Close
rst(1).Close
Set rst(3) = Nothing
Set rst(1) = Nothing
Debug.Print "Done."
Db.TableDefs.Refresh
DoCmd.OpenTable "Test", acViewNormal
End Function
I'm not saying this will work, and you could certainly clean up the logic in that code, but this should make it a bit better already.

Related

Subroutine & close record set hangs up while working from home

I have a subroutine that imports records from a store procedure (imports from a query to a temp table in access) and ever since I have been working from home, it hangs up and won't complete. I have a workaround where I set up a code-break for each record and then a break before rsTemp.Close, but this requires me to run the import instead of the end-user (It is only once a week and affects only one person who typically imports)
Set rsTemp = CurrentDb.OpenRecordset("qryValuationDef_Import", dbOpenDynaset, dbSeeChanges)
Any general tips that might help with this issue as we continue to work from home?
Thank you
Sub FillValuationTable(ReportDate As Date)
Dim rsValID As DAO.Recordset
Dim rsSnap As DAO.Recordset
Dim rsTemp As DAO.Recordset
Dim rsDemand As DAO.Recordset
Dim ValId As Variant
Dim SnapID As Variant
Dim TimeStamp As Date
DoCmd.SetWarnings False
TimeStamp = Now()
If DCount("Deal_ID", "temp_GMSImport", "Selected=-1") > 0 Then 'Ensures that there are selected items to import
'Opens all applicable tables to write valuations to
Set rsValID = CurrentDb.OpenRecordset("dbo_dvsValuationDef", dbOpenDynaset, dbSeeChanges)
Set rsSnap = CurrentDb.OpenRecordset("dbo_dvsGMSDealSnapshot", dbOpenDynaset, dbSeeChanges)
Set rsTemp = CurrentDb.OpenRecordset("qryValuationDef_Import", dbOpenDynaset, dbSeeChanges)
Set rsDemand = CurrentDb.OpenRecordset("dbo_dvsValuationDriver", dbOpenDynaset, dbSeeChanges)
rsTemp.MoveFirst
Do 'loops through all selected import items and writes them to the dvsValuationDef, dvsGMSDealSnapshot, and dvsValuationDriver table tables
With rsValID
'dvsValuationDef Additions
.AddNew
''Debug.Print rsValID
!dvsValuationDef_Descript = rsTemp("Link_Description")
''capture the description
Debug.Print !dvsValuationDef_Descript
!dvsBusinessUnit_Id = rsTemp("dvsBusinessUnit_Id")
!dvsBuySellType_Id = rsTemp("dvsBuySellType_Id")
!dvsValuationDef_Counterparty = rsTemp("Counterparty")
''Debug.Print !dvsValuationDef_Counterparty
!dvsValuationDef_DealTypePrice = rsTemp("Deal_Type_Price")
!dvsValuationDef_PipeBoardCode = rsTemp("Pipe_Board_Code")
!dvsValuationDef_ReportDate = ReportDate
!dvsRegion_Id = GetTraderRegion(DLookup("dvsTrader_Id", "dbo_dvsTrader", "dvsTrader_LastName=" & Chr(34) & rsTemp("Trader") & Chr(34)), rsTemp("Trader"), rsTemp("dvsRegion_Id"))
!dvsExecutive_Id = DLookup("dvsExecutive_Id", "lu_Region_SuperRegion_Exec", "dvsRegion_ID=" & rsTemp("dvsRegion_Id"))
!dvsDealType_Id = GetDealTypeID(rsTemp("Deal_Type_Price"))
!dvsCounterpartyType_Id = rsTemp("dvsCounterpartyType_Id")
!dvsValuationDef_HasAIPTrace = 0
!dvsValuationDef_HasRamp = 0
!dvsValuationDef_IsHidden = 0
!dvsValuationDef_HasAIPAdjust = 0
!dvsValuationDef_LastModified = TimeStamp
!dvsValuationDef_IsHidden = 0
!dvsValuationDef_TradeDate = rsTemp("Trade_Date")
.Update
.Bookmark = .LastModified
ValId = !dvsValuationDef_Id
''add to print the valuation number
Debug.Print ValId
End With
With rsSnap
'dvsGMSDealSnapshot additions
.AddNew
!dvsGMSDealSnapshot_DealID = rsTemp("Deal_Id")
!dvsValuationDef_Id = ValId
!dvsGMSDealSnapshot_Trader = rsTemp("Trader")
!dvsGMSDealSnapshot_TradeDate = rsTemp("Trade_Date")
!dvsGMSDealSnapshot_Region = rsTemp("Region")
!dvsGMSDealSnapshot_DealLink = rsTemp("Deal_Link_ID")
''Debug.Print !dvsGMSDealSnapshot_DealLink
!dvsGMSDealSnapshot_LinkDescription = rsTemp("Link_Description")
!dvsGMSDealSnapshot_BusinessUnit = rsTemp("Business_Unit")
!dvsGMSDealSnapshot_BuySell = rsTemp("Buy_Sell")
!dvsGMSDealSnapshot_Counterparty = rsTemp("Counterparty")
!dvsGMSDealSnapshot_DealTypePrice = rsTemp("Deal_Type_Price")
!dvsGMSDealSnapshot_PipeBoardCode = rsTemp("Pipe_Board_Code")
!dvsGMSDealSnapshot_IsAMA = rsTemp("AMA")
!dvsGMSDealSnapshot_IsToggle = rsTemp("Toggle")
!dvsGMSDealSnapshot_StartDate = rsTemp("Start_Date")
!dvsGMSDealSnapshot_StopDate = rsTemp("Stop_Date")
!dvsGMSDealSnapshot_Quantity = rsTemp("Quantity")
!dvsGMSDealSnapshot_TotalDemand = rsTemp("Total_Demand")
!dvsGMSDealSnapshot_LastModified = TimeStamp
.Update
.Bookmark = .LastModified
SnapID = !dvsGMSDealSnapshot_Id
''Debug.Print "snap ID" + SnapID
End With
With rsDemand
'dvsValuationDriver additions (this is Demand only)
.AddNew
!dvsValuationDriver_StartDate = rsTemp("Start_Date")
!dvsValuationDriver_StopDate = rsTemp("Stop_Date")
!dvsValuationDriver_Override = rsTemp("Total_Demand")
!dvsValuationDef_Id = ValId
!dvsGMSDealSnapshot_Id = SnapID
!dvsValuationDriverCat_Id = 3
!dvsValuationDriver_LastModified = TimeStamp
.Update
End With
'The following adds the trader to the Many to One table
DoCmd.RunSQL "INSERT INTO dbo_dvsValuationDef_dvsTrader ( dvsTrader_Id, dvsValuationDef_Id )" & _
" SELECT " & Nz(rsTemp("dvsTrader_Id"), 0) & ", " & ValId & "; "
rsTemp.MoveNext
Loop Until rsTemp.EOF 'Loop until all the selected items for import are written correctly
rsTemp.Close
rsValID.Close
rsSnap.Close
End If
SequenceRowNumbers ReportDate
DoCmd.SetWarnings True
End Sub
The best thing to do would be to re-write this as a stored procedure within SQL Server, although this may take time depending on your TSQL skills.
A second option would be to create an Access database that is on the server in question. This database would have the correct tables from SQL Server linked, and you can then run your code in that database, rather than suffering the lag that you are currently experiencing.
Regards,

GoToRecord works fine, but simpliest way to return value for that record

Part of the issue is opening the table for the record set and having to set focus to the subform. I have been unsuccessful in sorting the table through vba. The goal is to find the MEDIAN value of a table, hence the sorting.
Private Sub cboUser_AfterUpdate()
Dim sourceReset As String
Dim dbMedian As DAO.Database
Dim rsMedian As DAO.Recordset
sourceReset = sbf.SourceObject '<--Is Table.TEMPtable btw.
Me.sbf.SourceObject = ""
Forms!frm.Requery
Forms!frm.Refresh
'Create new TEMPtable
DoCmd.SetWarnings False
DoCmd.OpenQuery "qryTEMPtable" '<--Is sorted here as desired
DoCmd.SetWarnings True
Set dbMedian = CurrentDb()
Set rsMedian = dbMedian.OpenRecordset("TEMPtable") '<--Gets unsorted here
sbf.SourceObject = sourceReset
Me.OrderBy = "NetWrkDays ASC" '<--Re-sorting, but on subform, which.. is
fine if I can return the column value later.
Forms!frm.Refresh
Me.[sbf].SetFocus
Records= DCount("[ColA]", "TEMPtable")
'Even number of records
If Records - 2 * Int(Records / 2) = 0 Then
MEDrcd = Records / 2
DoCmd.GoToRecord , , acGoTo, MEDrcd '<-Can see value in debug, how to
assign it to a useful variable???
''''Me.CurrentRecord ("NetWrkDays")
''''Me.RecordSource ("NetWrkDays")
Me.txtMED = rsMedian("NetWrkDays")
End If
'Odd number of records
If Records - 2 * Int(Records / 2) = 1 Then
MEDrcd1 = (Records - 1) / 2
MEDrcd2 = (Records + 1) / 2
DoCmd.GoToRecord acDataForm, "TempTable", acGoTo, MEDrcd1
MED1 = rsMedian("NetWrkDays")
DoCmd.GoToRecord acDataForm, "TempTable", acGoTo, MEDrcd2
MED2 = rsMedian("NetWrkDays")
Me.txtMED = (MED1 + MED2) / 2
End If
I guess I see no point in trying to use DoCmd.GoToRecord if you cant return the value at that point.
What is the best/correct method for returning a value after moving to a record.
As the subform and table are the same, I just ran with setting focus to the subform as I said was having issue sorting the table in vba. Though then me using rsMedian makes no sense, as the table rs never moves...but I cant retrieve a value for moving though the subform using GoToRecord.
I am going in circles here and i hope is not to garbled to understand. Thank you.
Found this method online. Is working great in case anyone else finds themselves in a similar situation.
Private Sub cboUser_AfterUpdate()
Dim sourceReset As String, sqlMED As String, sTable As String, sField As String
Dim j As Integer, varVal As Single
Dim rs As DAO.Recordset
sourceReset = sbf.SourceObject
Me.sbf.SourceObject = ""
Forms!frmSTATS.Requery
Forms!frmSTATS.Refresh
'Create new TEMPtable table
DoCmd.SetWarnings False
DoCmd.OpenQuery "qryTEMPtable"
DoCmd.SetWarnings True
'Get MEDIAN Data/Value
sTable = "TEMPtable"
sField = "NetWrkDays"
sqlMED = "SELECT " & sField & " from " & sTable & " WHERE " & sField & ">0 Order by " & sField & ";"
Set rs = CurrentDb.OpenRecordset(sqlMED)
rs.MoveLast
j = rs.RecordCount
rs.Move -Int(j / 2)
If j Mod 2 = 1 Then 'odd number of elements
getMedian = rs(sField)
Else 'even number of elements
varVal = rs(sField)
rs.MoveNext
varVal = varVal + rs(sField)
getMedian = varVal / 2
End If
Me.txtAnswer = getMedian
rs.Close
sbf.SourceObject = sourceReset
Me.OrderBy = "NetWrkDays ASC"
Forms!frmSTATS.Refresh
End Sub

There is an issue with my code here, can someone look?

I have a listview box that gets populated with five items. Here's the code that I used to populate it
Dim rs As New ADODB.Recordset
Set rs = New ADODB.Recordset
Dim lvwItem As ListItem
Dim x As Integer
lvwExpenditures.ListItems.Clear
With lvwExpenditures
.FullRowSelect = True
.View = lvwReport
.LabelEdit = lvwManual
.ColumnHeaders.Add , "FldName", "EXPENSES", 2200
.ColumnHeaders.Add , "ID", "ID", 0
End With
g_strSQL = "Select FldName, ID, Label, SortOrder from dbo.tblText_References where fldname ='expenditureitems'"
rs.Open g_strSQL, g_cnDatabase, adOpenStatic
Debug.Print g_strSQL
With rs
Do While Not .EOF
Set lvwItem = lvwExpenditures.ListItems.Add(, , .Fields("Label").Value)
lvwItem.SubItems(1) = .Fields("ID").Value 'Populate Date column
.MoveNext
Loop
End With
Set rs = Nothing
What I'm trying to do is let the user select multiple items, concatenate the items (with a comma) and insert them into a table. Here's the code I have for trying to take the selected items and concatenate them (I built a function), but the issue is, it takes one of the items, and concatonates it three times (when three items were selected in listview). I show the label and save the ID, so the when listview is loaded the ID's go in this order 10,11,12,13,14. On my last try, I selected the top three items and the function converted it to (13,13,13). How do I fix it? I know its a small issue
dim x As Integer
Dim mystring As String
For x = 1 To lvwExpenditures.ListItems.Count
If lvwExpenditures.ListItems(x).Selected = True Then
If x = 1 Then
mystring = lvwExpenditures.SelectedItem.SubItems(1)
Else
mystring = mystring & "," & lvwExpenditures.SelectedItem.SubItems(1)
End If
Else
End If
Next x
dim x As Integer
Dim mystring As String
dim sep as string
sep=", "
For x = 1 To lvwExpenditures.ListItems.Count
If lvwExpenditures.ListItems(x).Selected Then
mystring = mystring & lvwExpenditures.ListItems(x).SubItems(1) & sep
End If
Next x
if mystring<>"" then
mystring=left(mystring,len(mystring)-len(sep)
end if

VBA Access - How to return max/min from multiple fields

I need help with some VBA code in Microsoft Access that will produce the maximum/minimum values for each of the fields below and return with their corresponding case attached
Force Table
case Flxmax Flxmin Frxmax Frxmin
hs00p16010od 582.24 666.81 796.44 -451.15
hs00p16015od 878.7 878.7 1096.3 -500.36
hs00p16020od 1071.95 1071.9 1281.2 -743.05
hs00p16025od 1186.65 1186.6 1397.8 -959.36
Desired Output
Field Force Case
Flxmax 1186.65 hs00p16025od
Flxmin 666.81 hs00p16010od
Frxmax 1397.8 hs00p16025od
Frxmin -959.36 hs00p16025od
In addition, if there are identical max/min values in the table I need to pick just one in the results.
There are 30 additional fields to the ones shown above. I believe that I have to loop through each field till I reach the end and record the max/min row, but I'm unsure how to write this code. Any help would be great.
Current Code
Public Sub Max()
Dim sqlStatement As String
Dim rs1 As Object
Dim rs2 As Object
Dim fld As Field
Dim strName As String
Dim maximum As Long
Dim minimum As Long
sqlStatement = "SELECT * FROM Force;"
Set rs1 = CurrentDb().OpenRecordset(sqlStatement)
sqlStatement = "SELECT * FROM Results;"
Set rs2 = CurrentDb().OpenRecordset(sqlStatement)
rs2.AddNew 'Add new record to result table
'Field order to loop though: max, min, skip, max, min, skip...where skip implies a skipped field
For Each fld In rs1.Fields
With rs1
maximum = DMax(fld, Force)
'Write onto results tables
End With
Next fld
rs2.Update 'Update results table
Set rs1 = Nothing
Set rs2 = Nothing
End Sub
You are quite close. What basically is missing is that every min/max field value must be added/updated separately to the target table.
Revised Code
Public Sub Max()
Dim db As DAO.Database
Dim rs1 As DAO.Recordset
Dim rs2 As DAO.Recordset
Dim fld As DAO.Field
Dim newvalue As Long
Dim newfield As String
Dim newcase As String
Dim sqlStatement As String
Set db = CurrentDb
sqlStatement = "SELECT * FROM Force;"
Set rs1 = db.OpenRecordset(sqlStatement)
sqlStatement = "SELECT * FROM Results;"
Set rs2 = db.OpenRecordset(sqlStatement)
For Each fld In rs1.Fields
rs1.MoveFirst
newfield = fld.Name
If newfield <> "case" Then
newvalue = rs1(newfield).Value
While Not rs1.EOF
If Right(newfield, 3) = "min" Then
If newvalue > rs1(newfield).Value Then
newvalue = rs1(newfield).Value
newcase = rs1("Case").Value
End If
ElseIf Right(newfield, 3) = "max" Then
If newvalue < rs1(newfield).Value Then
newvalue = rs1(newfield).Value
newcase = rs1("Case").Value
End If
End If
rs1.MoveNext
Wend
rs2.AddNew
rs2!Field.Value = newfield
rs2!Force.Value = newvalue
rs2!Case.Value = newcase
rs2.Update
End If
Next fld
Set fld = Nothing
Set rs1 = Nothing
Set rs2 = Nothing
Set db = Nothing
End Sub
This is air code and I don't have test data. You may need to add some error handling.

VBA skipping If statements in Access 2010

I'm trying to make it so that when a user selects a person from a combobox their full details are displayed but some error-handling if statements keep giving false when the conditions should be returning true
Private Sub ComboOwnerID_Change()
Dim SelID As Integer
Dim rs As DAO.Recordset
Dim db As Database
Dim strSQL As String
Dim result As String
SelID = 0
SelID = Me.ComboOwnerID.Text
If Not (SelID = 0) Then
If Not (SelID = Null) Then
Set db = CurrentDb
strSQL = "SELECT * FROM Owners WHERE OwnerID = " + SelID
Set rs = db.OpenRecordset(strSQL)
Do While Not rs.EOF
result = ""
result = rs!Title + ". "
result = result + rs!Forname + " "
result = result + rs!Surname
rs.MoveNext
Loop
Me.lblOwnerName.Caption = result
Else
Me.lblOwnerName.Caption = "error"
End If
Else
Me.lblOwnerName.Caption = "error"
End If
End Sub
It's not even reached the SQL bit yet so i don't know if that works or not
Do not use the .text property in VBA, it is only available when the control has focus. The concatenator in VBA is & not +. Using + when one of the strings is null can return null.
If Not (SelID = Null) Then
Set db = CurrentDb
You mean:
If Not IsNull(SelID) Then
Set db = CurrentDb