Fill combobox starting from the second record - vb.net

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

Related

Naming Column Header Based On Results From Database

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

Datagridview - Oracle Update error "Dynamic SQL generation failed."

I'm using Datagridview to show me joined records from 2 tables. Data that is showing is from one of the tables + data that are in joined table (Table3). SQL query returns results in Datagridview (works fine in Oracle too), but update fails with "Dynamic SQL generation failed. Either no base tables were found or more than one base table was found". Here is my table design:
Table1:
ID_TABLE1
ITEM_NAME
ITEM_DESCRIPTION
Table3: (this is a joined view for Table1 and Table2)
ID_TABLE3
ID_TABLE1_FK
ID_TABLE3_FK
VALIDITY
DATE_CONNECTION
My code (exactly as Oracle recommends):
Public Class Form2
Private da As OracleDataAdapter
Private cb As OracleCommandBuilder
Private ds As DataSet
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Saving.Enabled = False 'this deals with error with updating (from Oracle site)
Dim SQL As String = "SELECT ID_TABLE1, ID_TABLE3, SERIAL_NO, ITEM_NAME, ITEM_DESCRIPTION, VALIDITY, DATE_CONNECTION from TABLE1, TABLE2 WHERE TABLE3.ID_TABLE1_FK=" & Form1.DataGridView1.CurrentRow.Cells(0).Value.ToString
Try
Oracleconn() 'connection to my DB
Dim cmd = New OracleCommand(SQL, Oracleconn)
cmd.CommandType = CommandType.Text
da = New OracleDataAdapter(cmd)
cb = New OracleCommandBuilder(da)
ds = New DataSet()
da.Fill(ds)
My_DGV.DataSource = ds.Tables(0)
Saving.Enabled = True
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
'No closing of connection here because of working with Dataset (Oracle suggestion)
End Try
End Sub
Private Sub Saving
da.Update(ds.Tables(0))
Saving.Enabled = True
End Sub
End Class
So, Is my SQL query wrong or what ? Any help would be much appreciated !
P.S.: In actual case only column "VALIDITY" from Table3 will be allowed to change for users, so I need to update only that field.
This is too complicated for me, looks like Oracle-provided suggestion for working with Datasets just isn't easy when you want to perform Update on join table records. So I tried a different approach and It worked for me. Since what I need is to update only 1 column from SQL query which returns to Datagridview I did this :
For Each row As DataGridViewRow In My_.Rows
cmd.Parameters.Add(New OracleParameter("validity", row.Cells(6).Value))
cmd.CommandText = "UPDATE TABLE3 SET VALIDITY= : validity WHERE ID_TABLE1_FK='" & row.Cells(1).Value & "'"
cmd.ExecuteNonQuery()
cmd.Parameters.Clear()
Next
If anyone knows the answer to my original question - so how to do same with just da.Update(ds.Tables(0)), then please let me know. I reckon that SQL query needs to be properly changed, using JOIN method.

List View Population Errors

I have 3 columns that need populating when a user presses 'search' however every time that I click 'search' only the Employee ID appears, neither the 'First Name' nor the 'Last Name' are present in the List View. The data does exist in my Access Database, this is proved as the program produces a blank record instead of a null value error. The code that I am using to populate the List View is:
ds.Clear()
lstClockin.Items.Clear()
con.ConnectionString = provider & datafile
con.Open() 'Open connection to the database
sqlstatement = "SELECT * FROM [EmployeeAccounts]"
da = New OleDb.OleDbDataAdapter(sqlstatement, con)
da.Fill(ds, "allmembers") 'Fill the data adapter
con.Close()
Dim recordCount, x As Short
recordCount = 0
x = 0
recordCount = ds.Tables("allmembers").Rows.Count
With ds.Tables("allmembers")
Do Until x = recordCount
lstClockin.Items.Add(.Rows(x).Item(0))
lstClockin.Items(x).SubItems.Add(.Rows(x).Item(1))
lstClockin.Items(x).SubItems.Add(.Rows(x).Item(2))
lstClockin.Items(x).SubItems.Add(.Rows(x).Item(3))
x = x + 1
Loop
End With
The first 3 columns in the Database are, [Employee ID], [First Name] & [Last Name]
Any suggestions are welcome; however I have ruled out using a DataGridView or any control. As this program needs to use a ListView. Thankyou in advance!
There are several things that can be improved in the code:
Dim SQL = "SELECT Id, Name, Fish FROM Sample"
Using dbcon As New OleDbConnection(ACEConnStr)
Using cmd As New OleDbCommand(SQL, dbcon)
dbcon.Open()
Dim lvi As ListViewItem
myLV.SuspendLayout()
Using rdr = cmd.ExecuteReader
Do While rdr.Read
lvi = New ListViewItem(rdr.GetInt32(0).ToString)
If rdr.IsDBNull(1) Then
lvi.SubItems.Add("")
Else
lvi.SubItems.Add(rdr.GetString(1))
End If
If rdr.IsDBNull(2) Then
lvi.SubItems.Add("")
Else
lvi.SubItems.Add(rdr.GetString(2))
End If
myLV.Items.Add(lvi)
Loop
End Using
myLV.ResumeLayout()
End Using
End Using
Connections and other DB Provider objects allocate resources which need to be released or your app will leak. Using blocks for things that implement Dispose will close and dispose of them for you
There is no need for an DataAdapter, DataSet and DataTable since you are copying the data to the control. This code uses a DataReader to get the data.
Rather than SELECT * the query specifies the columns/order so it can use the Getxxxxx methods to get typed data. That doesnt matter a great deal in this case because everything gets converted to string for the ListView. lvi.SubItems.Add(rdr(COLUMN_NAME).ToString()) would also work.
It seems unlikely the ID column could be null, so the code only checks the other 2 for DbNull (another thing the DGV can handle without help).
Since the ListView is suboptimal and slow in adding items, SuspendLayout and ResumeLayout are used to minimize paints while it is populated.
I am not at all sure what ...the program produces a blank record means, but in order use a ListView like it is a grid, the View property must be Details and you have to have added 3 columns in the IDE (or manually create them in code). Nothing will show without those settings.
If the DataTable is needed/used elsewhere, you can still fill one without a DataAdpater and populate the LV from it:
...
dt.Load(cmd.ExecuteReader)
For Each row As DataRow In dt.Rows
lvi = New ListViewItem(row(0).ToString())
If DBNull.Value.Equals(row(1)) Then
lvi.SubItems.Add("")
Else
lvi.SubItems.Add(row(1).ToString())
End If
If DBNull.Value.Equals(row(2)) Then
lvi.SubItems.Add("")
Else
lvi.SubItems.Add(row(2).ToString())
End If
myLV.Items.Add(lvi)
Next
This uses a different DBNull check since it is using a DataRow and not the DataReader.

Executing delete command on MS-Access through VB.NET does not delete the records

Just trying to delete all rows of an Access table:
Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click
'Clear old records from extract table
Dim sqlConnection As New System.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\CLI_CRVM.accdb")
Dim cmd As New System.Data.OleDb.OleDbCommand()
Dim intRC As Integer
cmd.CommandType = System.Data.CommandType.Text
cmd.CommandText = "DELETE * FROM [extract] ;"
cmd.Connection = sqlConnection
sqlConnection.Open()
intRC = cmd.ExecuteNonQuery()
sqlConnection.Close()
MsgBox(intRC)
End Sub
I do not get any errors but it doesn't delete the rows either. There are currently 10 rows in the table and the MsgBox shows 10 each time the button is clicked and there are still 10 rows in the table afterwards.
What am I missing?
Try without the asterisk:
DELETE FROM [extract];
You don't generally supply any columns in a DELETE. You only supply columns that you want to match a row against .. via a WHERE clause afterwards.
There are certain dialects of SQL that let you specify thresholds on what you delete in that part of the query - however, I don't believe Access' dialect does (I could be wrong).

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.