Access 2007 VBA Record Set Infinite Loop - ms-access

So I am doing a query that when you click a button it takes a record set with an unassigned field of data and copies that recordset into the same table with a new "assigned version".
I want my database to be able to make different/multiple "assigned versions" from the original unassigned set, and this works great when i create the first assigned set, but when i try to create a new assigned set it goes into a loop that seems completely random, it could create new entries from 10-1000 and i dont know what is causing this.
Sorry if this was confusing, looking at the code will probably help more
thanks!
Dim rs1 As DAO.Recordset
Dim unionquery As String
Dim CURRENT_SOFTWARE_VERSION As String
CURRENT_SOFTWARE_VERSION = Me.Parent.[Software Version].Value
initialquery = "select [Test Script] , [PROC_CHECK_ID], [Software Version] from (FORMAL_CERT_PROCEDURE_TEST_SCRIPTS inner join FORMAL_CERT_PROCEDURE_CHECK on FORMAL_CERT_PROCEDURE_TEST_SCRIPTS.TEST_CASE_ID = FORMAL_CERT_PROCEDURE_CHECK.TEST_CASE_ID) inner join FORMAL_CERT_SOFTWARE_VERSION on FORMAL_CERT_PROCEDURE_TEST_SCRIPTS.TEST_CASE_ID = FORMAL_CERT_SOFTWARE_VERSION.TEST_CASE_ID where PROC_CHECK_ID=" & Me.PROC_CHECK_ID & " AND [Software Version]=""" & CURRENT_SOFTWARE_VERSION & """ "
Set rs1 = CurrentDb.OpenRecordset(initialquery, dbOpenForwardOnly)
Do Until rs1.EOF = True
Dim rs2 As DAO.Recordset
Set rs2 = CurrentDb.OpenRecordset( _
"SELECT * FROM FORMAL_CERT_PROCEDURE_TEST_SCRIPTS", _
dbOpenDynaset)
rs2.AddNew
rs2![Test Script] = rs1![Test Script]
rs2![PROC_CHECK_ID_FK] = rs1!PROC_CHECK_ID
rs2![Software_Version] = rs1![Software Version].Value
rs2![TEST_CASE_ID] = Me.TEST_CASE_ID
rs2.Update
rs2.Close
Set rs2 = Nothing
rs1.MoveNext
Loop

Oh dear.
If you add records into the table you are currently iterating through, you will have problems in reaching EOF, since you are not only iterating through what you started with, but also the new records that you just added.
The solution is to separate the loop and the insert into discrete steps: loop through and save the values you want to insert, then insert after the loop is finished.
Assuming the values are string, numeric, string, numeric:
Set rs1 = CurrentDb.OpenRecordset(initialquery, dbOpenForwardOnly)
dim strQuery() as String
dim intCounter as Long
dim recordCount as Long
intCounter = 0
rs1.MoveLast
recordCount = rs1.RecordCount
Redim strQuery(0 to recordCount)
rs1.MoveFirst
strQuery(0) = "INSERT INTO FORMAL_CERT_PROCEDURE_TEST_SCRIPTS ([Test Script],[PROC_CHECK_ID_FK],[Software_Version],[TEST_CASE_ID]) VALUES "
Do Until rs1.EOF = True
intCounter = intCounter + 1
strQuery(intCounter) = strQuery(0) & " ('" & rs1![Test Script] & "'," & _
& rs1!PROC_CHECK_ID & "," & _
& "'" & rs1![Software Version].Value & "'," & _
& Me.TEST_CASE_ID & ")"
rs1.MoveNext
Loop
For intCounter = 0 To recordCount
CurrentDb.Execute(strQuery(intCounter))
Next
This will avoid the issue of the EOF pointer moving further away as you insert.
Edit: I forgot you can't do multiple inserts with default DBA, I changed the code to reflect that.

Related

Update syntax error in the WHERE clause

Generating a Report from Query; capturing data from several tables. The Report has two calculated boxes and I want to UPDATE the data back to one of the tables. Debugging shows I'm capturing the variables but keeps giving me Syntax errors in the WHERE clause. I've tried lots of syntax iterations from scouring the net.
Private Sub Report_Load()
Dim sqls As String
Dim TEP As Single
Dim PPS As Single
Dim RecipeN As String
TEP = Reports![RecipeBuild]![txtTEP]
PPS = Reports![RecipeBuild]![txtPPS]
RecipeN = Reports![RecipeBuild]![RecipeName]
sqls = "Update [tblRecipeBuild] " _
& "Set TEP = " & TEP & " " _
& "Set PPS = " & PPS & " " _
& "WHERE [RecipeName] = '" & RecipeN & "';"
DoCmd.SetWarnings False
DoCmd.RunSQL sqls
DoCmd.SetWarnings True
End Sub
An Access SQL UPDATE should include the SET keyword only once.
When you want to update more than one field, use SET once, and then use a comma between the pairs of FieldName=Value segments.
sqls = "Update [tblRecipeBuild] " _
& "Set TEP = " & TEP & ", PPS = " & PPS & " " _
& "WHERE [RecipeName] = '" & RecipeN & "';"
I think that should work but suggest you consider a parameter query instead of concatenating values into an UPDATE statement.
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strUpdate As String
strUpdate = "UPDATE tblRecipeBuild SET TEP=pTEP, PPS=pPPS WHERE RecipeName=pRecipeN;"
Debug.Print strUpdate
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strUpdate)
With qdf
.Parameters("pTEP").Value = TEP
.Parameters("pPPS").Value = PPS
.Parameters("pRecipeN").Value = RecipeN
End With
qdf.Execute dbFailOnError

Adding a third level to treeview active x control using VBA in MS Access 2010

I have the following VBA code which populates a treeview control with the parent table Groups and then the child table Categories, I also have a child to categories named Section. I would like to be able to add a third level to my treeview control, so I can display section. However, I don't know how to do this correctly. Any help on this subject would be greatly appreciated.
I am trying to use the same method of adding a child level as I have done with the group and categories; but unsuccessfully so far.
I am not sure if my original code is entirely correct, but it appears to work ok.
I am using Microsoft treeview control version 6.0, if that makes any difference.
Private Sub Form_Load()
Dim nodX As Node
Dim MyDB As DAO.Database
Dim MyRS As DAO.Recordset
Dim MyRSChild As DAO.Recordset
Dim strSQL As String
Set MyDB = CurrentDb()
Set MyRS = MyDB.OpenRecordset("SELECT * FROM Prt_Group ORDER BY Group_Number", dbOpenDynaset)
Set nodX = Treeview1.Nodes.Add(, , , "Parts List Treeview")
'Populate grp Nodes
Do While Not MyRS.EOF
Set nodX = Treeview1.Nodes.Add(1, tvwChild, "Group" & MyRS![PartGroupID], MyRS![Group_Number] & " - " & MyRS![Group_Description])
nodX.EnsureVisible
MyRS.MoveNext
Loop
strSQL = "Select * From Prt_Category ORDER BY PartCat_Number"
Set MyRSChild = MyDB.OpenRecordset(strSQL, dbOpenSnapshot)
'Populate category Nodes
Do While Not MyRSChild.EOF
Set nodX = Treeview1.Nodes.Add("Group" & MyRSChild![PartGroupID], tvwChild, "A" & CStr(MyRSChild![PartCatID]), _
" " & MyRSChild![PartCat_Number] & " - " & _
MyRSChild![PartCat_Description])
MyRSChild.MoveNext
Loop
MyRSChild.Close
MyRS.Close
Set MyRSChild = Nothing
Set MyRS = Nothing
End Sub
Having not enough information to provide a full answer I just can help you a little with this:
Private Sub Form_Load()
'.....
'Populate category Nodes
Do While Not MyRSChild.EOF
Set nodX = Treeview1.Nodes.Add("Group" & MyRSChild![PartGroupID], tvwChild, "A" & CStr(MyRSChild![PartCatID]), _
" " & MyRSChild![PartCat_Number] & " - " & _
MyRSChild![PartCat_Description])
'insert third level node begins here
'Maybe do a dataset operation on "Section table" and a while loop
Treeview1.Nodes.Add nodx, tvwChild, "KEYOFSECTION", "LABELOFSECTION"
MyRSChild.MoveNext
Loop
'...
End Sub
Change "KEYOFSECTION" with a unique key and "LABELOFSECTION" with an appropriate Section label
I have used the following code that successfully works. I'm not sure if it is the most efficient way of coding this, but it does work. This page helped me understand the node object.
Private Sub Form_Load()
Dim nodX As Node
Dim MyDB As DAO.Database
Dim MyRS As DAO.Recordset
Dim MyRSChild As DAO.Recordset
Dim strSQL As String
Set MyDB = CurrentDb()
Set MyRS = MyDB.OpenRecordset("SELECT * FROM Prt_Group ORDER BY Group_Number asc", dbOpenDynaset)
Set nodX = Treeview1.Nodes.Add(, , , "Groups/Categories/Sections Treeview")
'Populate grp Nodes
Do While Not MyRS.EOF
Set nodX = Treeview1.Nodes.Add(1, tvwChild, "Group" & MyRS![PartGroupID], MyRS![Group_Number] & " - " & MyRS![Group_Description])
nodX.EnsureVisible
MyRS.MoveNext
Loop
strSQL = "Select * From Prt_Category ORDER BY PartCat_Number ASC"
Set MyRSChild = MyDB.OpenRecordset(strSQL, dbOpenSnapshot)
'Populate category Nodes
Do While Not MyRSChild.EOF
Set nodX = Treeview1.Nodes.Add("Group" & MyRSChild![PartGroupID], tvwChild, "A" & CStr(MyRSChild![PartCatID]), _
" " & MyRSChild![PartCat_Number] & " - " & _
MyRSChild![PartCat_Description])
MyRSChild.MoveNext
Loop
'-------------------NEW CODE FOR THIRD LEVEL----------------------------
Dim strSQL1 As String
Dim myRSChild1 As DAO.Recordset
strSQL1 = "Select * From Prt_Section ORDER BY Section_Number"
Set myRSChild1 = MyDB.OpenRecordset(strSQL1, dbOpenSnapshot)
Do While Not myRSChild1.EOF
Set nodX = Treeview1.Nodes.Add("A" & CStr(myRSChild1![PartCatID]), tvwChild, "B" & CStr(myRSChild1![SectionID]), _
" " & myRSChild1![Section_Number] & " - " & _
myRSChild1![Section_Description])
myRSChild1.MoveNext
Loop
'------------- END OF ADDITIONAL CODE-----------------------
'Root Text Bold
Treeview1.Nodes(1).Bold = True
MyRSChild.Close
MyRS.Close
myRSChild1.Close
Set MyRSChild = Nothing
Set MyRS = Nothing
Set myRSChild1 = Nothing
end sub

Error on a recordset, but same SQL works elsewhere

Error: "Run-time error '3061' Too few parameters. Expected 2.
I wrote this simple function that returns the remaining percentage calculated for number of records changed. It is supposed to occur when the user updates the field called 'percentage' I am certain the code below should work, but obviously something is wrong. It occurs on the line:
Set rs = db.OpenRecordset("SELECT Tier1, [Percentage], Tier3 AS Battalion, Month " _
& "FROM tbl_CustomPercent " _
& "WHERE (((Tier1)=[Forms]![frmEntry]![cmbImport_T1]) AND ((Month)=[Forms]![frmEntry]![cmbMonth]));", dbOpenSnapshot)
I wonder how it could fail when the very same query is what populates the 'record source' for the form with the 'percentage' textbox.
Function RemainingPercentAvailable() As String
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT Tier1, [Percentage], Tier3 AS Battalion, Month " _
& "FROM tbl_CustomPercent " _
& "WHERE (((Tier1)=[Forms]![frmEntry]![cmbImport_T1]) AND ((Month)=[Forms]![frmEntry]![cmbMonth]));", dbOpenSnapshot)
Dim CurrentTotal As Single
CurrentTotal = 0
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst
Do Until rs.EOF = True
CurrentTotal = CurrentTotal + rs!Percentage
rs.MoveNext
Loop
End If
RemainingPercentAvailable = "Remaing available: " & Format(1 - CurrentTotal, "0.000%")
Set rs = Nothing
Set db = Nothing
End Function
Adapt your code to use the SELECT statement with a QueryDef, supply values for the parameters, and then open the recordset from the QueryDef.
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strSQL As String
strSQL = "SELECT Tier1, [Percentage], Tier3 AS Battalion, [Month] " _
& "FROM tbl_CustomPercent " _
& "WHERE (((Tier1)=[Forms]![frmEntry]![cmbImport_T1]) AND (([Month])=[Forms]![frmEntry]![cmbMonth]));"
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strSQL )
' supply values for the 2 parameters ...
qdf.Parameters(0).Value = Eval(qdf.Parameters(0).Name)
qdf.Parameters(1).Value = Eval(qdf.Parameters(1).Name)
Set rs = qdf.OpenRecordset
Note: Month is a reserved word. Although that name apparently caused no problems before, I enclosed it in square brackets so the db engine can not confuse the field name with the Month function. It may be an unneeded precaution here, but it's difficult to predict exactly when reserved words will create problems. Actually, it's better to avoid them entirely if possible.
This one is calling a query directly in a DAO.Recordset and it works just fine.
Note the same 'Set rs = db.OpenRecordset(strSQL, dbOpenDynaset) This is a parameter SQL as well.
The only difference is with this one is that I DIDN'T need to move through and analyze the recordset - but the error occurs on the 'Set rs = " line, so I wasn't able to get further anyway.
Dim rs As DAO.Recordset
Dim db As DAO.Database
Dim strSQL As String
strSQL = "SELECT Sum(tbl_SP.AFP) AS AFP_TOTAL, tbl_SP.T1_UNIT " _
& "FROM tbl_SP " _
& "GROUP BY tbl_SP.T1_UNIT " _
& "HAVING (((tbl_SP.T1_UNIT)='" & strUnit & "'));"
Set db = CurrentDb
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
AFP_Total = rs!AFP_Total
There is an even simpler way to calculate the total percentage.
Instead of looping through the records, you can use the DSum() function.
Note that DSum will return Null if there are no records, so you need to wrap it in Nz().
Just for fun, here is your function but written as one single statement:
Function RemainingPercentAvailable() As String
RemainingPercentAvailable = "Remaining available: " & Format(1 - _
Nz(DSum("Percentage", _
"tbl_CustomPercent", _
"Tier1 = " & QString(cmbImport_T1) & _
" AND [Month] = " & QString(cmbMonth))) _
, "0.000%")
End Function
I don't recommend building a temporary parameterized query in VBA, because it makes the code too complicated. And slower. I prefer to build "pure" SQL that will run directly in the db engine without any callbacks to Access. I'm assuming that your function is defined in the frmEntry form, and that cmbImport_T1 and cmbMonth are string fields. If they are numeric, omit qString().
Here is my version of your function. It handles the empty-recordset case correctly.
Function RemainingPercentAvailable() As String
Dim CurrentTotal As Double, q As String
q = "SELECT Percentage" & _
" FROM tbl_CustomPercent" & _
" WHERE Tier1 = " & QString(cmbImport_T1) & _
" AND [Month] = " & QString(cmbMonth)
CurrentTotal = 0
With CurrentDb.OpenRecordset(q)
While Not .EOF
CurrentTotal = CurrentTotal + .Fields("Percentage")
.MoveNext
Wend
End With
RemainingPercentAvailable = "Remaining available: " & _
Format(1 - CurrentTotal, "0.000%")
End Function
' Return string S quoted, with quotes escaped, for building SQL.
Public Function QString(ByVal S As String) As String
QString = "'" & Replace(S, "'", "''") & "'"
End Function

Access VBA: How to move past 'No Current Record' to next Record where 'Item' = 'Item'

How do I move past 'No Current Record' to next Record where 'Item' = 'Item'
Loop comes back around and finds a Sales Order record in rsSO but not in rsInv or the Inventory recordset, creating the "Record not found error." The reason is that once the Inventory is depleted by allocating it to open Sales Orders I then delete the Inventory record for that specific item but there still may me open sales order left for that item. How do I move to the next item in the Open Sales Order rsSO recordset once the Inventory is depleted in rsInv?
It is happening in the following section of code inside the first loop:
Do Until rsInv!Item = rsSO!Item
If rsInv!Item = rsSO!Item Then
Exit Do
Else
rsInv.MoveNext
End If
Loop
Entire code:
Public Function UpdateInventoryIntl()
Dim rsInv As DAO.Recordset, rsSO As DAO.Recordset, db As DAO.Database
Dim qdf As DAO.QueryDef
Dim AllocationQty As Long, SaleOrderRemainder As Long
Set db = CurrentDb
Set rsInv = CurrentDb.OpenRecordset( _
"SELECT * FROM [tbl_InventoryAvailForIntl] ORDER BY [Item] DESC,[QOH_IntlAllocation] DESC", _
dbOpenDynaset)
Set rsSO = CurrentDb.OpenRecordset("SELECT * FROM [tbl_IntlAllocated] ORDER BY [Item] DESC,[Qty_Open] DESC", _
dbOpenDynaset)
Do Until rsSO.RecordCount = 0
Do Until rsInv!Item = rsSO!Item
If rsInv!Item = rsSO!Item Then
Exit Do
Else
rsInv.MoveNext
End If
Loop
AllocationQty = IIf(rsSO!Qty_Open > rsInv!QOH_IntlAllocation, rsInv!QOH_IntlAllocation, rsSO!Qty_Open)
db.Execute ("INSERT INTO tbl_IntlAllocatedResults (Due_Date, Sale_Order_Num, SO_Line, Item, Qty_OpenStart, Location, Lot, QtyAllocated) " & _
"VALUES (#" & rsSO!Due_Date & "#,'" & rsSO!Sale_Order_Num & "'," & rsSO!SO_Line & ",'" & rsSO!Item & "'," & rsSO!Qty_OpenStart & ",'" & rsInv!Location & "','" & rsInv!Lot & "'," & AllocationQty & ");")
rsSO.Edit
rsSO!Qty_Open = rsSO!Qty_Open - AllocationQty
rsSO.Update
If rsSO!Qty_Open = 0 Then
rsSO.Delete
rsSO.MoveNext
End If
rsInv.Edit
rsInv!QOH_IntlAllocation = rsInv!QOH_IntlAllocation - AllocationQty
rsInv.Update
Debug.Print rsInv!QOH_IntlAllocation
If rsInv!QOH_IntlAllocation = 0 Then
rsInv.Delete
rsInv.MoveNext
End If
Loop
rsSO.Close
Set rsSO = Nothing
Set qdf = Nothing
rsInv.Close
Set rsInv = Nothing
End Function
Rather than cycling through the recordset use FindFirst:
Dim sCriteria as String
sCriteria = "Item = " & rsSO!Item
rsInv.FindFirst (sCriteria)
If rsInv.NoMatch Then
' Do whatever you need to if there is no inventory
Else
' Carry on with your code
End If
You may get better efficiency picking up the recordset as you need it, depending on the size of recordset.
Don't set your rsInv initially and then instead of your problematic loop use:
Set rsInv = Currentdb.OpenRecordset( _
"SELECT * FROM [tbl_InventoryAvailForIntl] _
WHERE [Item] = " & rsSO!Item & " ORDER BY [QOH_IntlAllocation] DESC", _
dbOpenDynaset)
You can then test if there are no records:
If rsInv.EOF and rsInv.BOF Then
' No records, do what is required when no inventory
End If

Simple access query

I'm trying to create a query in Access.
Let's say, for example, I have four fields: Numbers 1-26, Letters A-Z, 26 Names, and 26 Cities, so one record might be: 2, B, Jane, New York
I want to create and save a new query with:
the numbers field, the letters field, and the names field. I want the letters field to be filtered on "A" or "B", and the names field to have an expression so it's always 0.
This will become a loop, so it'll create 13 queries (A/B, C/D, etc).
It seems like having this process in VBA as opposed to the Access macro builder would be better since not only do I have to loop this process, but there are also 2 similar tables (same field names, different values) that I need to run it on.
You can run your queries in VBA using a recordset and then work with the data from there:
Sub YourQueries(ByVal pstrCol1 As String, ByVal pstrCol2 As String, ByVal pstrCol3 As String, ByVal pstrCol4 As String)
Dim rs As Recordset
Dim strSQL As String
' Change types above to match what's actually in the table
strSQL = "SELECT YourColumn1, YourColumn2, YourColumn3, YourColumn4 "
strSQL = strSQL & " WHERE "
strSQL = strSQL & "YourColumn1='" & pstrCol1 & "'"
strSQL = strSQL & " AND YourColumn1='" & pstrCol1 & "'"
strSQL = strSQL & " AND YourColumn1='" & pstrCol1 & "'"
strSQL = strSQL & " AND YourColumn1='" & pstrCol1 & "'"
Set rs = CurrentDb.OpenRecordset(strSQL, dbOpenSnapshot)
While Not rs.EOF
For i = 0 To 3
Debug.Print rs.Fields(i) & " is Column" & Format(i)
Next i
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
End Sub