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.
Related
The objective of the program is to interpret hockey statistics from a file using StreamReader and then display an added column of points. The following code kinda does so, however it’s ineffective in the sense that it doesn’t add the points value to the array - it separately outputs it. Looking for assistance as to how it would be possible to incorporate the points value into aryTextFile();
Dim hockeyFile, LineOfText, aryTextFile() As String
Dim i As Integer
Dim nameText(), NumberText(), goalsText(), assistsText(), GamesWonText() As String
Dim IntAssists(), IntGoals(), PointsText() As Single
hockeyFile = "C:\Users\Bob\Downloads\hockey.txt" 'state location of file
Dim objReader As New System.IO.StreamReader(hockeyFile) 'objReader can read hockeyFile
For i = 0 To objReader.Peek() <> -1 'reads each line seperately, ends when there is no more data to read
LineOfText = objReader.ReadLine 'stores seperate lines of data in HockeyFile into LineofText
aryTextFile = LineOfText.Split(",") 'takes lines and converts data into array
Name = aryTextFile(0) 'first piece of data in lines of text is the name
nameText(i) = aryTextFile(0)
If nameText(0) = "Name" Then
TextBox1.Text = LineOfText & ", Points." & vbCrLf 'displays first line fo text and adds "Points" label
End If
If Name <> "Name" Then 'when second line starts, then begin to intepret data
NumberText(i) = aryTextFile(1)
assistsText(i) = aryTextFile(2) 'assists are in third value of array
goalsText(i) = aryTextFile(3) 'goals are in fourth value of array
GamesWonText(i) = aryTextFile(4)
IntAssists(i) = Val(assistsText(i)) 'since our assists value is a string by default, it must be converted to a integer
IntGoals(i) = Val(goalsText(i)) 'since our goals value is a string by default, it must be converted to a integer
PointsText(i) = (IntGoals(i) * 2) + (IntAssists(i)) 'goals are two points, assists are one point
TextBox1.Text = TextBox1.Text & NumberText(i) & assistsText(i) & goalsText(i) & GamesWonText(i) & PointsText(i) & vbCrLf 'Displays points as last value in each line
End If
Next i
This should get you pretty close:
It'll need extra validation. It doesn't take into account whatever value you have between the name and the goals.
Private Sub ProcessHockeyStats()
Try
Dim inputFile As String = "c:\temp\hockey.txt"
Dim outputFile As String = "c:\temp\output.txt"
If Not File.Exists(inputFile) Then
MessageBox.Show("Missing input file")
Return
End If
If File.Exists(outputFile) Then
File.Delete(outputFile)
End If
Dim lines() As String = File.ReadAllLines(inputFile)
Dim output As List(Of String) = New List(Of String)
Dim firstLine As Boolean = True
For Each line As String In lines
Dim values() As String = line.Split(","c)
Dim points As Integer
If firstLine Then
output.Add("Name, Assists, Goals, Points")
firstLine = False
Else
'needs validation for values
points = CInt(values(1) * 2) + CInt(values(2))
output.Add(String.Concat(line, ",", points))
End If
Next
File.WriteAllLines("c:\temp\outfile.txt", output)
Catch ex As Exception
MessageBox.Show(String.Concat("Error occurred: ", ex.Message))
End Try
End Sub
VS2008 is ancient, especially when later versions of Visual Studio are free. I felt like showing an implementation using more-recent code. Like others, I strongly support building a class for this. The difference is my class is a little smarter, using the Factory pattern for creating instances and a Property to compute Points as needed:
Public Class HockeyPlayer
Public Property Name As String
Public Property Number As String
Public Property Assists As Integer
Public Property Goals As Integer
Public Property Wins As Integer
Public ReadOnly Property Points As Integer
Get
Return (Goals * 2) + Assists
End Get
End Property
Public Shared Function FromCSVLine(line As String) As HockeyPlayer
Dim parts() As String = line.Split(",")
Return New HockeyPlayer With {
.Name = parts(0),
.Number = parts(1),
.Assists = CInt(parts(2)),
.Goals = CInt(parts(3)),
.Wins = CInt(parts(4))
}
End Function
End Class
Dim hockeyFile As String = "C:\Users\Bob\Downloads\hockey.txt"
Dim players = File.ReadLines(hockeyFile).Skip(1).
Select(Function(line) HockeyPlayer.FromCSVLine(line)).
ToList() 'ToList() is optional, but I included it since you asked about an array
Dim result As New StringBuilder("Name, Number, Assists, Goals, Wins, Points")
For Each player In players
result.AppendLine($"{player.Name}, {player.Number}, {player.Assists}, {player.Goals}, {player.Wins}, {player.Points}")
Next player
TextBox1.Text = result.ToString()
I was gonna give you VS 2008 version afterward, but looking at this, the only thing here you couldn't do already even by VS 2010 was string interpolation... you really should upgrade.
Parallel arrays are really not the way to handle this. Create a class or structure to organize the data. Then create a list of the class. The list can be set as the DataSource of a DataGridView which will display your data in nice columns with headings matching the names of your properties in the Hockey class. You can easily order your data in the HockeyList by any of the properties of Hockey.
Public Class Hockey
Public Property Name As String
Public Property Number As String
Public Property Goals As Integer
Public Property Assists As Integer
Public Property Points As Integer
Public Property GamesWon As Integer
End Class
Private HockeyList As New List(Of Hockey)
Private Sub FillListAndDisplay()
Dim path = "C:\Users\Bob\Downloads\hockey.txt"
Dim Lines() = File.ReadAllLines(path)
For Each line As String In Lines
Dim arr() = line.Split(","c)
Dim h As New Hockey()
h.Name = arr(0)
h.Number = arr(1)
h.Assists = CInt(arr(2).Trim)
h.Goals = CInt(arr(3).Trim)
h.GamesWon = CInt(arr(4).Trim)
h.Points = h.Goals * 2 + h.Assists
HockeyList.Add(h)
Next
Dim orderedList = (From scorer In HockeyList Order By scorer.Points Ascending Select scorer).ToList
DataGridView1.DataSource = orderedList
End Sub
In need of your opinions. Currently developing an application in VB.NET.
I have a text file which contains more than one thousand rows. Each rows contains the data needed to be inserted into the database. A sample of a row is as follows:
0001--------SCOMNET--------0.100---0.105
At first glance, one might figured that each column was separated with a tab but actually each column was separated by blank spaces (I used '-' to denote as blank spaces because somehow could not get SO text editor to show the blank spaces).
The first column is defined by
Substring(0, 12) which is the data [0001--------]
second column
Substring(12, 12) in which the data is [SCOMNET-----]
third column is
Substring(24, 8) in which the data is [---0.100]
and last column is
Substring(32, 8) in which the data is [---0.105]
My initial though is to extract the lines for the text file and stored in as a list of strings, then while looping, do the separation of the each string item in the list with the SubString() function and insert it one by one until the end of the list. But this will no doubt takes time.
In my scenario, how can I take advantage of the SqlBulkCopy? Or if there is any other ways to approach this for a faster insert? Say;
open file
start loop
read line
separate each column in the line with substring
save in a DataTable
end loop
BCP(DataTable)
This includes a method that may be a more efficient way of reading your text file.
Sub readFixWidthTextFileIntoSqlTable()
Dim sqlConn As New SqlConnection("Connection String Goes Here")
sqlConn.Open()
Dim sqlComm As New SqlCommand
sqlComm.Connection = sqlConn
sqlComm.CommandType = CommandType.Text
sqlComm.CommandText = "INSERT INTO YourTableNameHere VALUES(#Field1, #Field2, #Field3, #Field4)"
sqlComm.Parameters.Add("#Field1", SqlDbType.Text)
sqlComm.Parameters.Add("#Field2", SqlDbType.Text)
sqlComm.Parameters.Add("#Field3", SqlDbType.Text)
sqlComm.Parameters.Add("#Field4", SqlDbType.Text)
Using IFReader As New FileIO.TextFieldParser(FileNameWithPath)
IFReader.TextFieldType = FileIO.FieldType.FixedWidth
IFReader.SetFieldWidths(12, 12, 8, 8)
While Not IFReader.EndOfData
Dim fields As String() = IFReader.ReadFields
sqlComm.Parameters("#Field1").Value = fields(0)
sqlComm.Parameters("#Field2").Value = fields(1)
sqlComm.Parameters("#Field3").Value = fields(2)
sqlComm.Parameters("#Field4").Value = fields(3)
sqlComm.ExecuteNonQuery()
End While
End Using
sqlConn.Close()
End Sub
You've got it pretty much right. This approach is one that I take a lot. Here's a bit of sample code to get you started. It is ONLY an example, there's absolutely no validation or and no consideration for Primary Keys on the table. If you want to review your question with more details of the structure of the destination table then I can make this example much more specific.
Read_File:
Dim sFileContents As String = ""
Using sRead As New StreamReader("e:\ExampleFile.txt")
sFileContents = sRead.ReadToEnd
End Using
Dim sFileLines() As String = sFileContents.Split(vbCrLf)
Connect_To_DB:
Dim sqlConn As New SqlConnection
sqlConn.ConnectionString = "Data Source=YourServerName;Initial Catalog=YourDbName;Integrated Security=True"
sqlConn.Open()
Setup_DataTable:
Dim ExampleTable As New DataTable
ExampleTable.Load(New SqlCommand("Select Top 0 * From Example_Table", sqlConn).ExecuteReader)
'This is not absolutely necessary but avoids trouble with NOT NULL columns (like keys)'
For Each dcColumn As DataColumn In ExampleTable.Columns : dcColumn.AllowDBNull = True : Next dcColumn
Save_To_DataTable:
For Each sLine In sFileLines
Dim ExampleRow As DataRow = ExampleTable.NewRow
ExampleRow("First_Column_Name") = sLine.Substring(0, 12).TrimEnd
ExampleRow("Second_Column_Name") = sLine.Substring(12, 12).TrimEnd
ExampleRow("Third_Column_Name") = sLine.Substring(24, 8).TrimEnd
ExampleRow("Fourth_Column_Name") = sLine.Substring(32, 8).TrimEnd
ExampleTable.Rows.Add(ExampleRow)
Next
Update_Database:
If ExampleTable.Rows.Count <> 0 Then
Dim sqlBulk As SqlBulkCopy = New SqlBulkCopy(sqlMvConnection)
sqlBulk.DestinationTableName = "Example_Table"
sqlBulk.WriteToServer(ExampleTable)
End If
Disconnect_From_DB:
sqlConn.Close()
Also, as commented on above and if you have access to it SSIS will do this in a jiffy.
How to get all the id numbers in database then store all id numbers to array in vb6?
Or is there another way to store all id numbers in one variable only? Because later in the program, I will use the id numbers one by one.
The GetRows method of an ADO recordset returns an array.
This sample opens the table as a recordset and loads its id values into an array.
Dim rs As Object
Dim varGetRows As Variant
Set rs = CreateObject("ADODB.Recordset")
rs.Open "tblFoo", CurrentProject.Connection
varGetRows = rs.GetRows(, , "id")
I don't know what you want to do with the array, so I'll just examine its values ...
Dim lngUBound As Long
Dim i As Long
lngUBound = UBound(varGetRows, 2)
For i = 0 To lngUBound
Debug.Print varGetRows(0, i)
Next i
If you're interested in something other than an array, you could use a Collection or Dictionary.
I am working on a windows form application, and I have it reading a text file that has information stored in the form of a table. It looks somewhat like this:
ID Name URL
1 client1 client1.com
2 client2 client2.com
3 client3 client3.com
And so on...
What I need to do is get this data to be read from a stream reader, that throws it into a string, including vbtabs and newlines, and then create an array out of that information, so that it acts as a table that I can then later pull information from based on the column names (i.e. ID, Name, URL) and the ID number. I do not have a lot of experience with arrays, so I was hoping to get some help here as how to do this.
The code I have so far for this functionality is:
Dim readCLientTxtListReader As New StreamReader(strReplicationDataClientAccessListPath)
Dim strClientAccessList As String = readCLientTxtListReader.ReadToEnd
Console.Write(strClientAccessList)
readCLientTxtListReader.Close()
Dim i As Integer
Dim aryClientAccessList() As String
aryClientAccessList = strClientAccessList.Split(vbTab)
For i = 0 To UBound(aryClientAccessList)
Console.WriteLine(aryClientAccessList)
Next i
The problem about this is that it just creates a new instance of the array as each individual string of characters between each vbtab. which means, the arrays look like:
ID
Name
URL
1
client1
client1.com
2
client2
client2.com
3
client3
client3.com
Which is not really what I need.
Any ideas?
If you need more info, let me know.
Edit: As an added side-note, I believe multidimensional arrays are what I am looking for, and am currently looking them up now, but if you have any more information on these, I would greatly appreciate it.
The way I am reading your end goal is that you want to have an array that that contains each row of the file and that each row should be an array with the tokens for that row in it. If that is correct, then you could do something like this:
var lines = new List<string[]>();
using (var strReplicationDataClientAccessListPath = new FileStream("path", FileMode.Open))
using (var streamReader = new StreamReader(strReplicationDataClientAccessListPath))
{
while (streamReader.Peek() >= 0)
{
var line = streamReader.ReadLine();
if (!string.IsNullOrEmpty(line))
lines.Add(line.Split('\t'));
}
}
foreach (var line in lines)
{
foreach (var token in line)
Console.Write(token);
Console.WriteLine();
}
I have not done VB in a long time but here is the C# which can be run through a converter to get VB.NET. Also I did it using a List, if you need an array at the end you can do:
lines.ToArray();
This is rclements code
converted to VB
Dim lines = New List(Of String())()
Using strReplicationDataClientAccessListPath = New FileStream("path", FileMode.Open)
Using streamReader = New StreamReader(strReplicationDataClientAccessListPath)
While streamReader.Peek() >= 0
Dim line = streamReader.ReadLine()
If Not String.IsNullOrEmpty(line) Then
lines.Add(line.Split(ControlChars.Tab))
End If
End While
End Using
End Using
For Each line As var In lines
For Each token As var In line
Console.Write(token)
Next
Console.WriteLine()
Next
You are trying to simulate CSV -> DataTable workflow, where vbTab is your CSV delimiter, and DataTable is your storage structure (you can query by field name, and by row index). There are numerous solutions on the internet, just google for CSV to DataTable.
Here is one, linked from here (SO answer).
If you still want multi-dimensional arrays, I recommended a List(Of String()) instead of String(,), because you would then not need to manage memory allocation. Each line of data would be an element of List, and a single dimension array, where column values are array elements 0-N.
To read from file, you can use IO.File.ReadAllLines.
Is it what you need?
'Read Values from the text file and store in a DataTable
Dim dt As New DataTable
Using TextReader As New IO.StreamReader("C:\Data.txt")
Dim Line As String = TextReader.ReadLine
If String.IsNullOrEmpty(Line) Then
MsgBox("No Data")
Exit Sub
End If
With Line.Split(vbTab)
dt.Columns.Add(.GetValue(0))
dt.Columns.Add(.GetValue(1))
dt.Columns.Add(.GetValue(2))
End With
Do
Line = TextReader.ReadLine
If Line Is Nothing Then Exit Do
dt.Rows.Add(Line.Split(vbTab))
Loop
End Using
'Print the DataTable header
For Each Column As DataColumn In dt.Columns
Console.Write(Column.ColumnName & vbTab)
Next
Console.WriteLine(vbCrLf & New String("-", 24))
'Print the DataTable contents
For Each Row As DataRow In dt.Rows
Console.WriteLine(Row("ID") & vbTab & Row("Name") & vbTab & Row("URL"))
Next
I have added another solution using List in case you prefer it more than the DataTable:
'Read Values from the text file and store in a List of type Tuples
Dim Values As New List(Of Tuple(Of String, String, String))
Using TextReader As New IO.StreamReader("C:\Data.txt")
Dim Line As String = TextReader.ReadLine
Do Until Line Is Nothing
With Line.Split(vbTab)
Values.Add(Tuple.Create(.GetValue(0).ToString, .GetValue(1).ToString, .GetValue(2).ToString))
End With
Line = TextReader.ReadLine
Loop
End Using
'Print the List contents
For Each T As Tuple(Of String, String, String) In Values
Console.WriteLine(T.Item1 & vbTab & T.Item2 & vbTab & T.Item3)
Next
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.