OleDbException was unhandled.......Syntax error in UPDATE statement - vb.net

I get that Error when i debug please can someone help please...
Below is the code:
Private Sub UpdateToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UpdateToolStripMenuItem.Click
If MsgBox("Save Changes?", MsgBoxStyle.Question + MsgBoxStyle.YesNo, "WARNING") = MsgBoxResult.Yes Then
Dim oleDC As New OleDbCommand
With oleDC
.Connection = conn
.CommandText = "UPDATE tblPatientsRecord SET Names='" & txtNames.Text & _
"',Licensenumber='" & txtLicensenumber.Text & _
"',Address='" & txtAddress.Text & _
"',Fullname='" & txtFullname.Text & _
"',Birthday='" & txtBase.Text &
"',Age='" & txtAge.Text & _
"',Country='" & cmbCountry.Text & "' WHERE PatientID='" & txtPatientID.Text & "'"
.ExecuteNonQuery()
MsgBox("Record Updated!", MsgBoxStyle.Information + MsgBoxStyle.OkOnly, "SUCCESS")
Disable()
Clear()
SaveToolStripMenuItem.Enabled = False
NewToolStripMenuItem.Enabled = True
LoadPatientsRecord()
getLastPatientID()
End With
End If
End Sub
help please

You should use SQL parameters. These will not only simplify your code, they will make certain kinds of errors regarding syntax and data types extremely unlikely and protect against SQL injection attacks:
Dim sql = <sql>
UPDATE tblPatientsRecord SET [Names] = #p1,
Licensenumber = #p2,
Address = #p3,
Fullname = #p4,
Birthday = #p5,
[Age] = #p6,
Country = #p7
WHERE PatientID = #p8
</sql>.Value
Using conn = New OleDbConnection(myConnStr),
cmd As New OleDbCommand(sql, conn)
conn.Open()
cmd.Parameters.Add("#p1", OleDbType.VarChar).Value = txtNames.Text
cmd.Parameters.Add("#p2", OleDbType.VarChar).Value = txtLicensenumber.Text
' ...etc
cmd.Parameters.Add("#p6", OleDbType.Integer).Value = intVar
cmd.Parameters.Add("#p7", OleDbType.VarChar).Value = strVar
'the last one is the WHERE
cmd.Parameters.Add("#p8", OleDbType.VarChar).Value = Convert.ToInt32(lblPatientID.Text)
cmd.ExecuteNonQuery()
'... etc
End Using
There are several other commonly seen issues which should be tended to.
DBConnection objects are intended to be created, used and disposed of rather than the same one used over and over. However, you can use a global connection string so you don't have the same connection string all over the place.
Many of the DBObjects should be disposed of. Using blocks will close and dispose of the connection and command objects. Generally, if something has Dispose method, wrap them in a Using block. The above shows how to "stack" 2 objects (OleDbConnection and OleDbCommand) into one Using statement which reduces indentation.
Use the Add method rather than AddWithValue. This allows you to specify the datataype for each parameter. Without it, the DB Provider must guess which can result in Datatype mismatch or even corrupt the database in some instances.
The WHERE clause is just another parameter. Often people will use Parameters for the first part of the SQL but concatenate for the WHERE clause needlessly.
The above also uses an XML literal to construct the SQL. This is handy for long, complex SQL because you can format and indent it as you like. You can also just use multiple lines to make it readable :
Dim sql = "UPDATE tblPatientsRecord SET [Names] = #p1, " _
& "Licensenumber = #p2, " _
& "Address = #p3, "
If you use SQL reserved words or spaces in table or column names, you must escape the names using [Square Brackets] as shown. It is best not to use either in the names. User, Password Names and Values are commonly seen words used as column or table names which result in SQL syntax errors.
Ticks are not all-purpose SQL field delimiters, they actually indicate that the value being passed is string/text: & "Age ='" & txtAge.Text & "'". If the DB is set to store Age as a number, your SQL is passing it as text/string which can result in a data type mismatch. The same is true of PatientID and Birthday if it is a date field.
A common problem concatenating strings for a SQL statements is too many or too few ticks (') in the result. This cant happen with SQL Parameters.
The main purpose for SQL Parameters, though is to prevent an error if the name is "O'Brian" or "O'Reilly" or "Bobby';DROP TABLE tblPatientsRecord"
These principles apply for other DB providers such asMySql, SQLite and SQLServer. The details such as the exact escape character however will vary.
Note that Access/OleDB doesn't actually use named parameters as such (#FirstName or even #p2), so will often see params in the form of "?". This means that you must add the parameter values (Add/AddWithValue) in the same exact order as those columns appear in the SQL.
For more information see:
Using Statement
Connection Pooling

Related

Inserting byte() along side strings to SQL database

So here is the predefined SQL statement that is stored in the DAO file. The values are coming from a class. The picture value is an image converted to a byte(). This class is written in VB.net. I'm in a new job and in my previous i used angular and the entity framework so writing SQL statements is new to me. I'm trying to follow existing examples from co workers but they have never inserted images into the database before so i'm kinda on my own. Yes i know i could just store the files in the server and save the paths to them in the database but for whatever reason my network team wants it stored in the database as blobs. So, here is the SQL statement.
"INSERT INTO AuthAccessID" &
"(" &
"FName," &
"MName," &
"LName," &
"Suffix," &
"Address," &
"AddressExt," &
"City," &
"State," &
"Zip," &
"LawFirm," &
"Picture," &
"AddedDate," &
"AddedBy," &
")" &
"VALUES(" &
"" & ReplaceApostrophes(pp.FName) & ", " &
"'" & ReplaceApostrophes(pp.MName) & "', " &
"'" & ReplaceApostrophes(pp.LName) & "', " &
"'" & ReplaceApostrophes(pp.Suffix) & "', " &
"'" & ReplaceApostrophes(pp.Address) & "', " &
"'" & ReplaceApostrophes(pp.AddressExt) & "', " &
"'" & ReplaceApostrophes(pp.City) & "', " &
"'" & ReplaceApostrophes(pp.State) & "', " &
"'" & ReplaceApostrophes(pp.Zip) & "', " &
"'" & ReplaceApostrophes(pp.LawFirm) & "', " &
"'" & pp.Picture & "', " &
"'" & pp.AddedDate & "', " &
"'" & ReplaceApostrophes(pp.AddedBy) & "')
the pp.Picture is the Byte(). The error i'm getting is:
Operator '&' is not defined for types 'String' and 'Byte()'
i have googled around but cannot find anything. Does anyone have any idea how to correct this? or is there a better way to write the SQL statement? If i can't get this to work the network team said i can use the server file method but they are really pushing the blob in SQL storage instead. Thanks in advance.
Always use Parameters to avoid sql injection, make you sql statement easier to write and read, and make sure you are sending the correct datatypes. Parameters will also allow apostrophes. Use the .Add method. See http://www.dbdelta.com/addwithvalue-is-evil/
and
https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
and another one:
https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications
Here is another
https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html
In the code below, I had to guess at the SqlDbType and Size. Check your database for the correct information.
Connections and commands are using unmanaged resources. They release these resources in their .Dispose method so this method must be called. Using...End Using blocks take care of closing and disposing objects even if there is an error.
I assumed pp was an instance of a class. I gave the class the name Person. Correct this to the real class name.
Private ConStr As String = "Your connection string"
Private Sub InsertAuthAccessID(pp As Person)
Dim sql = "INSERT INTO AuthAccessID (
FName,
MName,
LName,
Suffix,
Address,
AddressExt,
City,
State,
Zip,
LawFirm,
Picture,
AddedDate,
AddedBy)
VALUES (
#FName,
#MName,
#LName,
#Suffix,
#Address,
#AddressExt,
#City,
#State,
#Zip,
#LawFirm,
#Picture,
#AddedDate,
#AddedBy)"
Using cn As New SqlConnection(ConStr),
cmd As New SqlCommand(sql, cn)
cmd.Parameters.Add("#FName", SqlDbType.VarChar, 50).Value = pp.FName
cmd.Parameters.Add("#MName", SqlDbType.VarChar, 50).Value = pp.MName
cmd.Parameters.Add("#LName", SqlDbType.VarChar, 100).Value = pp.LName
cmd.Parameters.Add("#Suffix", SqlDbType.VarChar, 20).Value = pp.Suffix
cmd.Parameters.Add("#Address", SqlDbType.VarChar, 200).Value = pp.Address
cmd.Parameters.Add("#AddressExt", SqlDbType.VarChar, 50).Value = pp.AddressExt
cmd.Parameters.Add("#City", SqlDbType.VarChar, 100).Value = pp.City
cmd.Parameters.Add("#State", SqlDbType.VarChar, 50).Value = pp.State
cmd.Parameters.Add("#Zip", SqlDbType.VarChar, 20).Value = pp.Zip
cmd.Parameters.Add("#LawFirm", SqlDbType.VarChar, 200).Value = pp.LawFirm
cmd.Parameters.Add("#Picture", SqlDbType.VarBinary).Value = pp.Picture
cmd.Parameters.Add("#AddedDate", SqlDbType.Date).Value = pp.AddedDate
cmd.Parameters.Add("#AddedBy", SqlDbType.VarChar, 50).Value = pp.AddedBy
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub
EDIT:
In older versions of VB that did not support multiline String literals, you can use an XML literal instead:
Dim sql = <sql>
INSERT INTO AuthAccessID (
FName,
MName,
LName,
Suffix,
Address,
AddressExt,
City,
State,
Zip,
LawFirm,
Picture,
AddedDate,
AddedBy)
VALUES (
#FName,
#MName,
#LName,
#Suffix,
#Address,
#AddressExt,
#City,
#State,
#Zip,
#LawFirm,
#Picture,
#AddedDate,
#AddedBy)
</sql>
Using cn As New SqlConnection(ConStr),
cmd As New SqlCommand(sql.Value, cn)
Too long and involved for a comment. You have the following snippet in your code:
")" &
"VALUES(" &
"" & ReplaceApostrophes(pp.FName) & ", " &
"'" & ReplaceApostrophes(pp.MName) & "', " &
That is an error. FName is a string and must be treated in exactly the same manner as you do with MName. It is missing the single quote delimiters.
More generally, this approach relies on converting all your "fields" into literals to embed them as strings within your tsql statement. So the question now becomes how do you "write" a binary literal in tsql. You would do that by generating a string like this: 0x69048AEFDD010E. Documentation for tsql constants is here. Knowing that, the next issue is how to do that in your dev language - which is not something I can answer. This look promising.
But before you go down this path, use parameterization and you NEVER have to deal with this ever again.
I come from a MSAccess background, so I code quite much the same way I did in VBA or now with VB.net
Here the code I would use:
Dim sFields() As String
sFields = Split("FName,MName,LName,Suffix,Address,AddressExt,City,State,Zip,LawFirm,AddedDate,AddedBy", ",")
Dim rst As DataTable
Dim da As SqlDataAdapter
rst = MyrstEdit("select * from AuthAccessID where id = 0", da, strcon)
With rst.Rows.Add
For Each s In sFields
.Item(s) = GetValue(pp, s)
Next
End With
da.Update(rst)
And I have two helper routines. The first one gets any class property by a "string" value.
Since by luck, you have field names and the class members are the same!
Public Function GetValue(ByRef parent As Object, ByVal fieldName As String) As Object
Dim field As FieldInfo = parent.[GetType]().GetField(fieldName, BindingFlags.[Public] Or BindingFlags.Instance)
Return field.GetValue(parent)
End Function
And then I have a datable routine - that gets me the data table, and is this:
Public Function MyrstEdit(strSQL As String, ByRef oReader As SqlDataAdapter) As DataTable
Dim mycon As New SqlConnection(strCon)
oReader = New SqlDataAdapter(strSQL, mycon)
Dim rstData As New DataTable
Dim cmdBuilder = New SqlCommandBuilder(oReader)
Try
oReader.Fill(rstData)
oReader.AcceptChangesDuringUpdate = True
Catch
End Try
Return rstData
End Function
So, to get all the data types and structure? I pass a dummy sql that returns no rows. (no rows are returned, but we DO GET the valuable table data types when we do this dummy table pull!). In most cases, if the PK is a autonumber, then I use id = 0.
that same MyRstEdit() code bit has tons of uses! You can now deal with a table in a nice structure, loop it, shove it into a combo box, or datagrid. And as it shows, also allows editing of the data - all with type checking.
The REAL trick and tip I am sharing here? Break out your common data routines to about 2-3 routines like MyRstEdit().
That way, you really don't have to deal with messy in-line sql, or every time you need to work on a table, you don't wire truckloads of code. And the real beauty here is that data typing is done for you - you don't have line after line of parameters, nor line after line of data typing for each column.
So, I hope this post gives you some ideas. But it also nice since I get to code much like I did in MSAccess, and that includes writing VERY little code for updates such as this.
The ideas here are just that - a different approach. The other approaches here are also just fine. (but are quite a bit more code then I perfer).
There are times when using a data table is a rather nice - and I think this is such an example.
And while I am oh so often used to referencing columns as a table collection? The cool trick here is I am also referencing each member of the class with a string too!

Data Mismatch Error in VB.net SQL statement

I have this code:
Protected Sub unlikebtn_Click(sender As Object, e As EventArgs) Handles unlikebtn.Click
Dim strSQL As String
Dim MemberDataConn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; data source=" & Server.MapPath("database/Database.mdb"))
Dim MemberCommand As New OleDbCommand(strSQL, MemberDataConn)
MemberDataConn.Open()
MemberCommand.Connection = MemberDataConn
MemberCommand.CommandText = "DELETE FROM LIKES WHERE user_id ='" & Session("user_id") & "' AND post_id = '" & Session("post_id") & "'"
MemberCommand.ExecuteNonQuery()
MemberDataConn.Close()
likebtn.Visible = True
unlikebtn.Visible = False
End Sub
When I run it, I get an error on the .ExecuteNonQuery():
System.Data.OleDb.OleDbException: 'Data type mismatch in criteria expression.
I don't think the problem is the data-types in the database...
It is (almost) always a bad idea to concatenate values into an SQL command. Instead, you should use SQL parameters to pass the values.
Also, instances of some classes, such as an OleDbConnection, use unmanaged resources and you have to tell the .NET Framework to dispose of those resources when you've finished using them. You can either call the .Dispose() method yourself or use the Using construct. The latter is tidier as it will take care of the disposal even if there was a problem.
So your code could look like:
Dim strSQL As String = "DELETE FROM LIKES WHERE user_id = ? AND post_id = ?"
Using conn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; data source=" & Server.MapPath("database/Database.mdb"))
Using sqlCmd As New OleDbCommand(strSQL, conn)
'TODO: set the OleDbType to match the columns in the database '
sqlCmd.Parameters.Add(New OleDbParameter With {
.ParameterName = "#UserId",
.OleDbType = OleDbType.VarWChar,
.Size = 32,
.Value = CStr(Session("user_id"))})
sqlCmd.Parameters.Add(New OleDbParameter With {
.ParameterName = "#PostId",
.OleDbType = OleDbType.Integer,
.Value = CInt(Session("post_id"))})
conn.Open()
sqlCmd.ExecuteNonQuery()
conn.Close()
End Using
End Using
likebtn.Visible = True
unlikebtn.Visible = False
The ?s in the SQL command are placeholders for the parameters. The parameter names aren't used, but it makes it easier to see what is what in the code. Because the names aren't used, the parameters must be added in the same order as the corresponding placeholders. You will need to adjust the types of the parameters (and the sizes for strings) to match the column types in the database.
Incidentally, if the site is to run under IIS, then you could put the database in the App_Data directory as nothing in there will be served to a client, by default. Also, SQL Server is a more suitable database for a multi-user environment - you can use the Express edition for free.

datatypes dont match, correct query and table

Got a new one for you, tried everything i could think of but without succes.
I want to be able to edit some textboxes and then update their records in the database. I use this code:
Private Sub btnUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdate.Click
connection.Open()
cmdupdate.CommandText = "UPDATE tbl_stal SET Locatie = '" & cbLocatienummer.Text & "', Coordinaten = '" & txtCoordinaten.Text & "' WHERE ID = '" & cbID.Text & "'"
cmdupdate.CommandType = CommandType.Text
cmdupdate.Connection = connection
cmdupdate.ExecuteNonQuery()
MsgBox("De gegevens zijn aangepast." & vbNewLine & "The data has been modified." & vbNewLine & "Die Daten sind angepasst.", MsgBoxStyle.OkOnly, "Voersoorten")
connection.Close()
cmdupdate.Dispose()
I am certain that the names of the database table and it's fields are correct, tried using both numerical and textbased settings on the table fields(as normally they should be numerical, but they might be text too. )
However, when i load some data from the datagridvieuw into the textboxes, change the coordinates(for example) and hit the updatebutton, it will give me the error that the datatypes don't match.
Apart from the above, what else can it be?
When you write data to a database table using any kind of sql text you should NEVER use string concatenation to build the SQL. This because you could have problems in the string supplied (what if one of these strings contains an embedded single quote?) and because taking the user input and attaching it to your command is a really dangerous practice that leads to Sql Injection
(Well MS-Access doesn't support multiple commands so you are a bit safer here)
So you should rewrite your query in this way
Dim cmdText = "UPDATE tbl_stal SET Locatie = ?, Coordinaten = ? WHERE ID = ?"
Using connection = new OleDbConnection(.....)
Using cmdUpdate = new OleDbCommand(cmdText, connection)
connection.Open()
cmdUpdate.Parameters.AddWithValue("#p1", cbLocatienummer.Text)
cmdUpdate.Parameters.AddWithValue("#p2", txtCoordinaten.Text)
cmdUpdate.Parameters.AddWithValue("#p3", Convert.ToInt32(cbID.Text))
cmdUpdate.ExecuteNonQuery()
End Using
End Using
Notice that you should provide a parameter with the exact datatype that matches the datatype of your field, strings for text fields, numbers for numeric fields.

how to insert a row to my db table from vb.net

am using vb.net, and i want to insert a row to my db Table "adwPays" from my windows form.
this is my code:
Dim CC, EngName, FreName, LanCode As String
Dim DialCode As Integer
CC = txtCC.Text
EngName = txtEN.Text
FreName = txtFN.Text
LanCode = txtLC.Text
DialCode = txtDC.Text
Dim MyConn As New SqlConnection("Server=(local);Database=dbAjout;Integrated Security=True")
Dim query As String
query = "INSERT INTO adwPays (CC, Anglais,Francais,CodeLangue,IndicInter) VALUES ( ' " & CC & "','" & EngName & "','" & FreName & "','" & LanCode & "','" & DialCode & " ');"
Dim cmd As New SqlCommand(query, MyConn)
MyConn.Open()
cmd.ExecuteScalar()
MyConn.Close()
BUT its giving me this error
"An unhandled exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
Additional information: String or binary data would be truncated.
The statement has been terminated."
any help?
Use a parameterized query like this
Dim query = "INSERT INTO adwPays (CC, Anglais,Francais,CodeLangue,IndicInter) " &
"VALUES (#cc, #ename, #fname, #lan, #dial)"
Using MyConn = New SqlConnection("Server=(local);Database=dbAjout;Integrated Security=True")
Using cmd = New SqlCommand(query, MyConn)
cmd.Parameters.AddWithValue("#cc", CC)
cmd.Parameters.AddWithValue("#ename", EngName)
cmd.Parameters.AddWithValue("#fname", FreName)
cmd.Parameters.AddWithValue("#lan", LanCode)
cmd.Parameters.AddWithValue("#dial", DialCode)
MyConn.Open()
cmd.ExecuteNonQuery()
End Using
End Using
Using a parameterized query allows to avoid problems with Sql Injections and clears the command text from the formatting quotes around strings and dates and also let the framework code pass the correct decimal point for the numeric types when need
I have also added a Using Statement around the SqlConnection and the SqlCommand to be sure that the objects are closed and destroyed. The parameters are all passed as strings, this could be wrong if any of your database fields are not of text type.
It sounds like you have a String value that is longer than the database type size allows. Can you verify the type and size of each of the following fields:
cc
ename
fname
lan
Now cross-reference those sizes with what the values are in the textbox fields you are pulling them from in the UI.
My money is on one of those exceeding the database size limits.
If that is the case, then you need to introduce length checking before you attempt to save to the database.

Trying to update record, keep getting this error vb.net

I'm sure this question will be easy for you lot... :)
I'm simply trying to update an existing record in my database using the following:
Private Sub Button12_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button12.Click
If Not cnn.State = ConnectionState.Open Then
cnn.Open()
End If
cmd2.Connection = cnn
cmd2.CommandText = "UPDATE HireItemRecord SET HireItemBeginDate = " & TextBox45.Text & _
" ,HireItemEndDate = " & TextBox44.Text & _
" ,HireItemCost = " & TextBox16.Text & _
" ,PaymentMethod = " & TextBox17.Text & _
" ,Staff_Id = " & TextBox19.Text & _
" ,HireItemNotes = " & TextBox18.Text & _
" ,HireItemReturnDate = " & TextBox43.Text & _
"WHERE HireRecord_Id = " & TextBox13.Text
cmd2.ExecuteNonQuery()
ds1.Clear()
daHireItemRecord.Fill(ds1, "PersonDetails")
cnn.Close()
End Sub
However no matter what record is selected and whatever details are in the boxes I keep getting this same error over and over:
SqlException was unhandled
Incorrect syntax near '12'.
When there is absolutely nothing in the textboxes the error changes to:
Incorrect syntax near ','.
I'm very new to this and I just can't seem to understand why this is happening.
Thank you very much for your help. :)
So much wrong with this.
You need a space after each comma, not before it.
You should be escaping your values before using them in the query. If I put "0 WHERE 1=1 -- " in any of your text boxes, it'll trash your entire table.
You should ALWAYS name your form controls properly. If I sent you back to this code in a year's time and told you there was a problem with TextBox44, would you know what it means? Same goes for your variables. Sometimes it's ok to have i, x or tbl for a variable name, but in general they should be descriptive.
Example for #2, where I've put "'1/1/1999' WHERE 1=1 --" into TextBox45:
`UPDATE HireItemRecord SET HireItemBeginDate = '1/1/1999' WHERE 1=1 -- , HireItemEndDate...`
Everything after the -- becomes a comment, so you get this:
`UPDATE HireItemRecord SET HireItemBeginDate = '1/1/1999' WHERE 1=1`
Can you imagine what would happen if I executed that query? Nothing good.
You should use parameterized queries, as per the recommendations in this question: Algorithm to avoid SQL injection on MSSQL Server from C# code?
You should never use string concatenation to build SQL. It leaves you open to SQL Injection attacks. Try using the SQLCommand object provided in .Net. This allows you to "parameterize" your query and you don't have to worry about where to put " and '.
It will also allow you add parameters naturally without having to convert them to strings. Something like this:
Dim command As New SqlCommand("SELECT * FROM Table", connection)
command.Parameters.Add("#ID", SqlDbType.Int)
command.Parameters("#ID").Value = customerID
I stole that code from the documentation about SQL Parameters here.