Access 2016 Subform VBA Using Double Constant as Object? - vba

So I have a subform VBA function that looks like this:
Function GetVariable() As Double
' <control> = DLookup("<table var>","<table>", "<other table var> = <control>"
[someFunction] = DLookup("[Var]", "[tblExample]", "[tblExampleVar] = [subFormControl]")
' (return) = ( <control> - <otherControl>) / 12345.12
GetVariable = ([finalPosition] - [someFunction]) / 12345.12
End Function
And when I open the parent form (the form that contains this subform), I get the error, "Run-time error '2447' There is an invalid use of the . (dot) or ! operator or invalid parentheses."
What I gather from this is that Access is interpreting 12345.12 as an object and I do not understand why. When I run this subform on its own it works, but when it is a subform it does not. Has anyone dealt with this before?
Extra information: I have two subforms in this parent form that use the same calculation, both repeated in their form-specific VBA, and I do not think that they would conflict with one another because they do not share scope. So my conclusion remains that Access is trying to use 12345.12 as (object).member.
Thanks for reading.

Try to take care of Null values and to be more specific.
Also, a decimal value must be concatenated as a string with dot decimal separator:
Function GetVariable() As Double
If Not IsNull(Me![subFormControl].Value) Then
Me![someFunction].Value = DLookup("[Var]", "[tblExample]", "[tblExampleVar] = " & Str(Me![subFormControl].Value) & "")
If Not IsNull(Me![finalPosition].Value - Me![someFunction].Value) Then
GetVariable = (Me![finalPosition].Value - Me![someFunction].Value) / 12345.12#
End If
End If
End Function

References that work when a form opens independent won't necessarily work when that same form is used as a subform. That requires referencing to include the subform container name.
I don't see how running form as standalone could return correct data. I presume [subFormControl] is a field or control on form. This is a variable input. Variable must be concatenated in the DLookup() WHERE condition expression.
It seems these fields return names of controls or table. Do these names have spaces or punctuation/special characters (other than underscore). Really should not use in names nor use reserved words as names. If you do, need to delimit with [].
If you are referencing fields/controls on form to build a DLookup(), then all the inputs are variables and should be concatenated.
[someFunction] = DLookup("[" & [Var] & "]", "[" & [Table] & "]", "[" & [Condition] & "] = '" & [subformControl] & "'")
Whether or not delimiters are needed (and which ones) depends on the field type of the field that will be returned by the Condition input in the filter criteria.

Related

Access VBA Dlookup Run-time Error - I thought I understood Dlookups lol

I am getting the following error when trying to run my code:
My code is this:
Dim ID As Long
Dim frm As Access.Form
Set frm = Forms!Frm_JobTicket
'Look up Customer Name and insert corresponding ID from Qry_CustomerID
ID = DLookup("Customer_ID", "Qry_CustomerID", "Customer_Name = " & frm("Customer_Name"))
Syteline_Customer_ID = ID
End Sub
I originally was trying to set a form control [Syteline_Customer_ID] = to the Dlookup, but it was giving me this same error, so this was my attempt at working around it. [Syteline_Customer_ID] is a text box on Frm_JobTicket.
Qry_CustomerID pulls in 2 fields from Tbl_MasterCustomerList. That table's structure is as follows:
Customer_ID - Number (Integer)
Customer_Name - Short Text
Billing_Address - Short Text
Contact_Person - Short Text
CP_Email - Short Text
CP_Phone - Short Text
I would appreciate the help, honestly I have no idea why I'm getting this error. I have already checked the Qry_CustomerID is not spelled wrong, and is not missing an underscore, that's just my naming convention. I even tried changing it to just Query1 to call it and it didn't work.
Text fields require quote enclosure around literal values. Without quotes, the Access engine assumes you are referencing another field by that literal value. And in your case the space in the name value raised a syntax error. Therefore, in concatenating the form control value, simply enclose it with single quotes:
"Customer_Name = '" & frm("Customer_Name") & "'"
Actually, you do not even need any concatenation as DLookUp can read open form fields with absolute referencing:
"Customer_Name = Forms!Frm_JobTicket!Customer_Name"

How can i properly use DLookup function to return strings?

Dim gen as String
gen = DLookup("gender", "Patient", "ID_patient='" & Me.ComboPatients.Value & "'")
I get error runtime 3464 for mis-match-type data and i don't know why?
Data mismatch error occurs if ID_patient is a number type field. Do not use apostrophe delimiters for number type, only text type field. Use # for date/time type field parameters.
From your comment (should have edited question or started a new one), concatenation is not correct. AND must be included in literal string parts - will not be colored blue. Consider:
"age='young (0-30)' AND ID_par=" & Me.ComboPatients & " AND gender='male'"
or rearrange:
"age='young (0-30)' AND gender='male' AND ID_par=" & Me.ComboPatients

Incorrect Syntax in code to filter subform

I am trying to use an AfterUpdate event to filter a subform based on the selection in a combobox.
For some reason I keep getting a error: Run-time error '3075': Syntax error in string in query expression 'VendorID = 1".
The code is:
Private Sub Combo104_AfterUpdate()
Me.ProductSelectionSubform.Form.Filter = "VendorID = " & Me.Combo104.Value & "'"
Me.ProductSelectionSubform.Form.FilterOn = True
End Sub
Its nice and simple, but it keeps throwing that error. If I add a ' in = '" I get a a mismatch error.
Where am I messing up with this?
Since criteria field is a number type, no delimiters are needed - remove the apostrophe.
If field were text type, then the apostrophe would need a mate.
Use # delimiter for date/time field parameters.
Value is default property for data controls. Can save yourself some typing and omit it.

"Query too Complex": MS Access Function to Replace text in Query (Nested Replace())

Purpose: Use a SQL Query in MS Access to locate all records matching specific keywords in a long text field
I am attempting to query for all records in a MS Access DB that have a match on a list of specific keywords within a field. The keywords are as follows:
AIN, ATIN, CKD, AKI, ARF
Issue I'm running into is that the field is a free text entry field, so the formatting of the data is all over the place, and the keywords I'm searching on will often appear in the middle of other full length words (i.e. AIN matches on "pAIN","agAIN", etc), while I only want to include matches on words that are strictly the keywords (i.e. " AIN ", " AKI ").
The idea I'm working with is to simply include matches that will hit on the following format: field_name like '* AIN *'.So basically only include matches that have a space before and after the keyword to limit the number of false positives appearing in the result set.
I have tried writing a SQL query that will normalize the data so that all other characters that appear (".","!","?","#", etc...) will be replaced with a space character (i.e. " AIN!" would be replace(field_name,"!"," ") = " AIN ") with the idea that this should only include words containing only the keyword. In attempting to run my very long nested replace statement in the query, I am receiving the "Query Too Complex" message. Nested replace is as follows:
UCASE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(a.REF_CONTENT_NM,chr(13)," "),chr(10)," "),"`"," "),"~"," "),"!"," "),"#"," "),"#"," "),"$"," "),"%"," "),"^"," "),"&"," "),"*"," "),"("," "),")"," "),"-"," "),"_"," "),"="," "),"+"," "),"["," "),"{"," "),"]"," "),"}"," "),";"," "),":"," "),","," "),"<"," "),"."," "),">"," "),"/"," "),"?"," "),"\"," "),"|"," "),""""," ")) like "* AIN *"
I believe that a workaround would be to create a custom function that could be referenced in the SQL statement, but I am not entirely sure of how to accomplish this. So essentially, I am looking for guidance on how to evaluate a solution of how to normalize the text like the above nested replace statement in Access without running into the "Query Too Complex message". I feel like there is a simple solution that I am just not seeing here, so guidance would be tremendously appreciated!
The main trick to writing a custom function to do this is properly using the ParamArray
This is a small function that executes multiple replaces:
Public Function ReplaceMultiple(strInput As String, strReplace As String, ParamArray Find() As Variant) As String
Dim i As Long
ReplaceMultiple = strInput
For i = LBound(Find) To UBound(Find)
ReplaceMultiple = Replace(ReplaceMultiple, Find(i), strReplace)
Next
End Function
Implement it:
ReplaceMultiple(a.REF_CONTENT_NM, " ", chr(13), chr(10), "`", "etc....")
You might need to think about altering the logic altogether, though, for example keeping a table of characters that should be replaced. I remember something about the max number of arguments being around 20-30, so you might need to use ReplaceMultiple twice.
If you just want to replace everything that isn't a string with a space, you can try the following small function:
Public Function ReplaceNonAlphanumeric(str As String) As String
If str = "" Then Exit Function
Dim i As Long
For i = 1 To Len(str)
If Mid(str, i, 1) Like "[0-9A-z]" Then
ReplaceNonAlphanumeric = ReplaceNonAlphanumeric & Mid(str, i, 1)
Else
ReplaceNonAlphanumeric = ReplaceNonAlphanumeric & " "
End If
Next
End Function

VBA Textbox comparisons providing illogical results

Premise: Performing comparisons between two textboxes, one in a subform, one in a parent form, during the subform textbox's AfterUpdate event. When making this comparison, illogical results are returned.
Objective: Return legitimate comparisons between the values contained within these two controls.
Progress:
The following code shows an example of code and apparent, illegitimate results outputted to the Immediate window.
Code:
Debug.Print IsNumeric(textBurnup) & IsNumeric(Parent!textBurnupLimit), _
textBurnup & ">" & Parent!textBurnupLimit & " = " & _
(textBurnup > Parent!textBurnupLimit)
textBurnup = Parent!textBurnupLimit - 100
Debug.Print IsNumeric(textBurnup) & IsNumeric(Parent!textBurnupLimit), _
textBurnup & ">" & Parent!textBurnupLimit & " = " & _
(textBurnup > Parent!textBurnupLimit)
Results:
TrueTrue 100>21500 = True
TrueTrue 21400>21500 = False`
Things I have tried:
Setting textbox format to 'general number'. Fixes problem but I dont want to have to do this.
Performing an arithmetic operation on either control. Fixes problem but I dont want to have to do this.
Using either controls' .Value property. Doesn't work.
Substituting a number in for the Parent!textbox. Works. Defeats the purpose of looking at the Parent's textbox.
A few other things I can't think of now because I am just too surprised that I managed to break logic.
The textboxes are both numbers and should be comparable. Why is this happening? Why does setting one of their formats to 'general number' fix it?
Related articles:
String Compare Logic (based on answers below)
Source Info:
Coding Horror (based on answers below)
In your example 100 > 21500 is True because it's a string ("ascii-betical") comparison, not a numeric one.
One wrinkle in that though...
? "100" > "21500" --> False!
? "100" >" 21500" --> True!
I'm guessing your observed result was because you had a leading space on the second value: if that wasn't the case there's no way it would evaluate to True...
IsNumeric() doesn't check to see if a variable value is a number, just if it could safely be converted to one, so
IsNumeric("100") = True
even though "100" is a string.
If you want values pulled from to behave as numbers then the correct approach is
1) use IsNumeric() to check they can safely be converted to a numeric type then
2) use CDbl(), CLng() etc to convert them as #simoco suggests.
"CDbl(textBurnup) > CDbl(Parent!textBurnupLimit)?" - simoco
"In your example 100>21500 is True because it's a string ("ascii-betical") comparison, not a numeric one. IsNumeric() doesn't check to see if a variable value is a number, so IsNumeric("100") = True even though "100" is a string. If you want values pulled from to behave as numbers then the correct approach is 1)Use IsNumeric() to check they can safely be converted to a numeric type then 2) use CDbl(), CLng() etc to convert them as #simoco suggests" - Tim Williams