Naming Column Header Based On Results From Database - vb.net

net and would to have the Header Text of columns in a datagridview be named after results from the database, e.g the query in my code returns four dates,30/08/2017,04/09/2017,21/09/2017 and 03/02/2018. My aim is to have the column headers in the data grid named after those dates. Your help will highly be appreciated.
sql = "SELECT COUNT (ServiceDate) As NoOfServiceDates FROM (SELECT DISTINCT ServiceDate FROM tblattendance)"
Using command = New OleDbCommand(sql, connection)
Using reader = command.ExecuteReader
reader.Read()
ColumnNo = CInt(reader("NoOfServiceDates")).ToString
End Using
End Using
DataGridView1.ColumnCount = ColumnNo
For i = 0 To DataGridView1.Columns.Count - 1
sql = "SELECT DISTINCT ServiceDate FROM tblattendance"
Using command = New OleDbCommand(sql, connection)
Using reader = command.ExecuteReader
While reader.Read
DataGridView1.Columns(i).HeaderText = reader("ServiceDate").ToString
End While
End Using
End Using
Next

The current code re-runs the query each time through the column count loop, meaning it will set the column header for that column to all of the date values in sequence, so the last value in the query shows in the all the columns. You only need to run the query once:
Dim i As Integer = 0
sql = "SELECT DISTINCT ServiceDate FROM tblattendance"
Using command As New OleDbCommand(sql, connection), _
reader As OleDbDatareader = command.ExecuteReader()
While reader.Read
DataGridView1.Columns(i).HeaderText = reader("ServiceDate").ToString
i+= 1
End While
End Using
Additionally, this still results in two separate trips to the database, where you go once to get the count and again to get the values. Not only is this very bad for performance, it leaves you open to a bug where another user changes your data from one query to the next.
There are several ways you can get this down to one trip to the database: loading the results into memory via a List or DataTable, changing the SQL to include the count and the values together, or adding a new column each time through the list. Here's an example using the last option:
DataGridView1.Columns.Clear()
Dim sql As String = "SELECT DISTINCT ServiceDate FROM tblattendance"
Using connection As New OleDbConnection("string here"), _
command As New OleDbCommand(sql, connection)
connection.Open()
Using reader As OleDbDataReader = command.ExecuteReader()
While reader.Read
Dim column As String = reader("ServiceDate").ToString()
DataGridView1.Columns.Add(column, column)
End While
End Using
End Using
Even better if you can use something like Sql Server's PIVOT keyword in combination with the DataGridView's AutoGenerateColumns feature for DataBinding, where you will write ONE SQL statement that has both column info and data, and simply bind the result set to the grid.

The For Next is incorrect. You execute your command for every column, when you only need to execute it once. The last result from the DataReader will be the header for every column as currently written.
You should iterate through your DataReader and increment the cursor variable there:
Dim i As Integer = 0
Using command = New OleDbCommand(sql, connection)
Using reader = command.ExecuteReader
While reader.Read
DataGridView1.Columns(i).HeaderText = reader("ServiceDate").ToString
i += 1
End While
End Using
End Using

Related

Fill combobox starting from the second record

I Fill My ComboBox1 From Field ( Drivers ) ..with this code all records appears in Combobox1 .. How to make so that the first record does not appear in ComboBox1 .. i want the records to start with the second records in my combobx1 .. the ID numbers are (1-2-3-4-5-6) and so on.
Private Sub Fill_Numeros_Drivers()
Dim InfoAdapter As OleDbDataAdapter
Dim InfoTable As DataSet
ComboBox1.Items.Clear()
Dim Sql As String = "SELECT DISTINCT Drivers From Table1"
InfoAdapter = New OleDbDataAdapter(Sql, Conne)
InfoTable = New DataSet
InfoTable.Clear()
InfoAdapter.Fill(InfoTable, "Table1")
For Each rw As DataRow In InfoTable.Tables("Table1").Rows
ComboBox1.Items.Add(rw(0).ToString())
Next
End Sub
Keep your database objects local so you control their closing and disposing. Using...End Using blocks will do that for you even if there is and error.
I added a field to the query for DriverID. Whatever your Primary Key field is might be appropriate to assure the order of the records. The field in the Order By clause must be in the Select part of the query when DISTINCT is used. This field is downloaded but never used.
The first call to reader.Read reads the first record but nothing is done with it. The second call to reader.Read is now on the second record.
Private Sub Fill_Numeros_Drivers()
Using Conne As New OleDbConnection("Your connection string")
Using cmd As New OleDbCommand("SELECT DISTINCT Drivers, DriverID From Table1 Order By DriverID", Conne)
Conne.Open()
Using reader As OleDbDataReader = cmd.ExecuteReader
reader.Read() 'Reads the first record
Do While reader.Read
ComboBox1.Items.Add(reader.GetString(0))
Loop
End Using
End Using
End Using
End Sub

VB.Net and Access - Getting Totaliser Value

I'm trying to databind a textbox to a totaliser value in an access database. I currently update the database via OleDbCommand and then edit any existing entries via databinding on the form.
I have everything working fine, but I want a textbox to show the totaliser (sum) of a particular column in the datbase. Access shows this totaliser underneath the column if the database is opened.
Is there a method to bind this value to the textbox?
Thanks
Well, however you are accessing the database, you need to make a call to get the SUM of your desired table.
If we are talking about SQL, it would look something like:
conn = New OleDbConnection(Get_Constring)
conn.Open()
cmd.Connection = conn
cmd.CommandType = CommandType.Text
sSQL = " SELECT SUM(total) AS Total From YourTable"
cmd.CommandText = sSQL
OleDbDataReader dr = cmd.ExecuteReader()
If dr.Read() Then
set total = Convert.ToInt32(dr["Total"])
End If
You could load this into a DataTable/DataSet or use the DataReader and assign the result (the sum) to a textbox, like:
TextBox1.Text = total
If you are using Linq it could look like (this is just an example):
Dim yourObject = From cust In db.Customers
Group By cust.City
Into Average(cust.Orders.Count)
Order By Average
DataGridView1.DataSource = yourObject

SQL variable returning 0

When I run the following SQL statement in SQL Server Management Studio it returns a count of 2
SELECT COUNT(*)
FROM Daisy_Copy2
WHERE ChargeCode = '1';
But for some reason when I run the following VB.net code the result variable returns a 0 and doesn't identify that duplicate codes exist.
Dim result As Integer
Using cmdb = New SqlCommand("SELECT COUNT(*) FROM Daisy_Copy2 WHERE ChargeCode = '1'", conn)
Int(result = cmdb.ExecuteScalar())
If result > 1 Then
MessageBox.Show("Duplicate Codes Exist!", "Billing", _
MessageBoxButtons.OK, MessageBoxIcon.Information)
Else
MsgBox(result)
End If
End Using
Can anyone help me understand why?
Any help greatly appreciated.
Instead of ExecuteNonQuery you should use ExecuteScalar
Dim result As Integer = CInt(cmd.ExecuteScalar())
ExecuteNonQuery is normally used for updates or inserts that don't leave a result, so it returns an integer telling you how many rows were affected, not the result itself.
What you most likely are meaning to use is ExecuteScalar which returns the first column of the first row in the result set returned by the query, in this case the integer containing your count.
this is just a way you can use:
Dim Sqlda = New SqlDataAdapter("SELECT COUNT(*) AS tCount FROM Daisy_Copy2 WHERE ChargeCode=1", conn)
Dim sqlds = New DataSet
Sqlda.Fill(sqlds, "Daisy_Copy2")
Dim tblRow As DataRow
For Each tblRow In sqlds.Tables("Daisy_Copy2").Rows
MsgBox(tblRow("tCount").ToString())
Next
use below link to read more about it
System.Data.SqlClient Namespace
Good luck

Vb.net pull in a SQL table row by row

I am a little new to using vb.net and SQL so I figured I would check with you guys to see if what I am doing makes sense, or if there is a better way. For the first step I need to read in all the rows from a couple of tables and store the data in the way the code needs to see it. First I get a count:
mysqlCommand = New SQLCommand("SELECT COUNT(*) From TableName")
Try
SQLConnection.Open()
count = myCommand.ExecuteScalar()
Catch ex As SqlException
Finally
SQLConnection.Close()
End Try
Next
Now I just want to iterate through the rows, but I am having a hard time with two parts, First, I cannot figure out the SELECT statement that will jet me grab a particular row of the table. I saw the example here, How to select the nth row in a SQL database table?. However, this was how to do it in SQL only, but I was not sure how well that would translate over to a vb.net call.
Second, in the above mycommand.ExecuteScalar() tell VB that we expect a number back from this. I believe the select statement will return a DataRow, but I do not know which Execute() statement tells the script to expect that.
Thank you in advance.
A simple approach is using a DataTable which you iterate row by row. You can use a DataAdapter to fill it. Use the Using-statement to dispose/close objects property that implement IDisposable like the connection:
Dim table = New DataTable
Using sqlConnection = New SqlConnection("ConnectionString")
Using da = New SqlDataAdapter("SELECT Column1, Column2, ColumnX FROM TableName ORDER By Column1", sqlConnection)
' you dont need to open/close the connection with a DataAdapter '
da.Fill(table)
End Using
End Using
Now you can iterate all rows with a loop:
For Each row As DataRow In table.Rows
Dim col1 As Int32 = row.Field(Of Int32)(0)
Dim col2 As String = row.Field(Of String)("Column1")
' ...'
Next
or use the table as DataSource for a databound control.

Read row by row vb.net

I need to read row by row in a column in a table then I need to store this then call procedure to insert data to a different column using vb.net.
I have already create the DB connection and I know how to call the procedure
but I'm not sure of how to read in the loop and then to assign it to a variable to call it in the store procedure.
Dim drDocs As SqlClient.SqlDataReader
Dim cmdDocs As SqlClient.SqlCommand
Dim Doc As Long
Dim l As Long
Using conn As New SqlConnection(DBpath)
cmdDocs = New SqlClient.SqlCommand("Select (RecordID) from DocID", conn)
drDocs = cmdDocs.ExecuteReader
Do While drDocs.Read
'need it read each row in that field and hold value'
Loop
drDocs.Close()
cmdDocs.Dispose()
If Doc Then
cmdDocs = New SqlClient.SqlCommand("Insert_Doc", conn)
cmdDocs.CommandType = CommandType.StoredProcedure
cmdDocs.Parameters.Add("path", SqlDbType.NVarChar).Value =need to put hold value from reading that cloumn row by row
End If
End If
The code you've provided actually works now. It is as Juergen D says, sql functions like Max(), min() and using Limit will only return 1/certain number of rows based on their conditions.
if I may, just use this SQL command
"select `RecordID` from DocID asc;"
If you want it in descending format, use desc instead
...now reading further, I realize that what you want to do is to store the results, then loop again through it so that you can do an sql command with it, correct? what you can do then is to pass the SQL results to a container (I use datagridviews) then loop through the container.