I want to use multiple connection in if else code block but it's giving the following error when I checked in a Messagebox :
"Argument prompt cannot be converted to string"
Here is my code :
Try
Conn.Open()
Com.CommandText = "Select * FROM Table1 WHERE ID=" & txtID.Text & " AND DOR=#01/01/1900# AND Paid = '0' ORDER BY DOI"
Dr = Com.ExecuteReader
If Dr.Read = True Then
txtInstNo.Text = Dr(2)
txtInstAmount.Text = Dr(4)
Else
If MsgBox("Wait! You're not allowed to do it. Do you still want to continue ? ", MsgBoxStyle.YesNo Or MsgBoxStyle.Question, "Alert") = MsgBoxResult.Yes Then
Try
Dim Con As New OleDbConnection
Dim Comm As New OleDbCommand
Dim Dr2 As OleDbDataReader
Con.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Database.accdb"
Con.Open()
Comm.Connection = Con
Comm.CommandText = "Select * FROM Table1 WHERE ID=" & txtID.Text & " AND DOR=#01/01/1900# AND Paid = '0' ORDER BY DOI"
Comm.CommandType = CommandType.Text
Dr2 = Comm.ExecuteReader
MsgBox(Dr2) <-- Here I got that error
If Dr.Read = True Then
txtInstNo.Text = Dr(2)
txtInstAmount.Text = Dr(4)
Else
MsgBox("Sorry, no record found",MsgBoxStyle.Exclamation, "Alert")
End If
Dr2.Close()
Con.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
End If
Dr.Close()
Conn.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
Your query might be returning entire rows, objects, widgets or whatever. As #Andrew Morton pointed out, it's a Data Reader. It's not going to implicitly convert your result. You'll have to manipulate your reader result and convert it to a string to do anything useful. You'll also have to handle if your DataReader returns a null result, which when converted should be "" an empty string.
If you just want to see what Dr2 contains, you could try MsgBox(CStr(Dr2)). No error handling, if it throws an exception.
There are a few things which could be modified in your code to make it a bit shorter and so easier to track down what is not working. It is easier to isolate a problem if you have the minimal amount of code which shows the problem: How to create a Minimal, Complete, and Verifiable example.
I'll show my suggestion for a minimal amount of code on a new form which should help you narrow down where the problem is, and then I'll go over why I have written it that way and what could be going wrong.
Option Strict On
Option Infer On
Imports System.Data.OleDb
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Database.accdb"
Dim sql = "SELECT InstNo, InstAmount FROM Table1 WHERE ID = ? AND DOR = #01/01/1900# AND PAID='0' ORDER BY DOI"
' lists to hold the retrieved data
Dim instNos As New List(Of String)
Dim instAmounts As New List(Of String)
' get the data
Using conn As New OleDbConnection(connStr)
Using cmd As New OleDbCommand(sql, conn)
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#ID",
.DbType = DbType.String,
.Value = txtID.Text})
conn.Open()
Dim rdr = cmd.ExecuteReader()
While rdr.Read
instNos.Add(rdr.GetString(0))
instAmounts.Add(rdr.GetString(1))
End While
End Using
End Using
' act on the data
If instNos.Count = 0 Then
MsgBox(String.Format("No records were found for ID ""{0}"".", txtID.Text))
Else
txtInstNo.Text = String.Join(vbCrLf, instNos)
txtInstAmount.Text = String.Join(vbCrLf, instAmounts)
End If
End Sub
End Class
The code.
I start with Option Strict On to make sure that all data types match up and I haven't done anything else silly which Visual Studio can point out to me.
I use Option Infer On so that I don't have to type out the type of variables when the compiler can infer what they are.
I used just one Button on the form along with the three named textboxes as we are going for minimal code.
I set up the two strings which are going to be used in one place at the top of the sub because it is easier to maintain the code that way. Normally, you would declare variables just before they are used to minimise their scope.
I specified exactly which columns I want from the database. There is no point retrieving all of them with *. I had to guess what the columns are called - you will need to put in the actual names if they are different.
The result of a query to the database might have more than one record, so I initialise Lists for the data. (Your query has an ORDER BY so I assume that there could be more than one record.)
The Using statement makes sure that resources are released cleanly whatever else happens.
For OleDb, parameters are normally represented by a ?. (If there is more than one, they are all represented by question marks and the parameters must be added in the order in which they are to be put into the query.) I had to guess at the data type for the ID column - please put in the correct type. When you create the parameter, you can still use a meaningful name for it, even though it is ignored by the computer.
Next, the data (if any) is read. I do nothing else at this point except read the data to keep it fast and tidy. I assumed that the data to be retrieved is strings, hence the GetStrings. You should adjust that if required, and also the types of the Lists to match.
Now that the data has been read, I act on it. If there was no data, show an appropriate message, and if there was data then I put it into multiline textboxes to show it. Note that I wrote multiline: if it was a single line textbox then only the last line would be visible. Other ways of displaying it could be more useful, for example a DataGridView - in which case I might have read the data into a DataTable or a list of some class.
What could go wrong.
In your query, you have AND DOR = #01/01/1900# - is this correct?
In your query, you have AND PAID = '0' - is PAID actually a string? If it is a number then it should be AND PAID = 0. (The DB should convert the string "0" to the number zero, but why make it do extra work?)
Now that you have multiline textboxes for the results, you can see if it just happens that the last records found happened to be blank, and are simply not visible in a single-line textbox.
Finally, are you sure it is using the correct database file?
Related
I have three tables in access database and a Application in vb.net where i am trying to search data from all three tables by TextBox but it is giving error.can someone tell me how to do this?
enter code here
Private Sub check()
Dim Myconn As New OleDbConnection(constr)
Dim adapter As New OleDbDataAdapter()
Dim command As New OleDbCommand()
Dim sql = "select descriptionofgoods,remarks,mode from tabel1 INNER JOIN table2 ON tabel1.id = tabel2.id inner join tabel3 on tabel1.id = tabel3.id;"
Try
Myconn.Open()
dt.Clear()
If TextBox2.Text > "" Then
sql = sql & " and [id] = ? "
command.Parameters.AddWithValue("id", TextBox1.Text)
End If
command.Connection = Myconn
command.CommandText = sql
adapter.SelectCommand = command
adapter.Fill(dt)
If dt.Rows.Count > 0 Then
DataGridView1.DataSource = dt
DataGridView1.Refresh()
Else
MessageBox.Show("ITEM NOT FOUND")
End If
Catch exp As Exception
Throw exp
Finally
If Myconn IsNot Nothing Then Myconn.Close()
End Try
End Sub
A lot of your code is redundant and can be removed:
Using da as New OleDbDataAdapter("select descriptionofgoods,remarks,mode from tabel1 INNER JOIN table2 ON tabel1.id = tabel2.id inner join tabel3 on tabel1.id = tabel3.id", constr)
Dim dt = DirectCast(DataGridView1.DataSource, DataTable)
dt.BeginLoadData()
dt.Clear()
If Not string.IsNullOrEmpty(TextBox2.Text) Then
da.SelectCommand.CommandText &= " and tabel1.[id] = ? "
da.SelectCommand.Parameters.AddWithValue("id", TextBox1.Text) 'why is this TextBox1 when you tested textbox2 in the If?
End If
adapter.Fill(dt)
dt.EndLoadData()
End Using
Notes:
Use Using; you then don't need your Try/Finally
DataAdapter knows how to create and open a connection itself
Don't catch exceptions only to throw them again; it disrupts the stack trace. Dont put a catch at all if youre not going to catch anything; Try ... Finally is legal, Throw on its own is legal (doesn't disrupt stack trace)
Do not terminate an SQL with a semicolon if you want to add to it. Don't terminate a single statement SQL with a semicolon anyway
You have several tables with an ID column; Access might let you get away with not specifying which ID you're talking about but proper databases won't so get in the habit now of fully qualifying every column (in your select too)
See the comment about TextBox1/TextBox2
Please.. name your controls properly. "name of a type of object plus a serial number" is not a good name for anything; your name is Pankaj Babbar, not human105874274365. You name your local variables well but not your class level ones, which is definitely the wrong way round
To rename a control after you add it to a windows form, click on it, then change then text in the (Name) line of the property grid
Telling a datatable youre about to/have finished loading data improves performance
Bound controls update automatically (if you ever use BindingSource investigate the RaiseListChangedEvents setting too)
I am trying to get values from selected columns of the last row into label 1 and label 2 when the form is loaded from a SQL database. My code is not working. How can I do this?
My code is here:
Private Sub getvalue()
Dim strConn = "server= PANKAJ\SQLEXPRESS; database = pankaj billing software; integrated security=true"
Dim sqlConn = New SqlConnection(strConn)
sqlConn.Open()
Dim sqlcmd As New SqlCommand("select 22ktrate, 21ktrate from ratedata where max(rateid) = #rateid", sqlConn)
Dim myreader As SqlDataReader
myreader = sqlcmd.ExecuteReader()
myreader.Read()
If myreader.HasRows Then
Label1.Text = myreader.Item("22ktrate")
Label2.Text = myreader.Item("21ktrate")
End If
sqlConn.Close()
End Sub
The big thing I noticed is nothing sets the #rateid parameter.
Private Sub getvalue()
Dim conn As String = "server= PANKAJ\SQLEXPRESS; database = pankaj billing software; integrated security=true"
Dim sql As String = "select [22ktrate], [21ktrate] from ratedata where max(rateid) = #rateid"
Using sqlConn As New SqlConnection(conn), _
sqlcmd As New SqlCommand(sql, sqlConn)
'This was missing. You need to know what to set for 1234 here.
'I suggest adding it as argument to the method.
sqlcmd.Parameters.Add("#rateid", SqldbType.Int).Value = 1234
sqlConn.Open()
Using myreader As SqlDataReader = sqlcmd.ExecuteReader()
If myreader.Read() Then
Label1.Text = myreader("22ktrate").ToString()
Label2.Text = myreader("21ktrate").ToString()
End If
End Using
End Using
End Sub
I made other structural changes to the code, too, and you should follow this new pattern. The original code in the question had several less-noticeable issues that could eventually cause user-facing issues, such as failing to close the connection if an exception was thrown.
Finally, I saw this in the comments:
i just want last row two selected column values from sql database
There is no ORDER BY clause in that select statement. Without an ORDER BY clause, the order for the rows is undefined and Sql Server is free to give you the rows in any order it finds convenient. There is no meaningful definition for "last row". If this matters, you must add an ORDER BY clause to the sql statement... at which point, you are better off inverting the order and only taking the first record, rather than iterating the entire result set. If it doesn't matter... you're still better of just taking the first row vs iterating the entire set. In either case, you could also add a TOP 1 to the SQL command — if it's even possible to have more than one record match the max(rateid).
Actually, I can see that you're already using the reader to check if it had rows.
Just set the last value AFTER the reader has read.
This assumes that the Order by of your SQL query is correct (asc or desc)
Change this part:
myreader = sqlcmd.ExecuteReader()
myreader.Read()
If myreader.HasRows Then
Label1.Text = myreader.Item("22ktrate")
Label2.Text = myreader.Item("21ktrate")
End If
sqlConn.Close()
to
While myreader.Read()
Label1.Text = myreader.Item("22ktrate")
Label2.Text = myreader.Item("21ktrate")
End While
sqlConn.Close()
Currently I'm trying to understand and learn new code commands for vb.net. i have came across three codes while researching which is
"SELECT staff_id,pass_word FROM userlogin WHERE staff_id = #staff_id AND pass_word = #pass_word")
Second code:
Dim uName As New OleDbParameter("#staff_id", SqlDbType.VarChar)
Third and last:
uName.Value = txtstaffid.Text
myCommand.Parameters.Add(uName)
What are the uses of #pass_word code when you have already typed the pass_word column, Oledbparameter, and Parameters.Add?
The following code shows a bit more complete picture of what the code is doing. The Using...End Using blocks ensure that your objects are closed and disposed even if there are errors. Of course, in a real application, passwords would never be stored as plain text (too easy to hack). They would be salted and hashed but that is for another day.
Private Sub CheckPassword()
'This line assigns a Transact SQL command to a string variable.
'It will return a record with 2 columns. The #staff_id and #pass_word are parameter placeholders.
'The use of parameters limits the possibilit of SQL injection with malicious input be the user
'typing in the text box.
Dim strSQL = "SELECT staff_id,pass_word FROM userlogin WHERE staff_id = #staff_id AND pass_word = #pass_word;"
Using cn As New SqlConnection("Your connection string")
'Pass the command string and the connection to the constructor of the command.
Using cmd As New SqlCommand(strSQL, cn)
'It is unneccessary to create a command variable.
'The .Add method of the commands Parameters collection will create a parameter.
cmd.Parameters.Add("#staff_id", SqlDbType.VarChar).Value = txtstaffid.Text
cmd.Parameters.Add("#pass_word", SqlDbType.VarChar).Value = txtPassword.Text
cn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader
'All we really need to know is whether we returned a row.
If dr.HasRows Then
MessageBox.Show("Login Successful")
Else
MessageBox.Show("Login Failed")
End If
End Using
End Using
End Using
End Sub
I am developing an information system that works with a connected data source / MS Access database. The question is kinda cliche but I can't seem to find a proper solution from the similar ones I have come across.
Here is my code for the button.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'myConnection.ConnectionString = connString
'myConnection.Open()
If Me.txtConfirmPasscode.Text = Me.txtNewPasscode.Text Then
Dim updateCmd As OleDbCommand = New OleDbCommand("UPDATE Users SET Password = #ConfPasscode WHERE [Usernames] = #UsersID", myConnection)
Dim dr2 As OleDbDataReader = updateCmd.ExecuteReader 'SYNTEX ERROR IN UPDATE STATEMENT
With updateCmd.Parameters
updateCmd.Parameters.AddWithValue("#value", txtUserID.Text)
updateCmd.Parameters.AddWithValue("#firstname", txtConfirmPasscode.Text)
End With
updateCmd.ExecuteNonQuery()
Dim recFound As Boolean = False
Dim UserName As String = ""
While dr2.Read
recFound = True
UserName = dr2("Usernames").ToString
End While
If recFound = True Then
MessageBox.Show("Password changed successfully for " & UserName & ".", "Password Changed", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
'updateCmd.Parameters.Add(New OleDbParameter("Password", CType(txtConfirmPasscode.Text, String)))
Else
myConnection.Close()
Me.Refresh()
End If
Else
End If
Try
myConnection.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
I get a huge UPDATE statement syntax error when I reach these lines of code:
Dim updateCmd As OleDbCommand = New OleDbCommand("UPDATE Users SET Password = #ConfPasscode WHERE [Usernames] = #UsersID", myConnection)
Dim dr2 As OleDbDataReader = updateCmd.ExecuteReader 'I GET THE SYNTAX ERROR IN UPDATE STATEMENT ERROR HERE!
I hope that I can get a solution that works without overly formatting the code. I would also like to get solutions to my code grammer / syntax that could possibly cause some other problems in the above code
Password is a reserved keyword in ms-access. You need square brackets around it, but then you have another problem. You should set the parameters BEFORE executing the query, and albeit OleDb doesn't recognize parameters by name but by position, giving a matching name with your placeholders doesn't hurt
Dim updateCmd As OleDbCommand = New OleDbCommand("UPDATE Users
SET [Password] = #ConfPasscode
WHERE [Usernames] = #UsersID", myConnection)
With updateCmd.Parameters
' First ConfPasscode because is the first placeholder in the query
updateCmd.Parameters.AddWithValue("#ConfPasscode ", txtConfirmPasscode.Text)
' Now UsersID as second parameter following the placeholder sequence
updateCmd.Parameters.AddWithValue("#UsersID", txtUserID.Text)
End With
Dim rowUpdated = updateCmd.ExecuteNonQuery
....
In response to the comment below of Andrew Morton, I should mention to the problems caused by AddWithValue. In this context, with just strings, it is a performance problem, in other context (dates and decimals) could escalate to a correctness problem.
References
Can we stop to use AddWithValue already?
How data access code affects database performance
Also, as noted in another answer, the correct method to use for an Update query is ExecuteNonQuery, but also ExecuteReader can update your table but because it build an infrastructure required only when you have something to read is less efficient for an Update. In any case just use only ExecuteNonQuery or ExecuteReader
I notice that your execute your UPDATE command using executereader. It means that you will be returning a record after the update. On your query it only trigger update query. Maybe try putting it on stored procedure and selecting the updated records after the changes made.
In my application I create a function that allow the user to change the settings of the app. This settings are stored into a table 'cause there's a lot of records. Anyway, the problem's that if the settings isn't valorized yet, when the application start and load the settings from the table take of course a null GUID field and the message:
GUID format not recognized
appear. A code explaination:
Sub LoadSettings()
Using dbCon As MySqlConnection = establishConnection()
Try
dbCon.Open()
Dim MysqlCommand = New MySqlCommand("SELECT * FROM settings", dbCon)
Dim reader = MysqlCommand.ExecuteReader
For Each row In reader
Select Case row(2)
Case "company_name"
Setting.name.Text = row(3)
Case "company_email"
Setting.email.Text = row(3)
...
End Select
Next
End Sub
This function is called when the settings form is opened. If the settings aren't inserted yet, I get a message of bad format. I want to know how I can avoid this message.
You are not using the DataReader correctly. Consider this code:
Dim reader = MysqlCommand.ExecuteReader
For Each row In reader
... something
Next
MysqlCommand.ExecuteReader returns a DataReader object, but it is not - nor does it contain - a row collection you can iterate. If you hold the mouse over row you should see that it is a Data.Common.DataRecordInternal object which does have an Item property but a reference like row(2) will only compile with Option Strict Off.
Used correctly, when you Read a row the data in that internal object is available via the indexer (Item) and the various Getxxxxx() methods. This just prints the Id and Name from a table in a loop. I cant quite tell what you are trying to do with your results...it sort of looks like a Name/Value pair type thing maybe.
Dim SQL = "SELECT * FROM Demo"
Using dbcon = GetMySQLConnection(),
cmd As MySqlCommand = New MySqlCommand(SQL, dbcon)
dbcon.Open()
Using rdr As MySqlDataReader = cmd.ExecuteReader
If rdr.HasRows Then
Do While rdr.Read()
Console.WriteLine("{0} - {1}", rdr("Id").ToString, rdr("Name").ToString)
Loop
End If
End Using ' dispose of reader
End Using ' dispose of Connection AND command object
Alternatively, you could fill a DataTable and iterate the rows in that. Seems 6:5 and pick-em whether that would gain anything.
Note also that the Connection, Command and DataReader objects are properly disposed of when we are done using them.