Return array of ListViewItem to Sub - sql

I want to make a chart with several series on it. Every series belongs to a particular person.
First I read out the number of different persons in my table in Access:
connection.Open()
command.CommandText = "SELECT kontoverlauf_kunden_id FROM kontoverlauf GROUP BY kontoverlauf_kunden_id"
Dim kunden_id_array As New ArrayList()
reader = command.ExecuteReader()
Do While reader.Read()
kunden_id_array.Add(reader("kontoverlauf_kunden_id").ToString())
Loop
reader.Close()
connection.Close()
Now I have the different persons (the ID of them).
Second I add the series i need to the chart:
For counter As Integer = 0 To kunden_id_array.Count - 1
chartKontoverlauf.Series.Add(New Series("Konto [" & kunden_id_array.Item(counter) & "]"))
chartKontoverlauf.Series(counter).ChartType = SeriesChartType.Line
chartKontoverlauf.Series(counter).Color = Color.Red
chartKontoverlauf.Series(counter).BorderWidth = 3
Next
Now I just need to fill in the points I need, but that's kinda tricky.
I've made a function that will call every time and it reads out the values (money and time) for the particular person. Here's the function first:
Function DatenAuslesen(ByVal kunden_id As Integer) As ListViewItem
Dim lstViewItem As New ListViewItem
Try
connection.Open()
command.CommandText = "SELECT * FROM kontoverlauf WHERE kontoverlauf_kunden_id = " & kunden_id
reader = command.ExecuteReader()
Do While reader.Read()
lstViewItem.SubItems.Add(reader("kontoverlauf_wert").ToString())
lstViewItem.SubItems.Add(reader("kontoverlauf_datum").ToString())
Loop
reader.Close()
connection.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
connection.Close()
Return lstViewItem
End Function
To add the points now, I wrote this little thing:
For counter As Integer = 0 To kunden_id_array.Count - 1
For counter_2 As Integer = 0 To DatenAuslesen(kunden_id_array.Item(counter)).ListView.Items.Count - 1
chartKontoverlauf.Series(counter).Points.AddXY(DatenAuslesen(kunden_id_array.Item(counter)).ListView.Items(counter_2).SubItems(0).Text, DatenAuslesen(kunden_id_array.Item(counter)).ListView.Items(counter_2).SubItems(1).Text)
Next
Next
The problem with the thing is that it just gives me one of the values I need back, and not all. I can't access alle values properly. I'm still not sure if it's even the best variable to do this. I would need an array of ListViewItems to add all of them but I didn't found how to do this.
Maybe anyone has an idea?
Thank you!

Related

Having trouble getting the average for duration in (mm:ss)

For all who assist with this, thank you. My goal is to get the duration of chat conversations for my employees and then calculate their year average. The data is being inserted into a database as short text in the format of (mm:ss or 18:30). I have tried converting and parsing the data several different ways and I have looked through numerous explanations and solutions on SO.com so far with nothing working the way I would like. The below is my display procedure to bring the data into the form. I know I could have done this in an easier way, but I am fairly new to VB.net and coding in general.
Private Sub DisplayJanMetrics()
'Open a connection to the database and then assign the values from the appropriate metric columns to the appropriate labels.
Dim str As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\CoachingDB.accdb"
Dim conn As New OleDbConnection(str)
Try
conn.Open()
Dim sql As String = "SELECT Duration, CSAT, Away, Quality, Development FROM January WHERE Employee =" & "'" & cmbEmployee.SelectedItem.ToString & "'"
Dim cmd As New OleDbCommand(sql, conn)
Dim myReader As OleDbDataReader = cmd.ExecuteReader()
While myReader.Read
lblJanDuration.Text = myReader("Duration").ToString
lblJanCSAT.Text = myReader("CSAT").ToString
lblJanAway.Text = myReader("Away").ToString
lblJanQual.Text = myReader("Quality").ToString
lblJanDev.Text = myReader("Development").ToString
End While
Catch ex As OleDbException
MsgBox(ex.ToString)
Finally
conn.Close()
End Try
End Sub
Once the data has been loaded to the correct labels I have a button and click event to calculate the average from the labels - the other ones I was able to do easily because I could parse them to doubles and then do the calculation from there. Here is an image of what the form looks like, I think it will help all of you get an idea of what I am trying to accomplish.
This is what the form layout looks like
It is a good idea to separate your user interface code from your database code. You can use the same data retrieval function for any month by passing the month as TableName.
Database objects Connection, Command, and DataReader all need to be disposed and closed so they are placed in Using blocks. You don't want to hold the connection open while you update the user interface. Just return a DataTable and update the UI with that.
CalculateAverage first creates an array of the labels you want to include in the average. You can include all 12 but the average will not include empty labels. (IsNullOrEmpty)
Separate the string into minutes and seconds. Get the total seconds and add to the list.
Get the average number of seconds by calling Average on List(Of Integer).
Finally, turn the average seconds back into minutes and seconds and format a string to display.
Private Sub DisplayJanMetrics()
Dim dt As DataTable
Try
dt = GetEmployeeData(cmbEmployee.SelectedItem.ToString, "January")
Catch ex As Exception
MsgBox(ex.Message)
Exit Sub
End Try
If dt.Rows.Count > 0 Then
lblJanDuration.Text = dt(0)("Duration").ToString
lblJanCSAT.Text = dt(0)("CSAT").ToString
lblJanAway.Text = dt(0)("Away").ToString
lblJanQual.Text = dt(0)("Quality").ToString
lblJanDev.Text = dt(0)("Development").ToString
End If
End Sub
Private Function GetEmployeeData(Employee As String, TableName As String) As DataTable
Dim str As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\CoachingDB.accdb"
Dim sql As String = $"SELECT Duration, CSAT, Away, Quality, Development FROM {TableName} WHERE Employee = #Employee;"
Dim dt As New DataTable
Using conn As New OleDbConnection(str),
cmd As New OleDbCommand(sql, conn)
cmd.Parameters.Add("#Employee", OleDbType.VarChar).Value = Employee
conn.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
Private Function CalculateAverage() As String
Dim lst As New List(Of Integer)
Dim labels() = {Label1, Label2, Label3, Label4} 'an array of 1 thru 12
For Each label In labels
If Not String.IsNullOrEmpty(label.Text) Then
Dim fields = label.Text.Split(":"c)
Dim mins = CInt(fields(0))
Dim secs = CInt(fields(1))
lst.Add(mins * 60 + secs)
End If
Next
Dim avg = lst.Average
Dim avgMins = Math.Truncate(avg / 60)
Dim remainderSec = avg - avgMins * 60
Return $"{avgMins}:{remainderSec}"
End Function

Ms-access "Great Than" or equal query

I have an Ms-access DB that contain 40 students and I want to find students who are at least 18 years old.
I tried to use this code but it doesn't work!
Try
DataGridView1.Rows.Clear()
Dim dt As DataTable = New DBConnect().selectdata(String.Format("SELECT ID, Name FROM Students where Age > %{0}%", FlatTextBox8.Text))
For i As Integer = 0 To dt.Rows.Count - 1
DataGridView1.Rows.Add(i + 1, dt.Rows(i)(0), dt.Rows(i)(1))
Next
dt.Dispose()
dt = Nothing
Catch ex As Exception
End Try
How can I do this?
Name is a reserved word, so try with:
String.Format("SELECT ID, [Name] FROM Students where Age > {0}", FlatTextBox8.Text))
That said, use parameters.
It's better to use parametrized query in order to avoid sql injection.
This little function will fill and return a DataTable with the value you are looking at!
Private Function GetData() As System.Data.DataTable
Dim dt As New DataTable
Dim sqlCmd As String = "SELECT ID, Name FROM Students where Age > #Age"
Using myConnection As New SqlConnection(your_connection_string)
myConnection.Open()
Using myDataAdapter As New SqlDataAdapter(sqlCmd, myConnection)
myDataAdapter.SelectCommand.Parameters.Add("#Age", SqlDbType.Int) 'Change the type if your DB Table has another type
myDataAdapter.SelectCommand.Parameters("#Age").Value = Convert.ToInt16(FlatTextBox8.Text) 'Change the type if your DB Table has another type
myDataAdapter.Fill(dt)
End Using
myConnection.Close()
End Using
Return dt
End Function
Now it's time to call it inside your code:
Try
DataGridView1.Rows.Clear()
Dim dt As DataTable = GetData()
For i As Integer = 0 To dt.Rows.Count - 1
DataGridView1.Rows.Add(i + 1, dt.Rows(i)(0), dt.Rows(i)(1))
Next
dt.Dispose()
dt = Nothing
Catch ex As Exception
MsgBox(ex.Message)
Err.Clear
End Try
As you can notice, I also added a MsgBox() that will show you the error message if an exception is thrown. I found this very helpful while debugging.

get column value according to another column value from datatable in vb.net

i have a datatable similar to this:
id msg
1 thank you..
2 kindly...
3 please insert..
4 please stop
i need to get a msg according to a specific id from the datatable that's how i'm filling my datatable:
msgTable = selectMsg()
MsgBox(i need to get the msg here)
Public Function selectMsg() As DataTable
Dim command As SqlCommand = New SqlCommand("selectMsg", cn)
command.CommandType = CommandType.StoredProcedure
Dim da As New SqlDataAdapter(command)
'If dt.Rows.Count <> 0 Then
' dt.Rows.Clear()
'End If
Try
da.Fill(msgDS, "N_AI_HOME_CARE")
msgDT = msgDS.Tables(0)
Catch ex As Exception
logFile("SP selectMsg ---" + ex.Message)
End Try
Return msgDT
End Function
any suggestion will be much appreciated !
Supposing that your stored procedure returns the whole datatable of your messages (a very bad move because if the table is big you could have performance and network problems) then you need to apply the Select method with a filter expression to your returned datatable
msgTable = selectMsg()
Dim rows() = msgTable.Select("ID = " & idOfMessage)
if rows.Length > 0 then
MsgBox(row(0)(1).ToString()) ' read the first row, second column of the table'
End If
But I think you should use a more correct approach using a simple ExecuteScalar that doesn't return the entire datatable but just the first row and first column of a query
Public Function selectMsg(idOfMessage as Integer) As String
Dim command As SqlCommand = New SqlCommand("SELECT msg from tableName where ID = #id", cn)
command.Parameters.AddWithValue("#id", idOfMessage)
Dim result = command.ExecuteScalar()
if string.IsNullOrEmpty(result) Then
result = "No message found"
End If
return result
End Function
well acctually i just found that you use
MsgBox(msgTable.Rows(0)(1).ToString())
without any select method :)

Better way to print out rows from a datatable in vb.net

I am new to vb.net and I am trying to query a database and print out the records in the row to the console window. I got it to work, but I have a feeling that there is a more concise way to do this. One thing that I am sure is wrong is that I had to convert the dataset to a datatable to be able to retrieve the values. Is that correct? Could you take a look at the code below (especially the for loop) and let me know what I can improve upon?
Thanks!
Module Module1
Sub Main()
Dim constring As String = "Data Source=C:\Users\test\Desktop\MyDatabase1.sdf"
Dim conn As New SqlCeConnection(constring)
Dim cmd As New SqlCeCommand("SELECT * FROM ACCOUNT")
Dim adapter As New SqlCeDataAdapter
Dim ds As New DataSet()
Try
conn.Open()
cmd.Connection = conn
adapter.SelectCommand = cmd
adapter.Fill(ds, "testds")
cmd.Dispose()
adapter.Dispose()
conn.Close()
Dim dt As DataTable = ds.Tables.Item("testds")
Dim row As DataRow
Dim count As Integer = dt.Columns.Count()
For Each row In dt.Rows
Dim i As Integer = 0
While i <= count - 1
Console.Write(row(i))
i += 1
End While
Console.WriteLine(Environment.NewLine())
Next
Catch ex As Exception
Console.WriteLine("There was an error")
Console.WriteLine(ex)
End Try
Console.ReadLine()
End Sub
End Module
Here is how I would rewrite this for a few reasons:
1) You should always use Using statements with disposable objects to ensure they are correctly cleaned up. You had a good start with the dispose commands, but this way is safer.
2) It is more efficient to use ExecuteReader than loading everything into a dataset.
3) Your try/catch statement should include object creation as well as execution.
Finally, in response to your question about datasets and datatables, that code was absolutely correct: a dataset consists of zero or more datatables, so you were just extracting the existing datatable from the dataset.
Try
Dim constring As String = "Data Source=C:\Users\test\Desktop\MyDatabase1.sdf"
Using conn As New SqlCeConnection(constring)
conn.Open()
Using cmd As New SqlCeCommand("SELECT * FROM ACCOUNT", conn)
Dim reader As SqlCeDataReader
reader = cmd.ExecuteReader()
Do While reader.Read
For i As Integer = 0 To reader.FieldCount - 1
Console.Write(reader.GetString(i))
Next
Console.WriteLine(Environment.NewLine())
Loop
End Using
End Using
Catch ex As Exception
Console.WriteLine("There was an error")
Console.WriteLine(ex)
End Try
Console.ReadLine()
End Sub
One last note: since you are just printing to the console, it doesn't matter as much, but whenever you deal with a lot of strings, especially those that are to be concatenated, you should always consider using System.Text.StringBuilder.
Here is an example rewrite of the loop that prints to the console using stringbuilder (builds the string in memory, then dumps it to the console; I have also added the field name for good measure):
Dim sbOutput As New System.Text.StringBuilder(500)
For i As Integer = 0 To reader.FieldCount - 1
If sbOutput.Length <> 0 Then
sbOutput.Append("; ")
End If
sbOutput.Append(reader.GetName(i)).Append("=").Append(reader.GetString(i))
Next
sbOutput.AppendLine()
Console.Write(sbOutput.ToString)

When I run the query in query analyzer, it returns one row but when I use the same query in VB.NET, no rows are returned

Here is the code:
Function getData(ByVal id As String)
Dim reader As SqlClient.SqlDataReader
Dim statement As String
Dim count As Integer
Dim temp As Integer
statement = "SELECT * FROM General WHERE accountid='" + id + "'"
Conn.Open()
Comm = New SqlClient.SqlCommand(statement, Conn)
reader = Comm.ExecuteReader()
count = reader.FieldCount
Dim Data(count) As String
If reader.HasRows Then
For temp = 0 To count
Data(temp) = (reader.Item(temp))
Next temp
Else
Console.WriteLine("No rows found.")
End If
reader.Close()
Conn.Close()
Return Data
End Function
When I run the code the HasRows field is true but reader.Item(temp) gives the error
Invalid attempt to read when no data is present.
You need a While reader.Read() loop. The reader starts at row index -1; the Read() will advance to the first row (well, fetch it) and then you can process it.
That's why your HasRows returns true but you can't retrieve the fields -- you're not positioned at the first row yet.
You may want to do something like this:
If reader.HasRows Then
While reader.Read()
For temp = 0 To count
Data(temp) = (reader.Item(temp))
Next temp
End While
Else
Console.WriteLine("No rows found.")
End If