Error executing query when encountering name containing an apostrophe (e.g. O'Conner) - sql

My database program has a statement like:
variable = "SELECT * from Staff where StaffName = '" & cStaffName & "'"
This works fine until I have a member of staff with ' (apostrophe) in there name as it ends the start apostrophe.
SELECT * from Staff where StaffName = 'O'Conner'
Is there a way around this without replacing the apostrophe in her name?

You just need to use a parameterized query.
Using con = new SqlConnection(....)
Using cmd = new SqlCommand("SELECT * from Staff where StaffName = #name", con)
con.Open
cmd.Parameters.Add("#name", SqlDbType.NVarChar).Value = cStaffName
Using reader = cmd.ExecuteReader
.....
End Using
End Using
End Using
In this scenario you add a parameter to the SqlCommand parameters collection. The command text has no more a string concatenation but contains a parameter placeholder (#name). The parameter itself contains the value you want to pass to your query.
In this way there is no problem with quotes embedded in the value.
You also get the extra benefit to avoid any kind of Sql Injection problem with the user input

variable = "SELECT * from Staff where StaffName = '" & Replace(cStaffName, "'", "\'") & "'"

Related

Filter between dates VB.NET and Access database

As the title says, I'm unable to filter an SQL sentence from access database with vb.net
Dim data1 As String = DateTimePicker1.Value.ToShortDateString
Dim data2 As String = DateTimePicker2.Value.ToShortDateString
Dim sql As String = "SELECT totais.* From totais Where totais.data Between #" + data1 + "# And #" + data2 + "#;"
It gives me random values. If i put 1-10(October)-2019 it gives me all the records in system, if i put 12-10(October)-2019 it only gives today's record (doesn't show yesterday and before records). I'm not finding the problem, can you please help?
Thanks
I would use Parameters instead of concatenating a string for the Sql statement. It makes the statement much easier to read and avoids syntax errors.
With OleDb the order that parameters appear in the sql statement must match the order they are added to the parameters collection because OleDb pays no attention to the name of the parameter.
Private Sub OPCode()
Dim sql As String = "SELECT * From totais Where data Between #StartDate And #EndDate;"
Using dt As New DataTable
Using cn As New OleDbConnection("Your connection string"),
cmd As New OleDbCommand(sql, cn)
cmd.Parameters.Add("#StartDate", OleDbType.Date).Value = DateTimePicker1.Value
cmd.Parameters.Add("#EndDate", OleDbType.Date).Value = DateTimePicker2.Value
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
DataGridView1.DataSource = dt
End Using
End Sub
You need to use single quotes and convert type in SQL like this:
SELECT totais.* FROM totais WHERE totais.data Between CDATE('" + data1 + "') And CDATE('" + data2 + "');"
You should use parameters as per Mary's answer BUT for completeness...
Ms/Access requires dates specified as #mm/dd/yy# so your SQL will only work properly where the local date time format is mm/dd/yy. i.e. mostly the US. Otherwise you will have to format your date string.

SQL Selecting without parameters?

Im trying to select all records from a database table. Each record has a date in it i want to select all records where that date matches todays date
i created a variable called todaydate and used it within the query but i get No value provided for one or more required parameters error. What possible parameters would i use
Here is the code
Any help would be appreciated
Dim todaydate As Date = Date.Today()
If DbConnect() Then
Dim SQLCmd As New OleDbCommand
With SQLCmd
.Connection = cn
.CommandText = "Select * from Tbl_Rental Where DateOfHire = todaydate"
'parameters????
You're not using the variable. However, you should always use sql-parameters not concatenate strings(one reason: avoiding SQL-Injection). I'd also suggest to use the Using-statement for the connection and everything else that implements IDisposable:
Using cn As New OleDbConnection(connectionString)
cn.Open()
Using cmd As New OleDbCommand("Select * from Tbl_Rental Where DateOfHire = #DateOfHire", cn)
dim hireDateParameter As new OleDbParameter("#DateOfHire", OleDbType.Date)
hireDateParameter.Value = Date.Today
cmd.Parameters.Add(hireDateParameter)
' ... '
End Using
End Using
If it's always Date.Today you could do that also without a parameter because every database has date functions which return the current date. But since you haven't told us which DB you are using it's hard to show an example.
You need to actually use your variable, not include it as part of the string. Try this:
.CommandText = "Select * from Tbl_Rental Where DateOfHire = '" & todaydate.ToString("dd/MM/yy") & "'"
From a slightly different angle, would it suffice that the date was simply "greater than yesterday"?
.CommandText = "Select * from Tbl_Rental Where DateOfHire >= cast(getdate() as date)"
This strips the time off the date and anything at or later than midnight today is included.

Pass parameter to a query from another query in Access

I have a parameterized query GET_CUSTOMER:
SELECT * FROM Customer WHERE id = [customer_id]
I want to call this query from another query and pass it a parameter:
SELECT * FROM GET_CUSTOMER(123)
Note the above code is not valid, it is here to give you an idea of what I'm trying to do. Is it possible to do this in MS Access?
UPDATE 1:
The queries I posted are for example. The actual queries are much more complex. I know I can use table joins, but in my specific case it would be much easier if I could run parameterized queries inside other queries (that are parameterized as well). I can't use access forms because I'm using access with my .NET application.
This is how I end up solving this with help of https://stackoverflow.com/a/24677391/303463 . It turned out that Access shares parameters among all queries so there is no need to specifically pass parameters from one query to another.
Query1:
SELECT * FROM Customer WHERE ID > [param1] AND ID < [param2]
Query2:
SELECT * FROM Query1
VB.NET code:
Dim ConnString As String = "Provider=Microsoft.Jet.OleDb.4.0;Data Source=Database.mdb"
Dim SqlString As String = "Query2"
Using Conn As New OleDbConnection(ConnString)
Using Cmd As New OleDbCommand(SqlString, Conn)
Cmd.CommandType = CommandType.StoredProcedure
Cmd.Parameters.AddWithValue("param1", "1")
Cmd.Parameters.AddWithValue("param2", "3")
Conn.Open()
Using reader As OleDbDataReader = Cmd.ExecuteReader()
While reader.Read()
Console.WriteLine(reader("ID"))
End While
End Using
End Using
End Using
You can build the SQL on the fly.
MyID = prompt or get from user some ID
strSQl = "Select * from tblCustomer where ID in " & _
"(select * from tblTestCustomers where id = " & MyID
So you can nest, or use the source of one query to feed a list of ID to the second query.

Update Query in Visual Basic Express 2010

I'm trying to update an Access 2003 database using Visual Basic Express 2010 via SQL, I have so far got SELECT, DELETE and INSERT queries to work, but update will not...
con.ConnectionString = dbProvider & dbSource
con.Open() 'Open connection to the database
sqlstatement = "UPDATE users SET password = '" & NewPassword & "' WHERE USERID = " & ID & ";"
Dim dc As New OleDb.OleDbCommand(sqlstatement, con)
dc.ExecuteNonQuery()
con.Close()
Like I said, all other statements work, the error produced is:
http://i.stack.imgur.com/acFBT.png
Thank you!
The first problem is the word PASSWORD. It is a reserved keyword in MS-Access database. If you want to use it you should enclose it in square brackets.
Said that, please start using a parameterized query and not a string concatenation when you work with any type of database
So your code should be:
sqlstatement = "UPDATE users SET [password] = ? WHERE USERID = ?"
Using con = new OleDbConnection(dbProvider & dbSource)
Using dc = new OleDbCommand(sqlstatement, con)
con.Open()
dc.Parameters.AddWithValue("#p1", NewPassword)
dc.Parameters.AddWithValue("#p2", ID)
dc.ExecuteNonQuery()
End Using
End Using
You could read about the importance of Parameterized Queries and Sql Injection in many places, this link is a most famous one to start with

SQL output as variable in VB.net

I cannot seem to figure out how to get an output of a SQL query as a variable in VB. I need something like what's below so that I can use that variable in another SQL query. SQL doesn't allow the use of variables as column headers when running queries, so I thought I could use VB to insert the actual output of one SQL task as the dynamic variable in a loop of update queries. Let me (hopefully) explain.
I have the following query:
DECLARE #id int = (SELECT max(id) FROM [views]), #ViewType nvarchar(3);
WHILE #id IS NOT NULL
BEGIN
SELECT #ViewType = (SELECT [View] FROM [views] WHERE id = #id);
UPDATE a
SET a.[#ViewType] = '1'
FROM [summary] a
INNER JOIN [TeamImage] b
ON a.[Part_Number] = b.[PartNum]
WHERE b.[View] = #ViewType;
SELECT #id = max(id) FROM [views] WHERE id < #id;
END;
The SET a.[#ViewType] = '1' obviously will not work in SQL. But if I could have the (SELECT [View] FROM [views] WHERE id = #id) equal to a variable, then I could write the SQL query in VB and execute it and the variable would become part of the string and therefore execute correctly.
I'm newer to VB, but here's what I have so far:
Dim cn As SqlConnection = New SqlConnection("Data Source=Server1;" & _
"Initial Catalog=DB1;" & _
"Integrated Security=SSPI")
cn.Open()
Dim cmd As New sqlCommand("SELECT max(id) FROM orientation_view_experiment;", cn)
vID = cmd.ExecuteNonQuery()
Do While vID > 0
Dim cmd2 As New sqlCommand("SELECT [View] FROM [views] WHERE id ='" + vID + "'"
vViewType = cmd2.ExecuteNonQuery()
Dim cmd3 As New sqlCommand("UPDATE a
SET a.'" + vViewType + "' = '1' & _
FROM [summary] a & _
INNER JOIN [TeamImage] b & _
ON a.[Part_Number] = b.[PartNum] & _
WHERE b.[View] = '" + vViewType + "';"
cmd3.ExecuteNonQuery()
vID = vID - 1
Loop
cn.Close()
I hope some of that made sense, but I'm kind of lost at this point. I feel like I know what I need the SQL to do, but can't quite figure out how to make the computer/programs submit to my will and just do what I need it to do.
Thank you for any help/direction you can give.
Your code is wrong because you insist in using ExecuteNonQuery for SELECT statements. ExecuteNonQuery doesn't return the rows selected but just a count of the rows affected by an INSERT/DELETE/UPDATE query (I think that for SELECT it returns always zero)
What you need is ExecuteScalar to get the MAX value and the VIEW value because ExecuteScalar is the best choice when you expect to get just the first field of the first row from your SQL statement
Dim cmd As New sqlCommand("SELECT max(id) FROM orientation_view_experiment;", cn)
vID = Convert.ToInt32(cmd.ExecuteScalar())
Do While vID > 0
Dim cmd2 As New sqlCommand("SELECT [View] FROM [views] WHERE id =" + vID.ToString()
Dim result = cmd2.ExecuteScalar()
if Not string.IsNullOrEmpty(result)) Then
vViewType = result.ToString()
Dim cmd3 As New sqlCommand("UPDATE a SET a.[" + vViewType + "] = '1' " & _
"FROM [summary] a " & _
"INNER JOIN [TeamImage] b " & _
"ON a.[Part_Number] = b.[PartNum] " & _
"WHERE b.[View] = #vType"
cmd3.Parameters.AddWithValue("#vType", vViewType)
cmd3.ExecuteNonQuery()
End If
Loop
The last part of your code is not really clear to me, but you could use a couple of square brackets around the column name in table summary and a parameter for the View field in table TeamImage.
As a last advice, be sure that the column View in table TeamImage is not directly modifiable by your end user because a string concatenation like this could lead to a Sql Injection attacks
Do a little research into what the different methods of a command are. When you call ExecuteNonQuery, this return the number of records effected. I think you want ExecuteScalar as your cmd and cmd2 methods, so you can get a value from the database.
Have you tried replacing '" + vViewType + "' with [" + vViewType + "] ... in other words use square brackets to delimit the column name instead of single quotes which are for delimiting string literals?
Also, I would encourage stopping in the debugger, examining the command that you generated into cmd3 and try executing it directly. It might help you identify other similar problems such as the fact that vViewType is giving you a count of records instead of an actual value from the [View] column.