Inserting byte() along side strings to SQL database - sql

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!

Related

Building an odbc command string in Visual Basic

I'm trying to figure out where I am going wrong with the following SQL string in VB.NET
Dim SQL As String = "INSERT INTO USERS (" & String.Join(",", PropertyNames) & ", auditmonth) VALUES ('" & String.Join("','", Values) & "',", MonthName & "'"))
I'm getting the following three errors:
End of statement expected
Variable 'MonthName' hides a variable in an enclosing block
Unused local variable 'MonthName'
If I change back to
Dim SQL As String = "INSERT INTO USERS (" & String.Join(",", PropertyNames) VALUES ('" & String.Join("','", Values) & "')"
Then everything works fine. But what I'm trying to do is just add the current month to the database entry. The variable MonthName gets populated successfully. I'm just screwing something up with the syntax of the SQL command.
You should try breaking it up to multiple lines, and debug it to review the whole string constructed:
"INSERT INTO USERS (" &
String.Join(",", PropertyNames) &
", auditmonth) VALUES ('" &
String.Join("','", Values) & "','" &
MonthName & "')"
If your VB.NET compiler supports it, use this string substitution syntax for better readability:
String.Format(
"INSERT INTO USERS ({0}, auditmonth) VALUES ('{1}','{2}')",
String.Join(",", PropertyNames),
String.Join("','", Values),
MonthName)
and, do as #vku says!
You really should use SQL parameters to pass the values. If you try to concatenate them in a string, it will break if there is an apostrophe in the value, and it's also vulnerable to SQL injection attacks.
As shown in tinamzu's answer, it is better to spread the code out over several lines to make it easier to read. Also, use as many variables as you like to keep each line simple.
So, you might have something like this:
Dim columnNames = String.Join(",", propertyNames)
Dim valuePlaceholders = String.Join(", ", Enumerable.Repeat("?", values.Count))
Dim sql = String.Format("INSERT INTO USERS ({0}, auditmonth) VALUES ({1}, ?)",
columnNames,
valuePlaceholders)
Using conn As New OleDbConnection("yourConnectionString"),
cmd As New OleDbCommand(sql, conn)
For Each v In values
cmd.Parameters.Add("?", OleDbType.VarChar).Value = v
Next
cmd.Parameters.Add("?", OleDbType.VarChar).Value = monthName
conn.Open()
cmd.ExecuteNonQuery()
End Using
(Change the OleDbType.VarChar to match the relevant database column types.)
If you are using version 2015 or later of Visual Studio, you could use:
Dim sql = $"INSERT INTO USERS ({columnNames}, auditmonth) VALUES ({valuePlaceholders}, ?)"
instead as it is clear using just one line.

INSERT INTO and UPDATE SQL using visual basic into access database

I'm working on my A Level coursework using VB forms as my front end and an Access database as the back end. I've tried loads of different ways but I can't get the program to update or insert data into the database.
I know for a fact the connection is fine because I've had no problem retrieving data from access into the program.
This the code for one of the forms:
(the database connection is in a separate form)
Access.ExecQuery("SELECT * FROM Exam;")
Dim user As String = TxtStudent.Text
Dim board As String = CmbBoard.Text
Dim instrument As String = CmbInstrument.Text
Dim grade As String = CmbGrade.Text
Dim result As String = CmbResult.Text
Access.ExecQuery("INSERT INTO Grade (Username, Instrument, Exam Board, Grade, Result) VALUES ('" & user & "', '" & board & "', '" & instrument & ", " & grade & ", " & result & "');")
If Not String.IsNullOrEmpty(Access.Exception) Then MsgBox(Access.Exception) : Exit Sub
The error message says there is a syntax error on INSERT INTO statement.
Am i just being really stupid?
you are missing closing "'" for instrument '" & instrument & "', " . and also, just confirm the values for fields without single quotes(grade ) are numeric otherwise add single quotes
Your single and double parenthesis are a bit of a mess. This alone is a good reason to use parameters but it also protects you from malicious input by users. The important thing with Access is that you must add the parameters in the same order that the command uses them.
Dim cn As New OleDbConnection("Your Access connection string")
Dim s As String = "INSERT INTO Grade (Username, Instrument, Exam Board, Grade, Result) VALUES (#User, #Instrument, #Board, #Grade, #Result);"
Dim cmd As New OleDbCommand(s, cn)
cmd.Parameters.AddWithValue("#User", TxtStudent.Text)
cmd.Parameters.AddWithValue("#Instrument", CmbInstrument.Text)
cmd.Parameters.AddWithValue("#Board", cmdBoard.Text)
cmd.Parameters.AddWithValue("#Grade", CmdGrade.Text)
cmd.Parameters.AddWithValue("#Result", CmdResult.Text)
cn.Open()
cmd.ExecuteNonQuery()
cn.Close()
Double check the data types of the fields and adjust the code if they are not all strings.
In SQL Queries and statements , '(single quote) is used to pass a value of type string to any given parameter(or anything).You mistake was that you forgot to add ' in all the places.
"INSERT INTO Grade (Username, Instrument, Exam Board, Grade, Result) VALUES ('" & user & "', '" & board & "', '" & instrument & ", "'" & grade & "'", "'" & result & "'")"
This will solve it :)
However, one advice, don't give direct values in the statement itself,you are welcoming SQL-Injection.Rather,create parameters and values to them later :
Dim cmd as New SqlCommand("INSERT INTO Grade (Username)Values(#uname)",con)
cmd.Parameter.Add("#uname",SqlDbType.Vachar) = "abc"
Hope this helps to enrich your knowledge :)
You must try this!
Dim con As New OleDbConnection("Your Access connection string here")
Dim s As String = "INSERT INTO Grade ([Username], [Instrument], [Exam Board], [Grade], [Result]) VALUES (#User, #Instrument, #Board, #Grade, #Result)"
Dim cmd As New OleDbCommand(s, con)
con.Open()
cmd.Parameters.AddWithValue("#User", TxtStudent.Text)
cmd.Parameters.AddWithValue("#Instrument", CmbInstrument.Text)
cmd.Parameters.AddWithValue("#Board", cmdBoard.Text)
cmd.Parameters.AddWithValue("#Grade", CmdGrade.Text)
cmd.Parameters.AddWithValue("#Result", CmdResult.Text)
cmd.ExecuteNonQuery()
con.Close()
I hope it will works! :)
Dim con As New OleDbConnection("Your Access connection string here")
Dim s As String = "INSERT INTO Grade ([Username], [Instrument], [Exam Board], [Grade], [Result]) VALUES (#User, #Instrument, #Board, #Grade, #Result)"
Dim cmd As New OleDbCommand(s, con)
con.Open()
cmd.Parameters.AddWithValue("#User", TxtStudent.Text)
cmd.Parameters.AddWithValue("#Instrument", CmbInstrument.Text)
cmd.Parameters.AddWithValue("#Board", cmdBoard.Text)
cmd.Parameters.AddWithValue("#Grade", CmdGrade.Text)
cmd.Parameters.AddWithValue("#Result", CmdResult.Text)
cmd.ExecuteNonQuery()
con.Close()

Database Locked even after disposing all commands

The database is locked error appears even after I have disposed all the commands. I'm trying to write to the database and it is failing on the INSERT command at the bottom. I had it working before but for some reason it has started to fail now.
Sub Btn_SubmitClick(sender As Object, e As EventArgs)
If MsgBox("Are you sure?",vbYesNo,"Submit?") = 7 Then
'returns to previous screen
Else
'commences insert into database
Rows = (dataGridView1.RowCount - 1)
While count < rows
'putting grid stuff into variables
DateStart = dataGridView1.Rows(Count).Cells(0).Value.ToString
DateEnd = dataGridView1.Rows(Count).Cells(2).Value.ToString 'note other way round
TimeStart = dataGridView1.Rows(Count).Cells(1).Value.ToString
TimeEnd = dataGridView1.Rows(Count).Cells(3).Value.ToString
TotalHours = dataGridView1.Rows(Count).Cells(4).Value.ToString
OccuranceNo = dataGridView1.Rows(Count).Cells(5).Value.ToString
'fetching reason ID for Storage
SQLcommand = SQLconnect.CreateCommand
SQLcommand.CommandText = "SELECT Reason_ID FROM Reasons WHERE Reason_Name = '" & dataGridView1.Rows(Count).Cells(6).Value.ToString & "'"
SQLreader = SQLcommand.ExecuteReader
ReasonID = SQLreader("Reason_ID")
SQLcommand.Dispose
'fetching site ID for storage
SQLcommand = SQLconnect.CreateCommand
SQLcommand.CommandText = "SELECT Site_ID FROM Sites WHERE Site_Name = '" & dataGridView1.Rows(Count).Cells(7).Value.ToString & "'"
SQLreader = SQLcommand.ExecuteReader
SiteID = SQLreader("Site_ID")
SQLcommand.Dispose
Oncall = dataGridView1.Rows(Count).Cells(8).Value.ToString
'increment counter
Count = Count + 1
'send to database
SQLcommand = SQLconnect.CreateCommand
SQLcommand.CommandText = "INSERT INTO Shifts (Staff_ID, Date_Shift_Start, Date_Shift_End, Time_Shift_Start, Time_Shift_End, Total_Hours, Occurance_No, Site_ID, On_Call_Req, Rate, Approved, Reason_ID) VALUES ('" & userID & "' , '" & DateStart &"' , '" & DateEnd & "' , '" & TimeStart & "' , '" & TimeEnd & "' , '" & TotalHours & "' , '" & OccuranceNo & "' , '" & SiteID & "' , '" & Oncall & "' , '"& "1" & "' , '" & "N" & "' , '" & ReasonID & "')"
SQLcommand.ExecuteNonQuery()
SQLcommand.Dispose
End While
MsgBox("Ok")
End If
End Sub
There are several things which ought be changed in the code shown. Since none of the Connection, Command or Reader objects are declared in the code, they must be global objects you are reusing. Don't do that.
There can be reasons for one persistent connection, but queries are very specific in nature, so trying to reuse DbCommand and DataReaders can be counterproductive. Since these work closely with the DbConnection, all sorts of bad things can happen. And it means the root of the problem could be anywhere in your code.
The following will loop thru a DGV to insert however many rows there are.
Dim SQL = "INSERT INTO Sample (Fish, Bird, Color, Value, Price) VALUES (#f, #b, #c, #v, #p)"
Using dbcon As New SQLiteConnection(LiteConnStr)
Using cmd As New SQLiteCommand(SQL, dbcon)
dbcon.Open()
cmd.Parameters.Add("#f", DbType.String)
cmd.Parameters.Add("#b", DbType.String)
cmd.Parameters.Add("#c", DbType.String)
cmd.Parameters.Add("#v", DbType.Int32)
cmd.Parameters.Add("#p", DbType.Double)
Dim fishName As String
For Each dgvR As DataGridViewRow In dgv2.Rows
' skip the NewRow, it has no data
If dgvR.IsNewRow Then Continue For
' look up from another table
' just to shorten the code
userText = dgvR.Cells(0).Value.ToString()
fishName = dtFish.AsEnumerable().
FirstOrDefault(Function(f) f.Field(Of String)("Code") = userText).
Field(Of String)("Fish")
' or
'Dim drs = dtFish.Select(String.Format("Code = '{0}'", userText))
'fishName = drs(0)("Fish").ToString()
cmd.Parameters("#f").Value = fishName
cmd.Parameters("#b").Value = dgvR.Cells(1).Value
cmd.Parameters("#c").Value = dgvR.Cells(2).Value
cmd.Parameters("#v").Value = dgvR.Cells(3).Value
cmd.Parameters("#p").Value = dgvR.Cells(4).Value
cmd.ExecuteNonQuery()
Next
End Using
End Using
NOTE: Like the original code there is no Data Validation - that is, it assumes that whatever they typed is always valid. This is rarely a good assumption.
The code implements Using blocks which will declare and create the target objects (dbCommands, connections) and dispose of them when done with them. They cannot interfere with code elsewhere because they only exist in that block.
SQL Parameters are used to simplify code and specify datatypes. A side effect of concatenating SQL as you are, is that everything is passed as string! This can be very bad with SQLite which is typeless.
I would avoid firing off multiple look up queries in the loop. The original code should throw an InvalidOperationException since it never Reads from the DataReader.
Perhaps the best way to do this would be for Sites and Reasons to be ComboBox column in the DGV where the user sees whatever text, and the ValueMember would already be available for the code to store.
Another alternative shown in the answer is to pre-load a DataTable with the data and then use some extension methods to look up the value needed.
If you "must" use readers, implement them in their own Using blocks.
A For Each loop is used which provides the actual row being examined.
I'd seriously reconsider the idea of storing something like a startDateTime as individual Date and Time fields.
These are the basics if using DB Provider objects. It is not certain that refactoring that procedure shown will fix anything, because the problem could very well be anywhere in the code as a result of DBProvider objects left open and not disposed.
One other thing to check is any UI Manager you may be using for the db. Many of these accumulate changes until you click a Save or Write button. In the interim, some have the DB locked.
Finally, even though the code here is shorter and simpler, using a DataAdapter and a DataTable would allow new data in the DGV to automatically update the database:
rowsAffected = myDA.Update(myDT)
It would take perhaps 30 mins to learn how to configure it that way.

OleDbException was unhandled.......Syntax error in UPDATE statement

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

how to check duplicate record before insert, using vb.net and sql?

can someone help me with my code, i need to check first if record exist. Well i actually passed that one, but when it comes to inserting new record. im getting the error "There is already an open DataReader associated with this Command which must be closed first." can some help me with this? thanks.
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim reg_con As SqlConnection
Dim reg_cmd, chk_cmd As SqlCommand
Dim checker As SqlDataReader
Dim ID As Integer
Dim fname_, mname_, lname_, gender_, emailadd_, college_, password_ As String
ID = idnumber.Value
fname_ = fname.Value.ToString
mname_ = mname.Value.ToString
lname_ = lname.Value.ToString
gender_ = gender.Value.ToString
college_ = college.Value.ToString
emailadd_ = emailadd.Value.ToString
password_ = reg_password.Value.ToString
reg_con = New SqlConnection("Data Source=JOSH_FLYHEIGHT;Initial Catalog=QceandCceEvaluationSystemDatabase;Integrated Security=True")
reg_con.Open()
chk_cmd = New SqlCommand("SELECT IDnumber FROM UsersInfo WHERE IDnumber = '" & ID & "'", reg_con)
checker = chk_cmd.ExecuteReader(CommandBehavior.CloseConnection)
If checker.HasRows Then
MsgBox("Useralreadyexist")
Else
reg_cmd = New SqlCommand("INSERT INTO UsersInfo([IDnumber], [Fname], [Mname], [Lname], [Gender], [Emailadd], [College], [Password]) VALUES ('" & ID & "', '" & fname_ & "', '" & mname_ & "', '" & lname_ & "', '" & gender_ & "', '" & emailadd_ & "', '" & college_ & "', '" & password_ & "')", reg_con)
reg_cmd.ExecuteNonQuery()
End If
reg_con.Close()
End Sub
Add this string to your connection string
...MultipleActiveResultSets=True;";
Starting from Sql Server version 2005, this string allows an application to maintain multiple active statements on a single connection. Without it, until you close the SqlDataReader you cannot emit another command on the same connection used by the reader.
Apart from that, you insert statement is very dangerous because you use string concatenation. This is a well known code weakness that could result in an easy Sql Injection vulnerability
You should use a parameterized query (both for the insert and for the record check)
reg_cmd = New SqlCommand("INSERT INTO UsersInfo([IDnumber], ......) VALUES (" & _
"#id, ......)", reg_con)
reg_cmd.Parameters.AddWithValue("#id", ID)
.... add the other parameters required by the other field to insert.....
reg_cmd.ExecuteNonQuery()
In a parameterized query, you don't attach the user input to your sql command. Instead you put placeholders where the value should be placed (#id), then, before executing the query, you add, one by one, the parameters with the same name of the placeholder and its corresponding value.
You need to close your reader using checker.Close() as soon as you're done using it.
Quick and dirty solution - issue checker.Close() as a first command of both IF and ELSE block.
But (better) you don't need a full blown data reader to check for record existence. Instead you can do something like this:
chk_cmd = New SqlCommand("SELECT TOP (1) 1 FROM UsersInfo WHERE IDnumber = '" & ID & "'", reg_con)
Dim iExist as Integer = chk_cmd.ExecuteScalar()
If iExist = 1 Then
....
This approach uses ExecuteScalar method that returns a single value and doesn't tie the connection.
Side note: Instead of adding parameters like you do now - directly to the SQL String, a much better (and safer) approach is to use parametrized queries. Using this approach can save you a lot of pain in the future.