how can i open execuete a query in VB while there is reader opened? - mysql

is there any possible way to execute this without getting this error "There is already an open DataReader associated with this Connection which must be closed first." i already tried using "dr.close()" and i get another error that says "Invalid attempt to Read when reader is closed." can you help me out?
Heres my code:
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Label2.Text = AllPicker1.Text
Label3.Text = AllPicker2.Text
If AllPicker1.Value >= AllPicker2.Value Then
MsgBox("End Date Must be Greater!")
Else
Dim SQLstatement As String = "SELECT * FROM tblStudInfo,tbl_studentLog WHERE tblStudInfo.StudID = tbl_studentLog.StudentNumber AND tbl_studentLog.LoginDate BETWEEN '" & AllPicker1.Text & "' AND '" & AllPicker2.Text & "'"
OpenData(SQLstatement)
End If
End Sub
Public Sub OpenData(ByRef SQLstatement As String)
Dim cmd As MySqlCommand = New MySqlCommand
With cmd
.CommandText = SQLstatement
.CommandType = CommandType.Text
.Connection = SqlConnection
dr = .ExecuteReader()
End With
While dr.Read
Dim SQLstatementSave As String = "INSERT INTO tbl_report (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate) VALUES ('" & dr("StudID") & "','" & dr("Name") & "','" & dr("Course") & "','" & dr("Dept") & "','" & dr("LoginTime") & "','" & dr("LoginDate") & "') "
dr.Close()
Save(SQLstatementSave)
End While
SqlConnection.Close()
SqlConnection.Dispose()
SqlConnection.Open()
End Sub
Public Sub Save(ByRef SQLstatementSave As String)
Dim cmd As MySqlCommand = New MySqlCommand
With cmd
.CommandText = SQLstatementSave
.CommandType = CommandType.Text
.Connection = SqlConnection
.ExecuteNonQuery()
End With
SqlConnection.Close()
SqlConnection.Dispose()
SqlConnection.Open()
End Sub
End Class

It seems you are using only one SqlConnection. For most database systems you cannot reuse the connection while you are reading from it. You can either read all data into memory / DataTable and work on the rows after that or use a different SqlConnection for your Inserts.
When working with SqlConnections, Readers and Commands I find the Using Statement very helpful to visualize object usage and creation.

We can reduce this down to a single query:
INSERT INTO tbl_report
(RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate)
SELECT StudID, Name, Course, Dept, LoginTime, LoginDate
FROM tblStudInfo
INNER JOIN tbl_studentLog ON tblStudInfo.StudID = tbl_studentLog.StudentNumber
WHERE tbl_studentLog.LoginDate BETWEEN #StartDate AND #EndDate
Note the use of the full INNER JOIN syntax. The older TableA,TableB syntax for joins should be avoided. Also note the use of placeholders for your dates. This is important.
Now I need to draw attention to a couple functions I saw: OpenData(), and Save().
Those two functions are fundamentally broken, because they force you to build your queries in a way that leaves you vulnerable to sql injection hacking. Someday soon, someone will put a value like this into a textbox that is included with a query:
';DROP Table tbl_studentLog;--
Think carefully about what would happen now if someone entered that into your AllPicker1.Text. It would be hard to do that to a date picker, but I'll bet you have other plain text fields that would allow this. The first character (single quote) in my proposed input would close the string literal in the query. The second character (semi-colon) would end the individual statement, but sql server won't stop executing code. The next set of characters make up an additional statement that would drop your table. The final two characters comment out anything that follows, to avoid sql server rejecting or not committing the command because of syntax errors. Yes, Sql Server will run that additional statement, if that is what you put in a textbox.
So, your methods as written are broken, because the only accept completed sql strings as input. Any function that calls into the database MUST also include a mechanism for accepting query parameters. You ultimately want to be running code more like this:
Public Sub CreateReport(ByVal StartDate As DateTime, ByVal EndDate As DateTime)
Dim sql As String = _
"INSERT INTO tbl_report " & _
" (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate) " & _
" SELECT StudID, Name, Course, Dept, LoginTime, LoginDate " & _
" FROM tblStudInfo " & _
" INNER JOIN tbl_studentLog ON tblStudInfo.StudID = tbl_studentLog.StudentNumber " & _
" WHERE tbl_studentLog.LoginDate BETWEEN #StartDate AND #EndDate"
'.Net is designed such in most cases that you really do want a new SqlConnection for each query
'I know it's counter-intuitive, but it is the right way to do this
Using cn As New SqlConnection("Connection string"), _
cmd As New SqlCommand(sql, cn)
'Putting your data into the query using parameters like this is safe from injection attacks
cmd.Parameters.Add("#StartDate", SqlDbType.DateTime).Value = StartDate
cmd.Parameters.Add("#EndDate", SqlDbType.DateTime).Value = EndDate
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub
One thing to point out here is that at first glance I don't close the connection. However, the Using block will ensure that the connection is closed promptly... even if an exception is thrown. Your existing code will leave the connection hanging in the case of a exception.
Also note that this neatly side-steps the whole issue of needing to execute a separate query while your reader is opened... but if you ever do really need to do this (it's rare), the answer is simple: use a separate connection.

Instead of:
Dim SQLstatementSave As String = "INSERT INTO tbl_report
(RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate)
VALUES ('" & dr("StudID") & "','" & etc.
Try using .ToString on your DR() references.
Dim SQLstatementSave As String = "INSERT INTO tbl_report
(RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate)
VALUES ('" & dr("StudID").ToString & "','" & etc.

Related

HOW TO USE UPDATE IN SQL WITH VB

Can you please help me, what the problem of my code:
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
'UPDATE Data
openCon()
Try
cmd.Connection = con
cmd.CommandText = "UPDATE emp_table SET FNAME = '" & TextBox1.Text & "', LNAME= '" & TextBox2.Text & "', AGE = '" & TextBox3.Text & "', GENDER ='" & Gender & "', OFFICE STAFF= '" & ComboBox1.Text & "' Where ID ='" & TxtID.Text & "' "
cmd.ExecuteNonQuery()
con.Close()
MsgBox("Suceessfully Updated Record")
TxtID.Clear()
TextBox1.Clear()
TextBox2.Clear()
TextBox3.Clear()
RBMale.Checked = False
RBFemale.Checked = False
ComboBox1.Text = ""
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
There are many problems in your code and if you look around this site I think you will find many partial answers that step by step will help you solve your problems. So I try to give you an answer where all the problems are examined, discussed and solved.
First problem: How do you handle the connection.
It seems that you have a global connection instance called con that you open with openCon. This is not a good approach and always a source of problems. You always need to check if the connection is closed properly or not. For example, in the code above you have forgot to close the connection in case of exception and this will lead to other exceptions in some code not related to this one. You keep resources on the server locked to you and this will decrease the performance of every one connection to that server.
I would change your openCon to this
Public Function openCon() as MySqlConnection
Dim con as MySqlConnection = new MySqlConnection(....here connection string ...)
con.Open()
return con
End Function
This will create a new instance of the MySqlConnection every time you call this method Now you can remove the global connection instance and use the one returned by openCon in this way
Using con As MySqlConnection = openCon()
.... code that use the local con object
End Using
This will close and destroy the connection even if an exception occurs inside the Using block and the ADO.NET libraries are smart enough to use a thing called Connection Pooling to reduce the time required to build and open a connection with the same connection string.
Second problem: The syntax error.
Looking at the point of the error suggested by the message I can see a field name composed by two words separated by a space. This is fine, but then you should remember that the sql parser cannot understand this and you need to help it enclosing the two words in a backtick character (ALT+096) so the parser understand that this is a single field name. Given the fact column names are an internal information of no concern for your end user then why use spaces in column names? If possible remove the space in column names.
Third problem: Sql Injection and other syntax errors
You are concatenating strings to build an sql command. But this is an easy target for wannabe hackers. Suppose that I write in your textBox1 this string instead of a First Name: Mario'; --
Then your command becomes
UPDATE emp_table SET FNAME = 'Mario'; -- xxxxxxxxxxxx
everything after -- is considered a comment and the query is still executable, but it changes every record in emp_table to have a first name equal to Mario.
But the query could fail as well if someone writes a Last Name that contains an apostrophe like O'Leary just now the query is no more syntactically valid.
The solution to this is always one. Use Parameters.
Recap of changes to your code.
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim cmdText as String = "UPDATE emp_table SET FNAME = #fname,
LNAME= #lname, AGE = #age, GENDER =#gender,
`OFFICE STAFF` = #staff
Where ID =#id"
Using con as MySqlConnection = openCon()
Using cmd as MySqlCommand = new MySqlCommand(cmdText, con)
Try
cmd.Parameters.Add("#fname", MySqlDbType.VarChar).Value = textBox1.Text
cmd.Parameters.Add("#lname", MySqlDbType.VarChar).Value = textBox2.Text
cmd.Parameters.Add("#age", MySqlDbType.VarChar).Value = textBox3.Text
cmd.Parameters.Add("#gender", MySqlDbType.VarChar).Value = gender
cmd.Parameters.Add("#staff", MySqlDbType.VarChar).Value = combobox1.Text
cmd.Parameters.Add("#id", MySqlDbType.VarChar).Value = txtID.Text
cmd.ExecuteNonQuery()
MsgBox("Suceessfully Updated Record")
TxtID.Clear()
TextBox1.Clear()
TextBox2.Clear()
TextBox3.Clear()
RBMale.Checked = False
RBFemale.Checked = False
ComboBox1.Text = ""
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Using
End Using
End Sub
In the recap I have added parameters for every single field that you want to update. But remember. Parameters should have a Type (The MySqlDbType here) that should match the type of the field and the value should be of the same type. For example it seems improbable that Age is a varchar field. So you should convert TextBox3.Text to an integer if the field is an integer.

I get two error messages when trying to insert a data to MySQL table

I get these two error messages,
'ExecuteReader' is not a member of 'WindowsApplication1.MySqlCommand'
Too many arguments to 'Public Sub New()' {This error occurs in (query, conn) field}
Little explanation about what I am trying to do
Here I am trying to make an application that will input data to separate databases (Men, Women and Kids) using If pub = "" (pub is mentioned in another) Then according to ComboBox1 the table may get differ. According to the table the values need to be inserted.
This is the code I am using
Dim T As String
T = ComboBox1.Text
If pub = "Women" Then
conn = New MySqlConnection
conn.ConnectionString = "server=localhost;user=root;password=1234;database=women_clothing"
Dim reader As MySqlDataReader
Try
conn.Open()
Dim query As String
query = "INSERT INTO [" + T + "] VALUES ('" & TextBox1.Text & "','" & TextBox2.Text & "','" & TextBox3.Text & "','" & TextBox4.Text & "'," & Val(TextBox5.Text) & "," & Val(TextBox6.Text) & ");"
command = New MySqlCommand(query, conn)
reader = Command.ExecuteReader
MessageBox.Show("Data Saved")
conn.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
conn.Dispose()
End Try
loadtable()
ElseIf pub = "Men" Then
Else
End If
loadtable()
Thank You
You shouldn't use ExecuteReader for executing a statement that inserts data. ExecuteReader is for SELECT queries. ExecuteNonQuery is for INSERTs
Your code should look like:
Using conn = New MySqlConnection("server=localhost;user=root;password=1234;database=women_clothing")
Using cmd = New MySqlCommand("INSERT INTO tableName VALUES (#p1,#p2,#p3,#p4,#p5,#p6)", conn)
conn.Open()
cmd.Parameters.AddWithValue("#p1", TextBox1.Text)
cmd.Parameters.AddWithValue("#p2", TextBox2.Text)
cmd.Parameters.AddWithValue("#p3", TextBox3.Text)
cmd.Parameters.AddWithValue("#p4", TextBox4.Text)
cmd.Parameters.AddWithValue("#p5", TextBox5.Text)
cmd.Parameters.AddWithValue("#p6", TextBox6.Text)
cmd.ExecuteNonQuery()
End Using
End Using
I've also demonstrated how to use parameters; always use parameters. Your code as it stands is massively at risk of SQL injection attack hacking, and if that doesn't dissuade you enough to not write code in this way, bear in mind that your app will crash if anyone enters an apostrophe in one of your textboxes (which will then give the more astute tech whizzkids using it the idea that it's prone to injection hacking, then they will break into it) which looks bad to the end user (and makes them complain to your helpdesk/you).
It doesn't matter that "it's only a simple app for my grandma to index her vinyl collection" - this is about NOT learning a pattern of behavior that is plain risky, bordering on career-limiting if you want to take your coding skills into the software development world. As the VTech hack linked above shows, there are now 5 million images of children floating around out there whose parents never authorized their release, all because a few people didn't take proper precautions in doing their job. If any of my developers wrote an injection prone SQL, given the nature of one of the industries I work in, they'd just get fired.
Also, please get into the habit of renaming your textboxes after you add them to the form. It's incredibly difficult for anyone (yourself included, 6 months down the line) to have to constantly look up "hmm, what is the first name textbox? is it textbox2 or textbox3?" it takes about 2 seconds to type something new in the (Name) line of the property grid after you add the textbox to the form; firstNameTextBox is far better than textBox2
With credit to #Caius, this is a variation using ConnectionStringBuilder, a With block, a composite Using block and string interpolation, just for illustration.
NOTE the use of As in lieu of = when declaring the connection and command; this is to formally set the types rather than rely on Infer to determine them.
Dim connStr As New MySqlConnectionStringBuilder() With {
.Server = "localhost",
.Database = "women_clothing",
.UserID = "root",
.Password = "1234"
}
' -> "server=localhost;database=women_clothing;user id=root;password=1234"
Using conn As New MySqlConnection(connStr.ConnectionString),
cmd As New MySqlCommand($"INSERT INTO [{T}] VALUES (#p1, #p2, #p3, #p4, #p5, #p6)", conn)
conn.Open()
With cmd
.Parameters.AddWithValue("#p1", TextBox1.Text)
.Parameters.AddWithValue("#p2", TextBox2.Text)
.Parameters.AddWithValue("#p3", TextBox3.Text)
.Parameters.AddWithValue("#p4", TextBox4.Text)
.Parameters.AddWithValue("#p5", TextBox5.Text)
.Parameters.AddWithValue("#p6", TextBox6.Text)
.ExecuteNonQuery()
End With
conn.Close()
End Using

Im trying to insert a data into database using vb

I am trying to add a new data in mySql database using vb . But the error always says [unit_type] is not allowed to be null . I even changed the column's setting in the main database . I disabled the not null checkbox .
Dim datetoday = Date.Today
Try
command = "INSERT INTO assets_table ([date_created], [unit_type]) VALUES ('" & datetoday & "' , '" & frm_viewAssets.lbl_fetch.Text & "')"
Dim cmd As MySqlCommand = New MySqlCommand(command, myconn.open())
cmd.Parameters.Add(New MySqlParameter("date_created", CType(datetoday, String)))
cmd.Parameters.Add(New MySqlParameter("unit_type", CType(frm_viewAssets.lbl_fetch.Text, String)))
Try
cmd.ExecuteNonQuery()
cmd.Dispose()
myconn.close()
Catch ex As Exception
myconn.close()
End Try
You did the right thing by trying to use parameters but you did it wrong. You added the parameters to the command but, instead of using parameter place-holders in your SQL, you still inserted the literal values. This:
command = "INSERT INTO assets_table ([date_created], [unit_type]) VALUES ('" & datetoday & "' , '" & frm_viewAssets.lbl_fetch.Text & "')"
should be this:
command = "INSERT INTO assets_table ([date_created], [unit_type]) VALUES (#date_created, #unit_type)"
and then I think that you will need to add the "#" prefix to the parameter names when you create them as well.
Keep the database objects local so you can be sure they are closed and disposed. Using...End Using blocks will handle that for you even if there is an error.
Don't open the connection until directly before the .Execute.
I assumed the type of date_created to be a Date.
It can improve the efficiency of your sql to include the datatypes of your parameters.
If all you are doing in your Try/Catch is closing the connection you are just swallowing errors.
Private Sub OPCode()
Dim datetoday = Date.Today
Dim Command = "INSERT INTO assets_table ([date_created], [unit_type]) VALUES (#date_created , #unit_type);"
Using myconn As New MySqlConnection("Your connection string"),
cmd As New MySqlCommand(Command, myconn)
cmd.Parameters.Add("#date_created", MySqlDbType.Date).Value = datetoday
cmd.Parameters.Add("#unit_type", MySqlDbType.VarChar).Value = frm_viewAssets.lbl_fetch.Text
myconn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub

Is .ExecuteNonQuery() required to add sql data to a DB in vb.net

I am running the following code (part of it) to connect to PHPmyadmin DB
Private Sub sreg_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
SqlConnection.ConnectionString = ServerString
Try
If SqlConnection.State = ConnectionState.Closed Then
SqlConnection.Open()
MsgBox("Successfully connected to MySQL DB")
Else
SqlConnection.Close()
MsgBox("Connection is Closed")
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Public Sub SaveNames(ByRef SQLStatment As String)
Dim cmd As MySqlCommand = New MySqlCommand
With cmd
.CommandText = SQLStatment
.CommandType = CommandType.Text
.Connection = SqlConnection
.ExecuteNonQuery()
End With
SqlConnection.Close()
MsgBox("Succesfully Added!")
SqlConnection.Dispose()
End Sub
However the .ExecuteNonQuery() is giving me huge headaches in terms of errors and problems. It uploads the data but, it can only do it once (one upload) before, it returns an error.
When I remove the .ExecuteNonQuery() no data gets uploaded? So I guess it is necessary.
Here is the code im uploading (part of it)
sql = "INSERT INTO students(student_id, title, initial, surname,
street, city, pcode, country ) VALUES ('" & strStudent & "', '"
& vtital & "', '" & vinital & "', '" & vsurname & "', '" & vstreet
& "', '" & vcity & "', '" & vpcode & "', '" & vcountry & "' )"
SaveNames(sql)
Hope my question makes sense and that I can get the message across
There are some errors in your approach to save this data that could lead to your problem.
The first problem is that code doesn't use a parameterized query. This is a security concern (Sql Injection) but also a simple logical problem. If you concatenate strings to build a sql query you have a problem with strings that contains characters with a special meaning for the database sql engine. What if one of your strings contains a single quote? It will be seen as the end of the string with the remainder of your text as invalid sql.
The second problem is the lacking of open/close/dispose of the MySqlConnection also in case of exceptions. This is resolved by using the Using Statement.
So I would rewrite your method as
Public SaveNames(ByRef SQLStatment As String, List(Of MySqlParameter) parameters) As Integer
Using con = new MySqlConnection(... put here the connection string...)
Using cmd = New MySqlCommand(SQLStatment, con)
if parameters.Count > 0 Then
cmd.Parameters.AddRange(parameters.ToArray())
End If
return cmd.ExecuteNonQuery()
End Using
End Using
End Function
And call it with code like this
sql = "INSERT INTO students(student_id, title, initial, surname," & _
"street, city, pcode, country ) VALUES (#id,#title,#init,#sur," & _
"#street,#city,#pcode,#country)"
Dim ps = New List(Of MySqlParameters)()
Dim p = new MySqlParameter("#id", MySqlDbType.Int32).Value = Convert.ToInt32(strStudent)
ps.Add(p)
p = new MySqlParameter("#title", MySqlDbType.VarChar).Value = vtital
ps.Add(p)
.. and so on for the other parameters.
.. respecting the actual datatype on the database table
.....
SaveNames(sql, ps)
Try this ...
cmd = New MySqlCommand( sqlstatement, conn)
conn.open()
cmd.ExecuteNonQuery()
conn.Close()
And as I suggested you .. use parameterized

MySql query statement syntax error

I am getting a syntax error for the code below.
I am trying to create a user in the mysql database and add their information to a datagrid control all in one button click using two statements; one to create the actual user, and one to add the user and their additional information to a table on the database and then refresh the datasource which will display the new user's information in the datagrid control.
If anyone knows where i went wrong please feel free to critique my code and let me know; or simply offer more efficient alternatives to what im hoping to achieve.
For those of you that must know, i am running the latest version of MySql server, MySql Workbench, and Visual Basic 2010 Express on a windows 7 based laptop. I'm writing this program in VB.net.
Thanks!
Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
Dim sqluser As MySqlCommand = New MySqlCommand(
"CREATE USER " & txtuser.Text & "#" & frmLogin.txtserver.Text & " IDENTIFIED BY '" & txtpass.Text & "';", con)
Dim sqlinfo As MySqlCommand = New MySqlCommand(
"INSERT INTO employee(Name ,Title) VALUES('" & txtname.Text & "','" & txttitle.Text & "';", con)
Try
con.Close()
con.Open()
sqluser.ExecuteNonQuery()
MessageBox.Show("User Account successfully created!!")
sqlinfo.ExecuteNonQuery()
' retrieving the administration table.
DataAdapter1.SelectCommand = sqladmin
DataAdapter1.Fill(ds, "stratos")
DataGrid1.DataSource = ds
DataGrid1.DataMember = "stratos"
con.Close()
MessageBox.Show("User Information successfully created!!")
Catch myerror As MySqlException
MessageBox.Show("Error Setting Up Account: " & myerror.Message)
End Try
End Sub
You are missing a ')' at the end of your insert statement.
Dim sqlinfo As MySqlCommand = New MySqlCommand("INSERT INTO employee(Name ,Title ) VALUES('" & txtname.Text & "','" & txttitle.Text & "');"
I would also like to point out that this code will fail if the text has an apostrophe in it, and that it is wide open to SQL Injection. Please read up.
I think you may also need apostrophes around the username and host.
CREATE USER '" & txtuser.Text & "'#'" & frmLogin.txtserver.Text & "' IDENTIFIED BY '" & txtpass.Text & "';"
As for SQL Injection, I would recommend you consider reworking your code to use prepared statements like this. Replace those first two lines with this instead. Basically, you put in little placeholders in your query, and let the database driver handle all of the complex escaping and quoting of things for you. I'm not 100% sure this will work, but I think it's close.
Dim sqluser As MySqlCommand = New MySqlCommand("CREATE USER ?user#?host IDENTIFIED BY ?pass;", con)
sqluser.Parameters.Add("?user", txtuser.Text)
sqluser.Parameters.Add("?host", frmLogin.txtserver.Text)
sqluser.Parameters.Add("?pass", txtpass.Text)
sqluser.Prepare()
Dim sqlinfo As MySqlCommand = New MySqlCommand("INSERT INTO employee(Name ,Title) VALUES( ?user, ?title );", con)
sqlinfo.Parameters.Add("?user", txtuser.Text)
sqlinfo.Parameters.Add("?title", txttitle.Text)
sqlinfo.Prepare()
It has been ages since I did any VB, so this is mostly based on this page. Try to look here if this doesn't quite work. Documentation on Prepare