VB.NET - Unable to retrieve the first ID on a table using SELECT query - vb.net

Good day everyone! After 3 years without using VB.NET I decided to use again for my project that not require web development.
this is my code (Reference: link)
cmdOLEDB.CommandText = "SELECT Price FROM tblPrice"
cmdOLEDB.Connection = cnnOLEDB
Dim rdrOLEDB As OleDbDataReader = cmdOLEDB.ExecuteReader
Dim priceList(18) As String
Dim i As Integer = 0
If rdrOLEDB.Read = True Then
While rdrOLEDB.Read()
priceList(i) = rdrOLEDB.GetValue(0)
i += 1
End While
txtPrice1.Text = priceList(0).ToString
cnnOLEDB.Close()
Else
MsgBox("Record not found.")
cnnOLEDB.Close()
End If
when I put this code in a MsgBox
MsgBox(rdrOLEDB.GetValue(0))
the result is "2" but I have 1 more data before that. It means the query retrieve the ID # 2 not the ID # 1. Here's the screenshot on my Access database
and when I use this code:
txtPrice1.Text = priceList(17).ToString
the result is 35.

You are skipping the first record because you call two times the Read method.
The first call reads the first record and returns true, then you enter the while loop extracting the info, but at this point you are on the second record.
If you want to check if there are rows then call HasRows
If rdrOLEDB.HasRows Then
While rdrOLEDB.Read()
priceList(i) = rdrOLEDB.GetValue(0)
i += 1
End While
txtPrice1.Text = priceList(0).ToString
cnnOLEDB.Close()
Else
MsgBox("Record not found.")
cnnOLEDB.Close()
End If

Please check with If condition , replace rdrOLEDB.Read with rdrOLEDB.hasrows
If rdrOLEDB.Hasrows= True Then
and check it again.

Related

How to avoid duplicate entries in database access

I'm creating a Registration form
How can i Prevent a data from duplicating when i save a data to my Ms access Database , something like Error handling for duplicate data or same First Name/Last Name and a message box that says there's a duplicated data.
As for now this is the code that i saw someone uses.
For i As Integer = 0 To DataGridView1.Rows.Count - 1
If Fname.Text = DataGridView1.Rows(i).Cells(0).Value.ToString() Then
MessageBox.Show("Duplicate Info")
Return
End If
Next
Do you guys have any suggestion , Thanks in Advance
This might be useful for what you asked, but personally I would check if Data matches the one in DB instead of DataGridView, because Users can edit them if you don't set ReadOnly property to true.
Private Sub DuplicatePrevention(datagridview As DataGridView, name As String)
Dim duplicateCount As Integer = 0
For i As Integer = 0 To datagridview.Rows.Count - 1
If datagridview.Rows(i).Cells(0).Value.ToString = name Then
duplicateCount += 1
End If
Next
If duplicateCount = 0 Then
'fire your Query
Else
MsgBox(name & " exist already", MsgBoxStyle.Information)
End If
End Sub

Referencing an entire data set instead of a single Cell

I am creating a login form for users to log into using a database. I was wondering if there is a way in which i could get the program to search the entire table instead of a certain item. Here is my code so far.
Dim UserInputtedUsername As String
Dim UserInputtedPassword As String
UserInputtedUsername = txtAdminUsername.Text
UserInputtedPassword = txtAdminPassword.Text
sqlrunnerQuery = "SELECT * FROM tblLogin"
daRunners = New OleDb.OleDbDataAdapter(sqlrunnerQuery, RunnerConnection)
daRunners.Fill(dsRunner, "Login")
If UserInputtedUsername = dsadminlogin.Tables("Login").Rows(0).Item(2) And UserInputtedPassword = dsadminlogin.Tables("Login").Rows(0).Item(3) Then
Form1.Show()
ElseIf MsgBox("You have entered incorrect details") Then
End If
End Sub
Instead if searching the (in-memory) DataSet for your user serach the database in the first place. Therefore you have to use a WHERE in the sql query(with guessed column names):
sqlrunnerQuery = "SELECT * FROM tblLogin WHERE UserName=#UserName AND PassWord=#PassWord"
Note that i've used sql-parameters to prevent sql-injection. You add them in this way:
daRunners = New OleDb.OleDbDataAdapter(sqlrunnerQuery, RunnerConnection)
daRunners.SelectCommand.Parameters.AddWithValue("#UserName", txtAdminUsername.Text)
daRunners.SelectCommand.Parameters.AddWithValue("#PassWord", txtAdminPassword.Text)
Now the table is empty if there is no such user.
If dsadminlogin.Tables("Login").Rows.Count = 0 Then
MsgBox("You have entered incorrect details")
End If
For the sake of completeteness, you can search a complete DataTable with DataTable.Select. But i prefer LINQ-To-DataSet. Here's a simple example:
Dim grishamBooks = From bookRow in tblBooks
Where bookRow.Field(Of String)("Author") = "John Grisham"
Dim weHaveGrisham = grishamBooks.Any()

"No data exists for the row/column." executing OLEDB Oracle OleDbDataReader

I know this is very basic, and I've done this hundreds of times. But, for some strange reason I am executing this command on a database, and it fails when it tries to read a column from the result. If I execute this statement in SQL Plus logged in as the same credentials, the row (table has 1 row) is selected just fine. Any ideas what I am doing wrong? I tried accessing the columns by name, by index, and indeed any column - all of them give no data. I tried without the .NextResult() (just in case), same exception.
'...
' Determine if this database is Multisite enabled
Dim multisiteCmd As OleDbCommand = DbConnection.CreateCommand
multisiteCmd.CommandText = "SELECT * FROM TDM_DB_VERSION;"
Dim dbVersionReader As OleDbDataReader = multisiteCmd.ExecuteReader()
If dbVersionReader.HasRows Then
dbVersionReader.NextResult()
'If a ReplicaID was generated for the Database ID, then this is part of a
'multisite implementation
'Dim dbRepID As String = dbVersionReader("DB_REPLICID")
Dim dbRepID As String = dbVersionReader(9)
PluginSettings.UseMultisite = False
If Not dbRepID Is Nothing Then
If dbRepID.Length > 0 Then
PluginSettings.UseMultisite = True
PluginSettings.MultisiteReplicaId = dbRepID
End If
End If
End If
dbVersionReader.Close()
As you can see from these Immediate commands, the connection is open:
? DbConnection.Provider
"OraOLEDB.Oracle"
? DbConnection.State
Open {1}
NextResult() is for statements that have more than one result set. For example, if you had sent a command like this:
"SELECT * FROM TDM_DB_VERSION;SELECT * FROM dual;"
Note there are two queries in there. You can handle them both with a single call to the database and a single OleDbDataReader, and NextResult() is part of how you do that.
What you want instead is this:
Dim multisiteCmd As OleDbCommand = DbConnection.CreateCommand
multisiteCmd.CommandText = "SELECT * FROM TDM_DB_VERSION;"
Dim dbVersionReader As OleDbDataReader = multisiteCmd.ExecuteReader()
If dbVersionReader.Read() Then
'If a ReplicaID was generated for the Database ID, then this is part of a
'multisite implementation
'Dim dbRepID As String = dbVersionReader("DB_REPLICID")
Dim dbRepID As String = dbVersionReader(9)
PluginSettings.UseMultisite = False
If Not dbRepID Is Nothing Then ' Do you mean check for DbNull here? "Nothing" is not the same thing
If dbRepID.Length > 0 Then
PluginSettings.UseMultisite = True
PluginSettings.MultisiteReplicaId = dbRepID
End If
End If
End If
dbVersionReader.Close()

SQL QUERY Return 0 Records but 2 records exist

This code returns zero rows count but there are 2 rows in appointment table.
The msgbox I commented was to check if the date is correct and format is correct and shows date as 2014/08/09. The appointment date in database is 2014/08/09 for 2 records (the only 2 records). Record count variable shows 0.
Table name (copied directly cut and paste) is Appointments and column is AppointmentDate.
The connectDatabase sub routine connects to the database successfully as I use it whenever I connect to database so it's correct as I connect to other tables correctly before I run this code using same sub routine.
Command.text contains
SELECT * FROM Appointments WHERE AppointmentDate = 2014/08/09
Don't know what other details to specify.
Private Sub frmAppointments_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'load appointments
LoadAppointments(dtpAppointmentDate.Value.Date)
End Sub
Public Sub LoadAppointments(whichdate As Date)
Dim sqlcmd As New OleDb.OleDbCommand
'set connection
ConnectDatabase()
With frmAppointments
'MsgBox(whichdate)
M_connDB.Open()
'fetch records from database
sqlcmd.Connection = M_connDB
sqlcmd.CommandText = "SELECT * FROM Appointments WHERE AppointmentDate = " & whichdate
.dataAdapterAppointments = New OleDb.OleDbDataAdapter(sqlcmd.CommandText, M_connDB)
'first clear data table to prevent duplicates
.dataTableAppointments.Rows.Clear()
.dataAdapterAppointments.Fill(.dataTableAppointments)
M_connDB.Close()
Dim rowindex As String
Dim iy As Long
Dim recordcount As Long
'check if any records exist
recordcount = .dataTableAppointments.Rows.Count
If Not recordcount = 0 Then
For iy = 0 To .dataTableAppointments.Rows.Count
For Each row As DataGridViewRow In .dtgrdAppointments.Rows
If row.Cells(0).Value = .dataTableAppointments.Rows(iy).Item(6) Then
rowindex = row.Index.ToString()
MsgBox(.dtgrdAppointments.Rows(rowindex).Cells(0).Value, vbInformation + vbOKOnly, "MSG")
Exit For
End If
Next
Next iy
Else
MsgBox("No Appointments for selected date.", vbInformation + vbOKOnly, "No Appoinments")
End If
End With
Use sql-parameters instead of string-concatenation. This should work in MS Access:
sqlcmd.CommandText = "SELECT * FROM Appointments WHERE AppointmentDate = ?"
sqlcmd.Parameters.AddWithValue("AppointmentDate", whichdate)
This prevents you from conversion or localization issues and -even more important- sql-injection.
2014/08/09 doesn't have quotes around it, making it a math expression (2014 divided by 8 divided by 9). Of course, your table has no rows with a date matching the result of that expression. But don't put in the quotes. Instead, add a parameter.
I don't VB, so I write it in C#. My point of view is it's better to specify the datatype too:
sqlcmd.CommandText = "SELECT * FROM Appointments WHERE AppointmentDate=#whichdate";
sqlcmd.Parameters.Add("#whichdate", SqlDbType.Date).Value = whichdate;

For Loop: Skip to next line after X seconds

Can someone help me with this code:
I have a dataGrid with 2 columns:
and what I want to do is use PStools' Psloggedon cmd to give me the name of every person logged in and append that result to the "LOGGED_IN" column but what is happening is that if there is no user logged into a PC, the process takes like 5 minutes to post an error message.
Now, what I want to do is that if .5 seconds has gone to just forget the row it's currently querying and move on to the next row, in the column?
here is the vb.net code i want to focus on:
Dim RowCount As Integer = datagridView1.RowCount
For i = 0 To RowCount - 2
'PERFORM PSLOGGEDON ROUTINE
Dim Proc1 As New Process
Proc1.StartInfo = New ProcessStartInfo("psloggedon")
Proc1.StartInfo.Arguments = "-l \\" & datagridView1.Rows(i).Cells(0).Value & ""
Proc1.StartInfo.RedirectStandardOutput = True
Proc1.StartInfo.UseShellExecute = False
Proc1.StartInfo.CreateNoWindow = True
Proc1.Start()
'INSERT RESULTS IN LOGGEN_IN COLUMN
datagridView1.Rows(i).Cells(1).Value = Proc1.StandardOutput.ReadToEnd
Next
Can someone please show me how to write the code to get that done?
Use Process.WaitForExit(int milliseconds) method.
Instructs the Process component to wait the specified number of milliseconds for the associated process to exit.
Return Value
Type: System.Boolean
true if the associated process has exited; otherwise, false.
You can then use Process.Kill to kill process if it did not exit in given time.
Something like
Dim RowCount As Integer = datagridView1.RowCount
For i = 0 To RowCount - 2
'PERFORM PSLOGGEDON ROUTINE
Dim Proc1 As New Process
Proc1.StartInfo = New ProcessStartInfo("psloggedon")
Proc1.StartInfo.Arguments = "-l \\" & datagridView1.Rows(i).Cells(0).Value & ""
Proc1.StartInfo.RedirectStandardOutput = True
Proc1.StartInfo.UseShellExecute = False
Proc1.StartInfo.CreateNoWindow = True
Proc1.Start()
If Not Proc1.WaitForExit(5000) Then
Proc1.Kill()
End If
'INSERT RESULTS IN LOGGEN_IN COLUMN
datagridView1.Rows(i).Cells(1).Value = Proc1.StandardOutput.ReadToEnd
Next