Dcount function using parameters - vba

I want to prevent sql injection in my dcount function which I have here
DCount("[Treasury Name]", "tblTreasuries", "[Treasury Name] = '" & txtTreasuryName & "'")
this txtTreasuryName is a form input I have , of course the problem is when I input ' or " in the form i get an error and i don't know the right way to make this statement parametric

I don't understand why a " in txtTreasuryName would break your DCount() expression , but it's clear that a ' would.
Nevertheless you can avoid problems from either type of quote character by using a reference to the textbox instead of concatenating the textbox's value into your DCount() expression.
DCount("*", "tblTreasuries", "[Treasury Name] = Forms!YourFormName!txtTreasuryName")

If you can enter "Name1","Name2", then use IN:
Textbox holds: "Name1","Name2"
Count = DCount("*", "tblTreasuries", "[Treasury Name] In (" & Me!txtInput.Value & ")")

Related

ACCESS VBA Unmatched Records Query Not Working When Concatenating

I have been trying to run a query from MS ACCESS VBA. My query works well when I don't add concatenated fields. When I use a concatenated field like in the code below, it turns an empty result.
Is there any work around?
lstStudentName.RowSource = "SELECT [sdtName] & ' ' & [sdtFatherName] & ' ' & [sdtLastName] AS sdtFullName, sdtID FROM tbl_sdt_Info " & _
" LEFT join tbl_sdt_Rounds ON tbl_sdt_Info.sdtID = tbl_sdt_Rounds.sdtID " & _
" WHERE IS NULL(tbl_sdt_Rounds.sdtID)"
Issues with your SQL:
Incorrect use of IS NULL - should be either IsNull(tbl_sdt_Rounds.sdtID) or tbl_sdt_Rounds.sdtID IS NULL. The latter is preferable because it is SQL, IsNull() is a VBA function.
Since there are two sdtID fields, query shouldn't work without table prefix to specify field. I am surprised you get anything.
Although possibly not an issue as is, my preference would be to make sdtID the first field and set ColumnWidths as 0";1.0" and first column as BoundColumn. This will allow viewing and typing first letter of name but sdtID will be listbox value.
Never hurts to build and test query object and when it works, replicate SQL statement in VBA.
lstStudentName.RowSource = "SELECT tbl_sdt_Info.sdtID, sdtName & ' ' & sdtFatherName & ' ' & sdtLastName AS sdtFullName FROM tbl_sdt_Info " & _
"LEFT join tbl_sdt_Rounds ON tbl_sdt_Info.sdtID = tbl_sdt_Rounds.sdtID " & _
"WHERE tbl_sdt_Rounds.sdtID IS NULL;"

Filter by multiple parameters on Access form

I have a MS Access form that I want to filter the database based on a SQL statement.
The form will use multiple parameters, but I want it so that not all fields are required to perform the filter.
An example would be: User wants to query only by Date and Product and leave Customer and Analysis blank.
These are the fields in the form:
So far I have tried the following statements and using "LIKE" but it is returning blank results. I have only tried with two fields and it isn't working.
Public Sub Command121_Click()
Dim task As String
task = "select * from SageOrderLines_Live where [PromisedDeliveryDate] = " & Format(Me.DateFrom, "\#dd\/mm\/yyyy\#") & " AND [CustomerAccountNumber] LIKE "" & Me.CustomerAccount & """
DoCmd.ApplyFilter task
End Sub
Using LIKE without wildcard might as well be = sign.
Use of quote delimiters is incorrect - really need another quote on each side.
" AND [CustomerAccountNumber] LIKE """ & Me.CustomerAccount & "*"""
Or make it easier to read and use apostrophe instead of doubled quotes.
" AND [CustomerAccountNumber] LIKE '" & Me.CustomerAccount & "*'"

Passing value to textbox with sql query via VBA code - MS ACCESS

I am currently working in MS ACCESS. I have 2 forms one called MyForm and the second one name Transit. I have one table called SimulationTable which have 4 fields Fiscal_Year, Scenario_Number, Description and Operating_Unit. I would like with VBA code when clicking in a button to display result of SQL query in the textbox called TXTBOX which is in Transit form. I have tried many times but it doesn't work.
Any idea of how to fix ? Thank you.
Here is the SQL query:
SELECT SimulationTable.Description FROM SimulationTable WHERE Fiscal_Year=Forms!MainForm!OperatingFY AND Operating_Unit = Forms!MainForm!Text3 AND Scenario_Number = Forms!MainForm!Selected_scenario
Could just use DLookup():
Me.TXTBOX = DLookup("[Description]", "SimulationTable", "Fiscal_Year=" & Forms!MainForm!OperatingFY & _
" AND Operating_Unit = " & Forms!MainForm!Text3 & _
" AND Scenario_Number = " & Forms!MainForm!Selected_scenario)
Are these criteria fields all number type? Is TXTBOX bound to a field? If not, could even just put the DLookup() expression in ControlSource property.
It works. I have added apostrophes around the "Operating_Unit" which is a field in text format. Thanks very much June7.
Me.TXTBOX = DLookup("[Description]", "SimulationTable", "Fiscal_Year=" & Forms!MainForm!OperatingFY & " AND Operating_Unit ='" & Forms!MainForm!Text3 & "' AND Scenario_Number =" & Forms!MainForm!Selected_scenario)

Get VBA to Evaluate Formula In String

I have a table that stores a string representing a formula that I would like to have either Access or VBA evaluate. A few example strings look like:
table.FirstName & ' ' & table.LastName
table.LastName & ', ' & table.FirstName
table.LastName & ', ' & table.FirstName & ' ' & LEFT(table.Middle,1)
Basically, I'm trying to change how different names can be viewed based on entity type, missing information, etc.
Is there any way to force either Access (in a query) or VBA (as part of a custom function) to return what the string is telling it as opposed to the literal value? From the examples above, I would expect:
table.FirstName table.LastName
table.LastName, table.FirstName
table.LastName, table.Firstname, t
Replace by itself won't work, as some of the formatting includes LEFT(table.Name,1) or other functions. I'm just hoping there is a simple way to force the string to be evaluated, rather than having to come up with a complex function.
I apologize if I haven't explained this well, I feel like my attempt to merge the database aspect with the string formatting aspect may not come across clearly. If you have questions please reply and I'll do my best to explain it better.
Thank you in advance.
How about the Microsoft Access Eval() function:
?Eval("3 + 1")
4
You could build an SQL string from your table formulas like:
SQL = "Select " & tblFormulas.FormulaField.Value & " From " & Split(tblFormulas.FormulaField.Value, ".")(0) & ";"
Not bullet-proof but a start ...
As you have a special table with formulas you can aim at queries and/or VBA.
For VBA you can store code for eval function to be run in form of several forms with same set of required fields(that is used in formulas):
in field VBAformula of your special table should resides such string me![LastName] & ', ' & me!FirstName & ' ' & LEFT(Me![Middle],1)
then in some function you could write:
formula = dlookup("VBAformula","SpecialTable","id=" & me![HowToViewID])
Me![ViewAs] = eval(formula)
For Queries you can store SQL formula to be used in UPDATE query, SQLformula with such string:
[LastName] & ", " & [FirstName] & " " & LEFT([Middle],1) then you can build and run SQL:
formula = dlookup("SQLformula","SpecialTable","id=" & me![HowToViewID])
currentdb.Execute "UPDATE [table with people] SET [ViewAs] = " & formula & " WHERE peopleID=" & Me![peopleID] & ";" , dbFailOnError
These are examples to show some variants, so there is no error handling or security.

Escaping ' in Access SQL

I'm trying to do a domain lookup in vba with something like this:
DLookup("island", "villages", "village = '" & txtVillage & "'")
This works fine until txtVillage is something like Dillon's Bay, when the apostrophe is taken to be a single quote, and I get a run-time error.
I've written a trivial function that escapes single quotes - it replaces "'" with "''". This seems to be something that comes up fairly often, but I can't find any reference to a built-in function that does the same. Have I missed something?
The "Replace" function should do the trick. Based on your code above:
DLookup("island", "villages", "village = '" & Replace(txtVillage, "'", "''") & "'")
It's worse than you think. Think about what would happen if someone entered a value like this, and you haven't escaped anything:
'); DROP TABLE [YourTable]
Not pretty.
The reason there's no built in function to simply escape an apostrophe is because the correct way to handle this is to use query parameters. For an Ole/Access style query you'd set this as your query string:
DLookup("island", "village", "village = ? ")
And then set the parameter separately. I don't know how you go about setting the parameter value from vba, though.
Though the shorthand domain functions such as DLookup are tempting, they have their disadvantages. The equivalent Jet SQL is something like
SELECT FIRST(island)
FROM villages
WHERE village = ?;
If you have more than one matching candidate it will pick the 'first' one, the definition of 'first' is implementation (SQL engine) dependent and undefined for the Jet/ACE engine IIRC. Do you know which one would be first? If you don’t then steer clear of DLookup :)
[For interest, the answer for Jet/ACE will either be the minimum value based on the clusterd index at the time the database file was last compacted or the first (valid time) inserted value if the database has never been compacted. Clustered index is in turn determined by the PRIAMRY KEY if persent otherwise a UNIQUE constraint or index defined on NOT NULL columns, otherwise the first (valid time) inserted row. What if there is more than one UNIQUE constraint or index defined on NOT NULL columns, which one would be used for clustering? I've no idea! I trust you get the idea that 'first' is not easy to determine, even when you know how!]
I've also seen advice from Microsoft to avoid using domain aggregate functions from an optimization point of view:
Information about query performance in an Access database
http://support.microsoft.com/kb/209126
"Avoid using domain aggregate functions, such as the DLookup function... the Jet database engine cannot optimize queries that use domain aggregate functions"
If you choose to re-write using a query you can then take advantage of the PARAMETERS syntax, or you may prefer the Jet 4.0/ACE PROCEDURE syntax e.g. something like
CREATE PROCEDURE GetUniqueIslandName
(
:village_name VARCHAR(60)
)
AS
SELECT V1.island_name
FROM Villages AS V1
WHERE V1.village_name = :village_name
AND EXISTS
(
SELECT V2.village_name
FROM Villages AS V2
WHERE V2.village_name = V1.village_name
GROUP
BY V2.village_name
HAVING COUNT(*) = 1
);
This way you can use the engine's own functionality -- or at least that of its data providers -- to escape all characters (not merely double- and single quotes) as necessary.
But then, it should be like this (with one more doublequote each):
sSQL = "SELECT * FROM tblTranslation WHERE fldEnglish=""" & myString & """;"
Or what I prefer:
Make a function to escape single quotes, because "escaping" with "[]" would not allow these characters in your string...
Public Function fncSQLStr(varStr As Variant) As String
If IsNull(varStr) Then
fncSQLStr = ""
Else
fncSQLStr = Replace(Trim(varStr), "'", "''")
End If
End Function
I use this function for all my SQL-queries, like SELECT, INSERT and UPDATE (and in the WHERE clause as well...)
strSQL = "INSERT INTO tbl" &
" (fld1, fld2)" & _
" VALUES ('" & fncSQLStr(str1) & "', '" & fncSQLStr(Me.tfFld2.Value) & "');"
or
strSQL = "UPDATE tbl" & _
" SET fld1='" & fncSQLStr(str1) & "', fld2='" & fncSQLStr(Me.tfFld2.Value) & "'" & _
" WHERE fld3='" & fncSQLStr(str3) & "';"
I believe access can use Chr$(34) and happily have single quotes/apostrophes inside.
eg
DLookup("island", "villages", "village = " & chr$(34) & nonEscapedString & chr$(34))
Though then you'd have to escape the chr$(34) (")
You can use the Replace function.
Dim escapedString as String
escapedString = Replace(nonescapedString, "'", "''")
Parametrized queries such as Joel Coehoorn suggested are the way to go, instead of doing concatenation in query string. First - avoids certain security risks, second - I am reasonably certain it takes escaping into engine's own hands and you don't have to worry about that.
By the way, here's my EscapeQuotes function
Public Function EscapeQuotes(s As String) As String
If s = "" Then
EscapeQuotes = ""
ElseIf Left(s, 1) = "'" Then
EscapeQuotes = "''" & EscapeQuotes(Mid(s, 2))
Else
EscapeQuotes = Left(s, 1) & EscapeQuotes(Mid(s, 2))
End If
End Function
For who having trouble with single quotation and Replace function, this line may save your day ^o^
Replace(result, "'", "''", , , vbBinaryCompare)
put brackets around the criteria that might have an apostrophe in it.
SOmething like:
DLookup("island", "villages", "village = '[" & txtVillage & "]'")
They might need to be outside the single quotes or just around txtVillage like:
DLookup("island", "villages", "village = '" & [txtVillage] & "'")
But if you find the right combination, it will take care of the apostrophe.
Keith B
My solution is much simpler. Originally, I used this SQL expression to create an ADO recordset:
Dim sSQL as String
sSQL="SELECT * FROM tblTranslation WHERE fldEnglish='" & myString & "';"
When myString had an apostrophe in it, like Int'l Electrics, my program would halt. Using double quotes solved the problem.
sSQL="SELECT * FROM tblTranslation WHERE fldEnglish="" & myString & "";"