How to add database query results to an array - arrays

I am trying to select string values from an Access database and then place them into an array of strings so that I can perform a loop statement on the array.
However I don't know how to place the result of the query into an array. I know how to query the database but all I need is how to put the result in an array.
My select statement is Select motonum from moto. I want to put motonum in an array.
The whole code to read the data is:
connect2()
If Not cnn2.State = ConnectionState.Open Then
'open connection
cnn2.Open()
'MessageBox.Show("chk2")
End If
cmd5.Connection = cnn2
cmd5.CommandText = "Select motonum from moto"
myData5 = cmd5.ExecuteReader
While myData5.Read
'code to return results here
End While`

There are any number of different ways to approach this, depending on the actual needs of your project. First and foremost, I would ask if you actually require a string array as the return type. For most cases, an array is less useful that a List(Of String) or other types which implement IEnumerable.
Here are two options, both of which involve a List(Of String). However, one returns the List to the caller, which can then choose to employ the many useful methods of the List type in working with the data:
THIS is the way I would recommend:
Public Function getListOfMotonum() As List(Of String)
Dim SQL As String = "SELECT motonum FROM moto"
Dim output As New List(Of String)()
' Set the connection string in the Solutions Explorer/Properties/Settings object (double-click)
Using cn = New SqlConnection(Properties.Settings.[Default].MyConnectionString)
Using cmd = New SqlCommand(SQL, cn)
cn.Open()
Try
Dim dr = cmd.ExecuteReader()
While dr.Read()
output.Add(dr("motonum").ToString())
End While
Catch e As SqlException
' Do some logging or something.
MessageBox.Show("There was an error accessing your data. DETAIL: " & e.ToString())
End Try
End Using
End Using
Return output
End Function
Here is a trivial example of code which consumes the output of this function:
Private Sub PrintListToConsole()
Dim MyMotonumList = Me.getListOfMotonum()
For Each item As String In MyMotonumList
Console.WriteLine(item)
Next
End Sub
If your project REQUIRES a string array, the approach may vary. You can return a string from the same function with a couple minor modifications:
' Change the return type in the function signature:
Public Function getArrayOfMotonum() As String()
Dim SQL As String = "SELECT motonum FROM moto"
Dim output As New List(Of String)()
' . . . Same Data Access code as above:
' Just use the .ToArray method of the List class HERE:
Return output.ToArray()
End Function
Or, you can use the same method in your client code, consuming the original function which returns a list:
Private Sub PrintArrayToConsole()
Dim MyMotonumArray = Me.getArrayOfMotonum()
For Each item As String In MyMotonumArray
Console.WriteLine(item)
Next
End Sub
Returning the List from your function provides a more flexible return type, with many useful methods.
As a side note, allow me to recommend the Using block when consuming data access resources. This handles the proper tear down and disposal of the Connection and Command objects for you.

Related

Populating two one-dimensional arrays with text file

For my Visual Basic final, my program is required to read data from a text file into two different arrays, each being one-dimensional. The following is my code for doing so:
Option Explicit On
Option Infer Off
Option Strict On
Public Class frmMain
'Constant for filename and a dirty flag variable
Const INVENTORY_FILENAME As String = "inventory.txt"
Dim noFile As Boolean = False
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Populates DVD listbox with text file data upon load
'Variable for reading the file
Dim myFile As IO.StreamReader
'Declaring arrays for DVD names and prices
Dim arrayDVD() As String
Dim arrayPrice() As Double
'Variables for populating arrays with respective data
Dim dvdName As String
Dim dvdPrice As Double
Dim i As Integer = 0
'Checking that file exists then reading data to each array
If IO.File.Exists(INVENTORY_FILENAME) Then
myFile = IO.File.OpenText(INVENTORY_FILENAME)
'Read data to arrays
Do Until myFile.Peek = -1
dvdName = myFile.ReadLine()
dvdPrice = Double.Parse(myFile.ReadLine())
arrayDVD = dvdName
arrayPrice = dvdPrice
'Using arrays to populate multicolumn listbox
lstDVD.Items.Add(arrayDVD(i) & arrayPrice(i))
i += 1
Loop
'Closing the file
myFile.Close()
End If
End Sub
End Class
The text file alternates names and prices of DVDs to be read as individual lines, making the arrays parallel:
Pulp Fiction
9.99
Jumanji
13.99
And so on...
I'm receiving a value type error code stating that I cannot convert 'String' to 'String()' or convert 'Double' to 'Double()' when setting the arrays' values equal to their respective variables. Is there a way to correct this? Thanks in advance!
These lines are wrong:
arrayDVD = dvdName
arrayPrice = dvdPrice
arrayDVD and arrayPrice are arrays. You need to assign to a specific element in each of those arrays:
arrayDVD(i) = dvdName
arrayPrice(i) = dvdPrice
Don't forget to make sure the arrays actually have enough elements for this.
Hint: ReDim Preserve is pretty much the least efficient way possible to make sure an array is big enough. Each use will allocate a brand new array, copy the elements one at a time, assign the new array to the old reference, and then release the old array. It does not preserve in-place. Nevertheless, if this is a 100-level course it might be what you are expected to do at this point.
Finally, you should never use Double when working with money (use Decimal instead).
Separate from the question, here is how I might approach this without the weird array limitation:
Private Iterator Function ReadInventoryFile(filePath As String) As IEnumerable(Of (String, Decimal))
Using rdr As New StreamReader(filePath)
Dim DVDName As String = Nothing
While (DVDName = rdr.ReadLine()) IsNot Nothing
Yield (DVDName, Decimal.Parse(rdr.ReadLine()))
End While
End Using
End Function
Const INVENTORY_FILENAME As String = "inventory.txt"
Private data As List(Of (String, Decimal))
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try 'Replaces the File.Exists() check
data = ReadInventoryFile(INVENTORY_FILENAME).ToList()
For Each item As (String, Decimal) In data
lstDVD.Items.Add($"{item.Item1}{vbTab}{item.Item2:C}")
Next
Catch
' Actually do something here. Empty catch blocks are rarely correct.
' Note I catch at this level, rather than in the ReadFile() method.
End Try
End Sub

How Do You Return True If A String Contains Any Item In An Array Of String With LINQ in VB.NET

I could not find this question on stack overflow but if it is here, please let me know and I will take it down.
Using LINQ in VB.NET, how do you return True if a string contains one of the items in an array of strings?
This is this is the code in multiple lines. How do you do this in one line with LINQ in VB.NET?
Sub Main
Dim endPointTimeoutText As Array = {"endpoint timeout", "endpoint is not available"}
Dim strResult As String = "endpoint is not available sample text."
Dim booleanResult As Boolean = False
For Each item As String In endPointTimeoutText
If strResult.Contains(item) Then
booleanResult = True
Exit For
End If
Next
Console.WriteLine(booleanResult) 'Only included this for the example
End Sub
The expected result would be 'True' or 'False' depending on if the string (strResult) contained one of the values in the Array Of Strings (endPointTimeoutText)
You turn it around, mentally - don't ask "for this string X, which of these things in this array are in that string", you ask "for this array of strings, which of them are in this one string X":
Dim whichStringsArePresent = endPointTimeoutText.Where(Function(ett) strResult.Contains(ett))
Dim firstImeoutStringFound = endPointTimeoutText.FirstOrDefault(Function(ett) strResult.Contains(ett))
Dim wasATimeout = endPointTimeoutText.Any(Function(ett) strResult.Contains(ett))
etc
By the way it would make your code read more nicely if you make it so that Collections of things have plural names. Consider something more like this:
Dim wasATimeout = endPointTimeoutTexts.Any(Function(ett) strResult.Contains(ett))
It's subtle, but significant in terms of readability
Thank you Caius Jard for your help on this. I am going to post the complete program for what I'm going to use as the answer below.
I needed to use a List instead of an Array so that I could use the 'Any()' method. Thanks again Caius, I really appreciate it!
Sub Main
Dim endPointTimeoutText As String = "endpoint timeout,endpoint is not available"
Dim endPointTimeoutList As New List(Of String)
Dim strResult As String = "endpoint is not available sample text."
endPointTimeoutList = endPointTimeoutText.Split(",").ToList()
Dim areAnyStringsPresent As Boolean
areAnyStringsPresent = endPointTimeoutList.Any(Function(itemInEndPointTimeoutList) strResult.Contains(itemInEndPointTimeoutList))
Console.WriteLine(areAnyStringsPresent)
'This code produces the following output:
'True
End Sub

access an array in a different sub

I have a sub that creates an array and fills it with data, but I would like to use the same array (with the data recorded from previous sub) in a different sub/function. Is there a way to achieve that.
I'm quite new to VBA, so maybe I'm missing something obvious here.
Thanks in advance.
EDIT:
'//FIRST CODE
Dim MyResults() As String
'
'
'Fill MyResults() with data
'
'
Call ComboToText
'//SECOND CODE
Private Sub ComboToText()
'// If there is more than one item in MyResults() use combo box. For one item use Textbox.
Dim n As Long
If UBound(MyResults) > 1 Then
txtPCB.Visible = False
With cmbPCB
.Visible = True
For n = LBound(MyResults) To UBound(MyResults)
.AddItem MyResults(n)
Next n
.Style = fmStyleDropDownCombo
End With
Else
txtPCB.Text = MyResults(1)
End With
End Sub
Whenever I'm trying to run, VBA insists on declaration of MyResults() in second code too. If I declare it again, wouldn't I lose the data that's already in it?
As YowE3K says, you can pass the array as an argument to another sub:
Dim MyResults() As String
'Fill MyResults() with data
Call ComboToText(MyResults)
'//SECOND CODE
Private Sub ComboToText(MyResults() As String)
...
It's fine to use the same name in both Subs, as I did, but you can also use a different name in the second Sub.

Need help getting array to work with string builder

So I am building a stock info retrieval program, and I have a good bit of it done so far. Right now I have it return the price from the Yahoo Finance API by singling out the price in the returned API data and then shove it in a listbox with the stock symbol and price. That part works great, but I want to take it a step further now and be able to do what I want with other parts of that returned data. The normal format for the data is:
"<symbol>", <price>, "<date>", "<time>", etc.
If you take a look at my code, right now I have a Getstockinfo function that retrieves the full API output and converts each object(symbol, price, etc) into a new stringbuilder line, and then separates the lines by the commas using the ModifyLine function.
I want to now get the GetStockInfo to return an array, which would allow me to use that array as I pleased outside of that function(in eventhandlers, etc.)
ANY help would be much appreciated!
Public Function GetStockInfo(ByVal pstrSymbol As String) As String
Dim strURL As String
Dim strApiOutput As String
'Yahoo API
strURL = "http://quote.yahoo.com/d/quotes.csv?" & _
"s=" & pstrSymbol & _
"&d=t" & _
"&f=sl1d1t1c1ohgvj1pp2wern"
strApiOutput = RequestWebData(strURL)
'Create stringbuilder(easier to append, replace and insert data)
Dim strReturn As New System.Text.StringBuilder
'Seperate API output into different lines by using LineFeed
For Each strLine As String In strApiOutput.Split(ControlChars.Lf)
'makes sure line actually exists, if so, seperate and add to array using ModifyLine function
If strLine.Length > 0 Then
strReturn.Append(ModifyLIne(strLine) & Environment.NewLine)
End If
Next
Return strReturn.ToString
End Function
Private Function ModifyLIne(ByVal strLine As String) As String
Dim arrLine() As String
'Splits lines by the commas(the normal api output is as follows: <Obj1>, <Obj2>, <Obj3>, etc
'with Intermediary quotes here and there for certain objects such as Company Name
arrLine = strLine.Split(","c)
decStockPrice = CDec(arrLine(1))
Return decStockPrice.ToString
End Function
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim strSymbol As String = txtSymbol.Text
lstStocks.Items.Add(strSymbol.ToUpper() & " - " & GetStockInfo(strSymbol))
End Sub
I want to take it a step further now and be able to do what I want with other parts of that returned data This will do what you want, just not how you want (arrays are old-school)
Class StockQuote
Public Symbol As String
Public Price As Decimal
Public QuoteDate As DateTime
' etc
End Class
Friend myQuotes As New List(of StockQuote)
Then after you get a quote and determine you want to save it (are you saving all of them?):
Dim SQ as New StockQuote
With SQ
.Symbol = arrLine(0) ' so you can pass an array or list of ticker syms
.Price = Convert.ToDecimal(arrLine(1))
' not much sense saving Time and Date as sep items
' if you are getting multiple quotes for a day (vs ending)
.QuoteDate = combine arrline(2) and arrLine(3) ?
etc
End SQ
myQuotes.Add(SQ)
Now, myQuotes will have a list of all the quotes for all the symbols. Get them like you populated it: txtSym.Text = myQuotes(N).Symbol

Pass stored procedure result to array

Quick question that I'm a bit unsure on how to proceed with an array issue.
Basically I have a stored procedure that outputs some course categories and I want to pass all of the rows to an array.
Subject SubjectCode
Applied Science F04
Access to HE F05
So basically the above is an example of what I get from the stored procedure and I'd like to pass the results of the subject to an array.
Dim num as Integer
Dim strNumResult as String
num = 0
Do While (rsData.Read())
num = num + 1
strNumResult = num.ToString()
Dim array(strNumResult) as String
loop
I'm assuming that I'd need to count the amount of rows in the procedure first, then put this result into the array? How would I then systematically pull all subjects in the procedure into the array?
Thanks!
The easiest would be to use a List(Of Subject) instead which can be resized. I would also create a class for the subject since you have two fields.
Dim subjects = New List(Of Subject)
Using con = New SqlConnection(connectionString)
Using cmd = New SqlCommand("StoredProcedureName", con)
cmd.CommandType = CommandType.StoredProcedure
Try
con.Open()
Using reader = cmd.ExecuteReader()
While reader.Read
Dim subject = reader.GetString(0)
Dim subjectCode = reader.GetString(1)
subjects.Add(New Subject() With {
.Subject = subject,
.SubjectCode = subjectCode
})
End While
End Using
Catch ex As Exception
' log exception
End Try
End Using
End Using
here's a simple implementation of that class:
Public Class Subject
Public Subject As String
Public SubjectCode As String
End Class
If you insist on an array, you can call subjects.ToArray().
You need GetRows method which will get your recordset data into an array:
array = recordset.GetRows(Rows, Start, Fields )
Basically execute your stored procedure and when you have the results use the GetRows method which returns a collection of rows from the result, given an array of unique column ID's.
You can see an example here.
In your case after making sure that you have some records returned you can do this:
arrData = rsData.GetRows()
Hope this helps.

Resources