ADO Repeated SQL Parameters - sql

I have a query that uses a sub query with the same parameters, so it looks something like this:
strSelect = _
"SELECT a.State, a.FirstName, a.LastName, b.JobTitle " & _
"FROM apples a " & _
"LEFT JOIN ( " & _
"SELECT a.RecordNumber, " & _
"CASE WHEN j.JobTitle IS NULL THEN j.JobTitle2 ELSE j.jobtitle END " & _
"FROM apples a " & _
"LEFT JOIN jobs j ON j.RecordNumber = a.RecordNumber " & _
strWhere & _
") b ON b.RecordNumber = a.RecordNumber "
strWhere = _
"WHERE a.JobState = ? " & _
"AND a.JobDate = ? "
The sub-query in real life is less pointless than the one in the example.
The question here is if I repeat strWhere, then is there a way to get the parameters to work for the resulting strSQL = strSelect & strWhere statement? The issue is that I have two parameters, but they're repeated, so it would be four parameters for the strSQL statement, but I would prefer to not repeat my parameters when I declare them.
I have a feeling I'm missing something pretty obvious here. Any suggestions?

You should use named parameters:
Try using named parameters for example:
WHERE a.JobState = #JobDate
and
AND a.JobDate = #JobDate
Then, when you add your parameters you will only need to add them once. It will look something like this:
SqlParameter param = new SqlParameter();
param.ParameterName = "JobDate";
param.Value = theDate;

Related

MS Access SQL - Problem with subquery and function in ORDER BY clause

The senario is that some people apply for some positions.
So there are tApplicant, tPosition and a join table tPreferences for a many-to-many relationship between them.
I need to build a SQL expression where these should happen:
get some fields from a join of tApplicant and tPosition into a new table.
create a new field called AM which should be either 1 or 0.
1 = If tApplicant.applicationID is found in a third not relevant table called tInfo.
0 = If tApplicant.applicationID is not found there.
ORDER BY AM.
It is executed in VBA. This is what I 've got so far:
sSQL = "SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tPreferences.fld3, " & _
"NZ((SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID), 0) AS AM " _
"INTO " & sTable & " FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ";"
CurrentDB.Execute sSQL, dbFailOnError
It seems like step 3 cannot be done.
Adding ORDER BY AM, throws Run-time error '3061'. Too few parameters. Expected 1..
While adding ORDER BY NZ((SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID), 0), throws Run-Time Error 3075: Syntax Error in Query Expression 'NZ((SELECT 1 FROM tAMEA WHERE tAMEA.aitisiID = tAiton.aitisiID), 0'..
If omitted, everything works fine but there's no ORDER BY.
How can I achieve this?
PS: If values 1 and 0 for AM make things complicated, and some other values instead could be easier to get with the query, it will be OK, I will deal with this in the rest of the code.
Nz is an application-level function (technically, a method of the Access.Application object exposed as a function. It is unavailable for use in DAO.
CurrentDb.Execute is using DAO.
There are two rewrite possibilities:
Rewrite to avoid Nz:
IIF((SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID) IS NOT NULL, 1, 0)
Or my preferred rewrite:
ORDER BY EXISTS(SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID) DESC
Rewrite to DoCmd.RunSQL which does allow these functions (and suppress warnings as desired:
DoCmd.RunSQL sSQL
First, Access might think that the subquery may return more than one record, thus Top 1 should be used.
Next, it makes no sense to order the records to be inserted, as records per definition carries no order unless you specify this in the target table or the query where that table is used as source.
Also, even if you insisted to sort the insert, Access can't do this, as it doesn't know the output for AM.
Thus, this will run:
sSQL = "SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tPreferences.fld3, " & _
"NZ((SELECT Top 1 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID), 0) AS AM " _
"INTO " & sTable & " FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ";"
CurrentDB.Execute sSQL, dbFailOnError
That said, Erik's suggestion to replace Nz with Exists is preferable as this will result in "clean SQL" which always will run faster:
sSQL = "SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tPreferences.fld3, " & _
"EXISTS (SELECT Top 1 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID) AS AM " _
"INTO " & sTable & " FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ";"
CurrentDB.Execute sSQL, dbFailOnError
Neither will this be sortable on AM. Also, it will in Access SQL return -1 and 0 for AM. To obtain 1, apply ABS:
sSQL = "SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tPreferences.fld3, " & _
"ABS(EXISTS (SELECT Top 1 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID)) AS AM " _
"INTO " & sTable & " FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ";"
CurrentDB.Execute sSQL, dbFailOnError
#ErikA and #Gustav 's answers pointed me to the right direction. Thank you both for your time.
The problem in this case was that I tried to use a subquery in the ORDER BY clause. Which I found out now that is not allowed. eg. see here
More over, I found this question, which makes mine a possible duplicate. Here it is suggested to wrap the query.
So I firstly SELECT the data in no order with the subquery and then, INSERT INTO the new table using ORDER BY with the new column of the subquery.
So I'm posting what finally worked for me.
sSQL = "SELECT * INTO " & sTable & " FROM (" & _
"SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tProtimisi.fld3, " & _
"NZ((SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID), 0) AS AM " & _
"FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ") " & _
"ORDER BY AM DESC;"
CurrentDb.Execute sSQL, dbFailOnError

Correctly assigned parameter valuecan not be used

I want to get a cmb-value before the entry is changed, by using ".oldValue". The value is correctly assigned (according to debugger), but running the SQL Access is asking for a manual entry. Doing the entry manually works fine, so the remaining code should be fine.
My Code:
Dim CategoryNameBeforeChange As String
CategoryNameBeforeChange = Forms!frmCategory!txtCategoryName.OldValue
SQL = "UPDATE CategoryTbl " & _
"SET CategoryTbl.CategoryName = Forms!frmCategory!txtCategoryName " & _
"WHERE (CategoryTbl.CategoryName = CategoryNameBeforeChange);"
Any idea what went wrong here?
Any help is greatly appreciated!
Try this:
SQL = "UPDATE CategoryTbl " & _
"SET CategoryTbl.CategoryName = Forms!frmCategory!txtCategoryName " & _
"WHERE (CategoryTbl.CategoryName = " & CategoryNameBeforeChange & ");"
I suspect that CategoryName is text, in this case it should be
SQL = "UPDATE CategoryTbl " & _
"SET CategoryTbl.CategoryName = Forms!frmCategory!txtCategoryName " & _
"WHERE (CategoryTbl.CategoryName = '" & CategoryNameBeforeChange & "');"

access 2013 increasing quantity in a table field

Good day. I'm a little stumped about what is happening in my code. I have a userform which collects txtQntyRecd and cboSupplySource. I calculate the lookupValue. And it works just fine. It successfully places the txtQntyRecd in the correct tblWarehouseLocations.WQuantity location. The code is:
updateQnty = "UPDATE tblSupplySources INNER JOIN ((tblWarehouseLocations " & _
"INNER JOIN tblSupplySource_WarehouseLocation ON tblWarehouseLocations.WLocation_ID = tblSupplySource_WarehouseLocation.SWLocation_ID)) " & _
"ON tblSupplySources.SupplySourceID = tblSupplySource_WarehouseLocation.Supply_Source_ID " & _
"SET tblWarehouseLocations.WQuantity = '" & Me.txtQntyRecd & "'" & _
"WHERE (((tblSupplySource_WarehouseLocation.Supply_Source_ID)= " & Me.cboSupplySource & ") " & _
" AND ((tblWarehouseLocations.WLocation_ID)=" & lookupValue & "))"
CurrentDb.Execute updateQnty, dbFailOnError
What I want to do is add the next quantity to the same location. I get weird results if I change the SET statement to the following:
SET tblWarehouseLocations.WQuantity = tblWarehouseLocations.WQuantity + '" & Me.txtQntyRecd & "'"
If I put 200 in the first statement, I get 200 in my WQuantity field. When I change to the second statement and I try to add 1 to the 200 I get a result of 211. If I add 1 again, the result is 223. Add 1 again, the result is 236.
Could someone explain what is happening and why the results aren't 201, 202 and 203? In the future I will need to subtract quantities from WQuantity as well.
Thanks
You're adding quotes around an integer and appending it as a string. Change it to:
".....
SET tblWarehouseLocations.WQuantity = tblWarehouseLocations.WQuantity + " & val(Me!txtQntyRecd) & "....
...."
I've changed the . to a ! as I think it's still a nice distinction between objects properties and controls, and used the val function as it converts the string number value to the integer value.
This is your query in full:
' When I use values from controls, I like to store them in vars
Dim quantityReceived As integer
quantityReceived = val(Me!txtQntyRecd)
updateQnty = "UPDATE tblSupplySources INNER JOIN ((tblWarehouseLocations " & _
"INNER JOIN tblSupplySource_WarehouseLocation ON tblWarehouseLocations.WLocation_ID = tblSupplySource_WarehouseLocation.SWLocation_ID)) " & _
"ON tblSupplySources.SupplySourceID = tblSupplySource_WarehouseLocation.Supply_Source_ID " & _
"SET tblWarehouseLocations.WQuantity = tblWarehouseLocations.WQuantity + " & quantityReceived & _
" WHERE (((tblSupplySource_WarehouseLocation.Supply_Source_ID)= " & Me.cboSupplySource & ") " & _
" AND ((tblWarehouseLocations.WLocation_ID)=" & lookupValue & "))"
I solved the problem. I created a SELECT query to get the present amount in WQuantity. Now quantityReceived = Me!txtQntyRecd + the present amount. With SET tblWarehouseLocations.WQuantity = " & quantityReceived it works fine. However, if just seems so cumbersome.
' lookupValue gives the index into the tblWarehouseLocations where WQuantity resides
Dim lookupValue As Integer
lookupValue = DLookup("[WLocation_ID]", "[tblWarehouseLocations]", "[Location_Name] = '" & Me.cboWLocation & "'")
'Define SQL Query
strSQL = "select tblWarehouseLocations.WQuantity FROM tblWarehouseLocations WHERE (((tblWarehouseLocations.WLocation_ID)= " & lookupValue & "))"
Set rs = db.OpenRecordset(strSQL)
If IsNull(rs!WQuantity) Then
dbvalue = 0
Else
dbvalue = rs!WQuantity
End If
Dim quantityReceived As Integer
quantityReceived = Val(Me!txtQntyRecd) + dbvalue
updateQnty = "UPDATE tblSupplySources INNER JOIN ((tblWarehouseLocations " & _
"INNER JOIN tblSupplySource_WarehouseLocation ON tblWarehouseLocations.WLocation_ID = tblSupplySource_WarehouseLocation.SWLocation_ID)) " & _
"ON tblSupplySources.SupplySourceID = tblSupplySource_WarehouseLocation.Supply_Source_ID " & _
"SET tblWarehouseLocations.WQuantity = " & quantityReceived & _
" WHERE (((tblSupplySource_WarehouseLocation.Supply_Source_ID)= " & Me.cboSupplySource & ") " & _
" AND ((tblWarehouseLocations.WLocation_ID)=" & lookupValue & "))"
CurrentDb.Execute updateQnty, dbFailOnError

= and LIKE operator in a sql command

So i have these two query in my access VBA code. The When I replace like with = i end up retrieving no records. the like works perfectly with out a hitch but I can't use it because sometimes it'll pull up the wrong data. What am I doing wrong with the = operator?
Set rsStepCalendar = db.OpenRecordset("Select * from tblStepCalendar " & _
"Where (groupNr = '*" & txtGroupNum.Value & "*' ) " & _
"AND (Cancel = False)", dbOpenDynaset)
Set rs = db.OpenRecordset("Select * from tblContacts " & _
"Where (groupNum = '*" & txtGroupNum.Value & "*' ) " & _
"AND (canceledContact = False)", dbOpenDynaset)
groupNum = '*" & txtGroupNum.Value & "*'
Is looking for the value surrounded by asterisk characters which only have symbolic meaning as "anything" when combined with LIKE.
For = use groupNum = '" & txtGroupNum.Value & "'
You should also escape any user input/use parametrized queries.

how to make condition to update table?

i want to make condition to update my table if there's already same data (in the same column) inserted in the table.
im using
If String.ReferenceEquals(hotel, hotel) = False Then
insertDatabase()
Else
updateDatabase()
End If
this is the updateDatabase() code...
Dim sql2 As String = "update infoHotel set nameHotel = N" & FormatSqlParam(hotel) & _
", streetAddress = N" & FormatSqlParam(StreetAddress) & _
", locality = N" & FormatSqlParam(Locality) & _
", postalCode = N" & FormatSqlParam(PostalCode) & _
", country = N" & FormatSqlParam(Country) & _
", addressFull = N" & FormatSqlParam(address) & _
", tel = N" & FormatSqlParam(contact) & _
"where hotel = '" & hotel & "')"
this is the formatSqlParam() code:
Function FormatSqlParam(ByVal strParam As String) As String
Dim newParamFormat As String
If strParam = String.Empty Then
newParamFormat = "'" & "NA" & "'"
Else
newParamFormat = strParam.Trim()
newParamFormat = "'" & newParamFormat.Replace("'", "''") & "'"
End If
Return newParamFormat
End Function
the function manage to go into updateDatabase() but has some error saying
"Incorrect syntax near 'Oriental'."
Oriental is the data inserted in the table. is it suitable to use ReferenceEquals?
im using vb.net and sql database..tq
You should be using parameterized queries instead of concatenating strings like so:
Dim sql2 As String = "Update InfoHotel" _
& "Set nameHotel = #nameHotel" _
& ", knownAs1 = #knownAs1" _
& ", knownAs2 = #knownAs2" _
& ", knownAs3 = #knownAs3" _
& ", knownAs4 = #knownAs4" _
& " Where hotel = #hotel"
If you used parameterized queries, you wouldn't have to worry about trying do quote replacement and potentially introducing a SQL Injection vulnerability.
You have a single quote in your data, as in:
Oriental's
Show us the code for FormatSqlParam() -- the bug is probably in there.
Or else you left out the single quotes around the hotel name:
where hotel = '" & hotel & "')"
I hope that's not it, because it would mean you're using the name as a key, a very bad idea.