I have a subroutine as below
Public Sub updateStagesTable(sName As String, percentageValue As Double)
stageName = "'" & sName & "'"
sSQL = "INSERT INTO StagesT ([Stage Name], [Stage Value In Percentage]) VALUES (" & stageName & "," & percentageValue & ");"
DoCmd.SetWarnings False
DoCmd.RunSQL sSQL
End Sub
and I call it from another subroutine as below
economy = 3.53
updateStagesTable ("Economy", economy)
But I get this compile error
Compile Error: expected: =
I don't understand what I am doing wrong here. Please help.
updateStagesTable ("Economy", economy)
should be
updateStagesTable "Economy", economy
with no parentheses
See related: Unexpected results from typename
I have never liked this peculiarity of VB so I always use the alternate CALL syntax, in your case this would be:
Call updateStagesTable("Economy", economy)
which does allow the parentheses that all other languages expect
Apparently this is an area of confusion!
For one thing, wrapping the input argument in parentheses seems to work for some subroutine calls. And, furthermore, the tooltips in the VBA Editor mirror the statement defining the procedure, which includes parentheses!
So what is behind the confusion? Below is some basic code to explore this.
' Simple subroutine with two input arguments.
Sub twoInputs(in1, in2)
Debug.Print in1 & " eats "; in2 & "!"
End Sub
' Simple subroutine with one input argument.
Sub oneInput(in1)
Debug.Print in1 & " eats pizza!"
End Sub
' Routine to test various syntaxes for calling subroutines.
Sub subCallingTest()
'twoInputs("Cat", "fish") 'FAILS. Parentheses cannot be ignored here.
twoInputs "Cat", "fish" 'Works.
twoInputs ("Cat"), ("fish") 'Works, but only because parentheses can be ignored here!
Call twoInputs("Cat", "fish") 'Works.
'Call twoInputs "Cat", "fish" 'FAILS. Parentheses are required here.
oneInput "Daughter" 'Works.
oneInput ("Daughter") 'Works, but only because parentheses can be ignored here!
Call oneInput("Daughter") 'Works.
'Call oneInput "Daughter" 'FAILS. Parentheses are required here.
End Sub
It turns out that the parentheses are tolerated for a single input argument if the procedure/code only cares about the value of the inputs (see counter-example at the end), because they can be ignored in the same way as they can be when they are wrapped around individual numbers — but not when they are wrapped around several numbers.
debug.print 1 + 2 * 10 ' Answer is 21.
debug.print (1) + (2) * 10 ' Answer is 21.
debug.print (1 + 2) * 10 ' Answer is 30.
There is one very subtle clue as to when the parentheses are expected, which is in the spacing. Notice that the Editor inserts a space after the procedure's name in oneInput ("Daughter"), but not in Call oneInput("Daughter").
—DIV
P.S. If a procedure has no arguments at all, then parentheses are not used to invoke it (neither with nor without the call statement).
P.P.S. A subroutine can be guaranteed to only care about the values of the input arguments if the inputs are explicitly marked as ByVal in the defining Sub statement. In my examples above there is no explicit designation of the input arguments, so the arguments have defaulted to ByRef; however, it is apparent from the above examples that the performance will nevertheless be unaffected. A simple counter-example would be as follows.
Sub oneInputMod(in1)
in1 = UCase(in1)
Debug.Print in1 & " eats pizza!"
End Sub
Sub subCallingTestMod()
person = "everyone" ' Set a local variable's value.
oneInputMod person ' Works.
Debug.Print person ' Output is "EVERYONE", as nominally intended.
person = "everyone" ' Reset a local variable's value.
oneInputMod (person) ' Seems to work, judging by immediately visible output (which was not affected by the parentheses).
Debug.Print person ' Output is "everyone", which is nominally unintended.
person = "everyone" ' Reset a local variable's value.
Call oneInputMod(person) ' Works.
Debug.Print person ' Output is "EVERYONE", as nominally intended.
End Sub
Related
I am going to VBA for deleting data table.
It shows the errors shown in the screenshot.
Please help me to resolve it.
Private Sub cmdxoa_Click()
If Not (Me.frmformsub1.Form.Recordset.EOF And Me.frmformsub1.Form.Recordset.BOF) Then
If MsgBox("Do you wwant to delete ?", vbYesNo) = vbYes Then
CurrentDb.Execute "DELETE from db " & _
" where NOLC = " & Me.frmformsub1.Form.Recordset.Fields("nolc")
Me.frmformsub1.Form.Requery
End If
End If
End Sub
So if NOLC in the table is of type text, your criteria expression has to be:
"where NOLC = '" & Me.frmformsub1.Form.Recordset.Fields("nolc").Value & "'"
As you see you have to surround the value with '.
Remark: .Value isn't necessary, but it enhances the readability and assures that you are interested in the value and not in the object itself (the control in that case).
BUT: You should use parametrized queries instead string concatenation to avoid SQL injection:
How do I use parameters in VBA in the different contexts in Microsoft Access?
I am trying to pass 3 textboxes into a different form via parsing the string. I am getting a run time error 13.
Private Sub txtFullName_Click()
Const cstrForm As String = "frmInputInfo"
DoCmd.OpenForm "frmInputInfo", acFormAdd, , , acDialog, _
Me.txtFullName & "|" & Me.PATS_Job_Opening_ID & "|" & Me.NYCAPS_JobID
End Sub
Private Sub Form_Load()
varSplitString = Split(Me.OpenArgs, "|")
Me.[FullName].Value = varSplitString(0)
Me.[PATS Job Opening ID].Value = varSplitString(1)
Me.[NYCAPS_JobID].Value = varSplitString(2)
End Sub
and them on the form load I typed
Any help will be appreciated
You have to be extremely attentive with all those commas in the DoCmd.OpenForm options list. It's just way too darn easy to cause a misalignment between what you and Access think about which values apply to which options.
In your case you intend to pass a string, Me.txtFullName & "|" & Me.PATS_Job_Opening_ID & "|" & Me.NYCAPS_JobID, to OpenArgs. Unfortunately you omitted a comma, so Access thinks you're feeding it a value for WindowMode, which is supposed to be a number. Therefore, error 13: "type mismatch"!
Do it this way and you eliminate any confusion about which value goes with which option.
Dim strArgs As String
strArgs = Me.txtFullName & "|" & Me.PATS_Job_Opening_ID & "|" & Me.NYCAPS_JobID
Debug.Print strArgs ' make sure you got what you expect '
DoCmd.OpenForm FormName:="frmInputInfo", _
DataMode:=acFormAdd, _
WindowMode:=acDialog, _
OpenArgs:=strArgs
Also in the form event, make sure you got something for OpenArgs before you attempt to Split it. As it stands now, if the form is ever opened without supplying OpenArgs, your code will essentially attempt Split(Null, "|") and that will trigger a different error.
You can test before split like this:
If Len(Me.OpenArgs) > 0 Then
' do your split thing here '
End If
I've been using the Access "On Not In List" event for a long time. It allows you to limit the items in your combo box to a particular list, but allows the user to add an item to combo's record source on the fly if they want to enter something that isn't already there. You set the "Limit To List" property of the combo box to Yes, but then you put some code behind the "On Not In List" event. Intermittently, I get a situation in Access 2016 where this doesn't seem to work. I get the standard "The item is not in the list." error when trying to enter a new item, without my code-behind logic being seen and called. What's up?
After banging my head against the wall for a long time, I believe this is bug in Access 2016 and I think I stumbled on a fix. I set the form's RecordSetType property to Snapshot, closed and saved form, reopened the form in design view, set the RecordSetType property back to Dynaset. This seems to have cleared up the problem. I have no idea why.
But since I'm here. . . some additional details: In the code-behind for each control I use code like this:
Private Sub VendorID_NotInList(NewData As String, Response As Integer)
Response = RU_NotInList("Lookup Vendor", "Description", NewData, gc_strMsgCap)
End Sub
This type of subroutine gets created automatically behind the "On Not In List" event, when you click on the 'code builder' option. I have mine call a utility function that I wrote a long time ago. ("RU" refers a code library.)
The function returns an intrinsic Access integer constant that gets passed straight back to Access to handle.
The inside of that routine looks like this:
Function RU_NotInList(TableName As String, FieldName As String, newdata As String, Optional pstrTile As String) As Integer
Dim rs As DAO.Recordset, db As DAO.Database, n1 As Integer
RU_NotInList = DATA_ERRCONTINUE
On Error GoTo RU_NotInList_Error
If Len(Trim(newdata)) = 0 Then Exit Function
n1 = MsgBox(newdata & " is not in the list. Do you wish to add it?", MB_ICONQUESTION + MB_YESNO, pstrTile)
If n1 = IDNO Then Exit Function
Dim strSQL As String
strSQL = "INSERT INTO [" & TableName & "] ([" & FieldName & "]) VALUES (""" & newdata & """)"
WarningsHour True 'Turns hourglass cursor on, warning messages off.
DoCmd.RunSQL strSQL
WarningsHour False 'Undoes the above.
RU_NotInList = DATA_ERRADDED
Exit Function
RU_NotInList_Error:
RUError "RU_NotInList", Err 'generic error-handling routine in the RU library
Exit Function
End Function
All the all-caps items in the code above are Access intrinsic constants.
What started as a simple validation code converted in something very paradoxical in my eyes.
The following code returns "Good work!" when I input a negative number in the InputBox popup
Dim myvar As String
myvar = InputBox("input a positive number, please")
If IsNumeric(myvar) Then
myvar = CDbl(myvar)
Select Case myvar
Case Is < 0
MsgBox "I need a positive number"
Exit Sub
Case Is > 0
MsgBox "Good work!"
[MyField] = myvar
RunCommand acCmdSaveRecord
Me.Requery
Exit Sub
Case Else
MsgBox "You entered '" & myvars & "'. I don't know what to do about"
End Select
Else
MsgBox "A Number, please"
End If
Is this really the best way to validate an InputBox?
Since myvar is a String, CDbl(myvar) will get implicitly converted back to a string. Create a temporary numeric variable for the Select Case.
I agree with some of the other answers. Think about this code re-write (notice the second variable declared):
Dim myvar as String
Dim myDbl as Double
myvar = inputBox ("Input a positive number, please")
if isnumeric(myvar) then
myDbl = cDbl(myvar)
else
msgbox "Enter a number please"
exit sub
end if
if mydbl <=0 then
msgbox "I need a positive number"
else 'if mydbl > 0 then
MsgBox "Good work!"
[MyField] = myvar
RunCommand acCmdSaveRecord
Me.Requery
end if
That would solve you problems by accounting for zero and declaring a separate variable as a double there. The if statement instead of the case is just preference I suppose. But now think about the two variables you have.
debug.print "MyVar is a string containing: " & myvar
debug.print cstr(cdbl(myvar)*2)
'This forces myvar into a double(a number-type) to do math on it and then print it out
However, if you were to re-run the first print, you would see that myvar is still a string and can be used like a string. In VBA, unlike some other languages, variables are only what you declare them as. If you want to use them as other things, you have to declare another variable of the needed type.
TL;DR Think of them as different containers. Strings are circle boxes and doubles are square boxes. They might be able to hold similar stuff but the functionality of the containers is limited by their shape. In VBA you don't have a way to force a circle into a square so you have to make a whole second container and transfer the stuff over.
Im trying to create a function in my VBA where if the record they are trying to insert already exists however it returns a type mismatch.
EventCombo is a integer
MedalCombo is string
Private Sub MyCombo_BeforeUpdate(Cancel As Integer)
If Not IsNull(DLookup("RacerID", "Medals", "RaceID = " + EventCombo.Value _
+ " AND Medal = '" + MedalCombo.Value + "'" )) Then
MsgBox "Record Exists"
End If.
End Sub
What this does (or is supposed to do) is make sure no one else has the same medal in the same race.
What am I doing wrong?
With combo boxes in Access, you need to make sure that .value is really what you want. Often the first column is hidden which is .value while what is visible on the drop down box is not .value. When using a combo box to eliminate confusion I use the .columns property.
Also, to make sure the result from the combo box is a number and not text (as you did not use quotes in your example) I used the val() function to convert the combobox data to a number. If it already is a number, this will have no effect. Otherwise, if it is a digit stored as a string, it will convert it to a number. This might not be strictly necessary but it eliminates another possible problem. If the combobox column has a value which is some text which cannot convert to a number it will return 0 which you can test for in your code.
I cleaned up your code a bit with the following
I replaced the + with & like Remou said
changed .value to .columns(0). If the column you are looking for is not the first one, change 0 to the appropriate value
value() function
removed line continuation _. (Personal preference, feel free to ignore)
Private Sub MyCombo_BeforeUpdate(Cancel As Integer)
If Not IsNull(DLookup("RacerID", "Medals", "RaceID = " & Val(EventCombo.Columns(0)) & " AND Medal = '" & MedalCombo.Columns(0) & "'")) Then
MsgBox "Record Exists"
End If
End Sub