How to get every record in a Recordset in VB? - vb.net

Hey here my problems i'm calling a stored proc and I put the record into an ADODB RecordSet.
When i Check the field.count its say i got 6 result which is good. But when i try to loop into that record set it skips one of them. Heres my code
oRs = g_oSQL.GetRecords("PS_palFetchAllPalette_sel")
If Not oRs Is Nothing Then
cmbPallet.Items.Clear()
oRs.MoveFirst()
While Not oRs.EOF
If oRs.Fields.Item("palcode").Value.ToString() <> "None" Then
cmbPallet.Items.Add(oRs.Fields.Item("palcode").Value.ToString())
End If
oRs.MoveNext()
End While

I think what happens is when you reach your last record with oRs.MoveNext() then you are at EOF so next loop won't happen. try to change the structure of the loop.
With oRs
Do Until .EOF
'get your data
.MoveNext
Loop
End With

I haven't worked with ADODB for a while but wouldn't field.count indicate the number of fields in the recordset and not the number of records returned? You could have returned 0 records but still have the metadata on the query.
Are you sure your check for "None" is working? This would require that palcode not ne empty or Null but have the actual value of "None." Set a breakpoint inside the While loop and see if your are getting what you expected.

Related

How to insert Listbox items in MS Access database in a single row

I have the following code:
Try
Dim queryString As String
queryString = "Insert into ServiceRecords([Personnel]) Values(#Personnels)"
command1 = New OleDbCommand(queryString, connection)
For i As Integer = 0 To Me.ListBox1.Items.Count + 1
command1.Parameters.AddWithValue("Personnels", ListBox1.Items(i))
command1.Parameters.Clear()
command1.ExecuteNonQuery()
Next
Catch ex As Exception
End Try
But I get the error below, and I don't know how to fix it. I think it happens because of my code.
And this is what I get:
Let's review.
First, as muffi suggested, use the Add method instead of .AddWithValue but instead of DBType use OLEDBType. There is not .String type in OleDBType. You will have to check your Access db to get the correct datatype. Probably VarChar. In addition, the parameter name should match the parameter name in your query string. With Access the position is the important thing but with other databases the name matters.
Second, as Charles suggested, change the plus one to minus 1. Most people start counting at one but computers usually start at zero so the upper index of the ListBox is one less than the Count (remember you are starting at zero not one).
Third , as Charles also pointed out it is wrong to clear the parameters before you execute. Then you would have nothing in your parameter. It is not necessary to clear them at all because you are overwriting the Value property with each iteration of your loop and I have set the name and datatype outside the loop because they stay the same. We don't want to reset properties for each iteration when they don't change.
command1.Parameters.Add("#Personnels", OleDbType.VarChar)
For i As Integer = 0 To ListBox1.Count -1
command1.Parameters("#Personnels").Value = ListBox1.Items(i)
command1.ExecuteNonQuery
Next

How to debug.print a query result from the query design in VBA /Access

I want to execute a predefined query from access via VBA and print it to the debug output. The name of the query design is in a variable named report.
I was expecting that it would work with:
debug.print db.Execute report
But everytime vba autocorrects it to:
debug.print db.Execute; report
If I understand it correctly, the ; stands for a new line and makes therefore no sense in my case. But in both cases, with and without the new line I get an error. I assume that the simple problem is, that this is not the right syntax.
I could find a lot of information about how to debug print a query that is created as a string in VBA, but I can't find any hints how to output a query that is predefined in Access via a query design.
Try either:
'// You need the parentheses because the result has to be evaluated before it can be passed to the .Print() method
Debug.Print db.Execute(result)
or
Dim myResult As String
myResult = db.Execute(result)
Debug.Print myResult
In VBA you can pass arguments to a procedure/method without using parentheses, as long as the result isn't being being assigned to anything.
'// Not assigning anything
MyExampleFunction arg1, arg2, arg3
'// assigning the result, which needs to be evaluated before it can be passed to a variable.
MyResult = MyExampleFunction(arg1, arg2, arg3)
In the same way, when you call Debug.Print it assumes that db.Execute and result are actually separate arguments (it has no way of knowing that you want result to be passed to db.Execute first because there's nothing in your syntax to state that). So you have to use parentheses to let it know.
It seems as the problem was that it is only possible to call updates with db.Execute and not queries.
There is no good solution to print a whole table from a query with debug.print but using a RecordSet as seen in the following code is a possible way.
Dim rs As DAO.RecordSet
Set rs = db.OpenRecordset(Bericht)
Do Until rs.EOF = True
Debug.Print rs("Matrikelnummer"), rs("Bewertung"), rs("Termin (Datum)"), rs("Maximale Bewertung"), rs("Bestehensgrenze"), rs("Versuch"), rs("Äquivalenzleistung")
rs.MoveNext
Loop
rs.Close
Set rs = Nothing

Loop through recordset data 10 records at a time and add to array

Context: I am writing a Google Maps API in my Microsoft Access database which takes postcodes in a table and sends them over to Google as part of a HTTP GET request. To make my requests more efficient, I am trying to batch 10 postcodes together at a time to send over to Google. I have chosen 10 as Google has a 2000 character limit in it's GET API requests.
Exam Question: Using DAO recordsets, how do I loop through my Postcodes table, 10 records at a time and add those 10 records to an array, until I reach the end of the table? So in essence, get 10 records from the table, add them to an array, then clear the array, then get the next 10 records and add them to the array, then clear the array...until I reach the end of the table.
My basic code so far is:
Public Function CalcGeoData()
Dim rs As DAO.Recordset
Dim Postcodes(0 To 10) As String
' Begin to loop through the Postcodes in I_Postcodes and update for distance and time from base
Set rs = CurrentDb.OpenRecordset("Postcodes")
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst
Do Until rs.EOF = True
Debug.Print (rs!Postcode)
Debug.Print "-----------"
rs.Move 10
Loop
End If
rs.Close
Set rs = Nothing
End Function
Inside your loop:
Create another loop from i = 1 to 10. Inside that loop:
Add the values from the current record to myArray(i).
Special case: If the end of the recordset is reached, clear the remaining array entries.
Send the array to Google (or do whatever else you want to do with it).
Translating this to code is left as an exercise.
Note: You might want to consider using a VBA Collection instead of an array, which has a useful Add method.
Use the GetRows method: Moving through the Recordset in Access VBA
Put it inside a loop where you pull 10 records (not RecordCount as shown) in each loop until no more records.

VBA collection with 2 or more fields

I'm using a Collection to store data from a recordset in VBA. The recordset has two fields.
I'm using a collection because I want to utilise its ability to prevent duplicates by using the key parameter. I'm running an SQL query to generate the recordset many times and a lot of the results will be identical to the previous, but some will be different. I want to capture a collection of the unique results from each recordset.
I can do this currently using the following:
rs.Open sql_vehicles, cn
If rs.RecordCount > 0 Then
Do While Not rs.EOF
On Error Resume Next
value = rs.Fields("EVN").value
catalogue_Tags.Add Item:=value, Key:=value
rs.MoveNext
On Error GoTo 0
Loop
End If
which all resides in a for loop generating a new recordset each time which may or may not be different.
This will give me a collection with unique values from the "EVN" field in the recordset, but I need to be able to store the second field in the recordset as well, but I want to still avoid duplicates of the EVN field!
Any ideas on how to do this?
Seems to me you can just use 2 collections to get 2 unique lists...
value = rs.Fields("EVN").value
catalogue_Tags_EVN.Add Item:=value, Key:=value
value = rs.Fields("ABC").value
catalogue_Tags_ABC.Add Item:=value, Key:=value
I just notice your requirement is slightly different then I read the first time...
Add "Microsoft Scripting Runtime" reference to your project and use a dictionary of dictionaries.
Dim evnValues as new Scripting.Dictionary ' this will actually be a dictionary of dictionaries.
inside the loop do this...
ABCvalue = rs.Fields("ABC").value
if not evnValues.Exists(value) then
' sub dictionary does not exist yet. initialize the list for this evn value
evnValues(value)=New Scripting.Dictionary
end if
evnValues(value).item(ABCValue)=ABCValue ' accumulate a list of the ABCValues relative to the unique evnValue.
At the end you will have a dictionary with the Names of the top level being your unique EVN values and the sub value will be a collection of 1 or more ABC values.

recordset.movefirst "Rowset position cannot be restarted"

I have a function that runs a stored procedure that returns only a single row and column (so one result).
I'm trying to get that one result into a variable so I can return it. I'm trying to use recordset.MoveFirst but I get the "Rowset position cannot be restarted." error. I tried just removing it, since I only have one result, but I then get an overflow. My statement looks like this:
If recordset.EOF = False Then
recordset.MoveFirst
temp = rs!ID
End IF
temp is an integer. I've checked the stored procedure to make sure it only returns the single result, and it does. Am I doing something wrong? Is there a better way to pass the result into a variable? It's possible the recordset is forward only (which means it's read only?) but I can't seem to find an answer as to how to fix that.
There is usually no reason to MoveFirst if you have not previously navigated the record set.
The overflow is unrelated to the database code and is caused by rs!ID not fitting in a VBA integer (16 bit) so make temp a Long instead (32 bit) and remove MoveFirst.
Make sure you are not using a forward-only recordset. Recordsets are this way by default. Instead use a dynamic (adOpenDynamic) or static (adOpenStatic) cursor type.
You may also need to set CursorLocation = adUseClient.
Finally, check for BOF before calling MoveFirst.
Example:
...
rs.CursorType = adOpenStatic
rs.CursorLocation = adUseClient
rs.Open "SELECT * FROM MyTable"
...
If (Not rs.BOF) Then
rs.MoveFirst
End If
You can use MoveFirst for forward only recordset ONLY when you are at EOF.
Tricky, undocumented, but WORKS!!!!