Dcount on multiselect listbox? - ms-access

Me again. This code works fine when only 1 item is selected, however when more than one item is selected I get the error "syntax error (comma) in query expression" on the following line of code:
intCountNull = DCount("*", "Scrubbed", strCriteria & " Is Null")
Here is my code:
Private Sub Command29_Click()
Dim strCriteria As String
Dim intCountNull As Integer
Dim varItem As Variant
'On Error GoTo Err_Command29_Click
Me.Fields_Values.RowSource = ""
For Each varItem In Me!List101.ItemsSelected
strCriteria = strCriteria & "," & Me!List101.ItemData(varItem)
Next varItem
strCriteria = Right(strCriteria, Len(strCriteria) - 1)
intCountNull = DCount("*", "Scrubbed", strCriteria & " Is Null")
Fields_Values.RowSource = intCountNull & " null values found in " & strCriteria
Exit_Command29_Click:
Exit Sub
'Err_Command29_Click:
'MsgBox "Please select a field"
End Sub

... when more than one item is selected I get the error "syntax error (comma) in query expression" on the following line of code: intCountNull = DCount("*", "Scrubbed", strCriteria & " Is Null")
That makes sense. If the list box selections were "field1", "field3", and "field4", your DCount() would throw error #3075, "Syntax error (comma) in query expression 'field1,field3,field4 Is Null'."
The DCount() expression would be evaluated like this SELECT statement:
SELECT Count(*)
FROM Scrubbed
WHERE field1,field3,field4 Is Null
And the db engine will definitely complain about that WHERE clause. You can't give it a list of field names and ask it whether the list Is Null. You would have to separately ask whether each field Is Null.
That is the explanation for why you get that error. However, I think you need to change your approach.
Build up the RowSource value list string for Fields_Values as you iterate through List101 selected items. (Make sure you have Value List as the Row Source Type property for Fields_Values.) Here is a tested sample which does what I think you want.
Private Sub Command29_Click()
Dim strCriteria As String
Dim intCountNull As Integer
Dim varItem As Variant
Dim strRowSource As String
Me.Fields_Values.RowSource = ""
For Each varItem In Me!List101.ItemsSelected
strCriteria = "[" & Me!List101.ItemData(varItem) & _
"] Is Null"
intCountNull = DCount("*", "Scrubbed", strCriteria)
'Debug.Print strCriteria, intCountNull '
strRowSource = strRowSource & ";" & intCountNull & _
" null values found in " & _
Me!List101.ItemData(varItem)
Next varItem
'Debug.Print strRowSource '
If Len(strRowSource) > 0 Then
strRowSource = Mid(strRowSource, 2)
Me.Fields_Values.RowSource = strRowSource
End If
'Debug.Print strRowSource '
End Sub
Also I don't see why the user should even be allowed to click Command29 unless List101 contains selected items. So consider disabling Command29 until selections have been made.
Private Sub Form_Load()
Me.Command29.Enabled = False
End Sub
Private Sub List101_AfterUpdate()
Me.Command29.Enabled = (Me.List101.ItemsSelected.Count > 0)
End Sub
Finally, I'll suggest you do yourself a favor by giving your controls meaningful names ... Command29 could be cmdShowNullCounts and List101 could be lstFieldNames. Meaningful names are especially helpful when you're dealing with dozens of controls. You should also find them helpful when you need to revisit the form design after a few months. Anyone else who has to take over in the future will appreciate your courtesy.

Related

Searching function for textbox and letting my function still run when there are none entries in for the textbox and listbox

All I really need to know is how to make it where I can make selections in multiple multi-select listboxes, but leave any number of them blank and still have the macro/query work without having to put in an error message about it.
This also includes doing the same with the textboxes. The textboxes would function the same as the listboxes where they would search for anything in a data table to matches what I am looking for in the records and display what I am looking for in a table.
Here is my code
Private Sub Command62_Click()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim varItem As Variant
Dim District As String
Dim Circumstance As String
Dim Location As String
Dim Method As String
Dim Point As String
Dim Rank As String
Dim strSQL As String
Set db = CurrentDb()
Set qdf = db.QueryDefs("qryMultiselect")
For Each varItem In Me!District.ItemsSelected
District = District & ",'" & Me!District.ItemData(varItem) & "'"
Next varItem
If Len(District) = 0 Then
MsgBox "You did not select anything in the Distrcit field." _
, vbExclamation, "Nothing to find!"
Exit Sub
End If
District = Right(District, Len(District) - 1)
For Each varItem In Me!Circumstance.ItemsSelected
Circumstance = Circumstance & ",'" & Me!Circumstance.ItemData(varItem) &
"'"
Next varItem
If Len(Circumstance) = 0 Then
MsgBox "You did not select anything in the Circumstance field." _
, vbExclamation, "Nothing to find!"
Exit Sub
End If
Circumstance = Right(Circumstance, Len(Circumstance) - 1)
For Each varItem In Me!Location.ItemsSelected
Location = Location & ",'" & Me!Location.ItemData(varItem) & "'"
Next varItem
If Len(Location) = 0 Then
MsgBox "You did not select anything in the Location field." _
, vbExclamation, "Nothing to find!"
Exit Sub
End If
Location = Right(Location, Len(Location) - 1)
For Each varItem In Me!Method.ItemsSelected
Method = Method & ",'" & Me!Method.ItemData(varItem) & "'"
Next varItem
If Len(Method) = 0 Then
MsgBox "You did not select anything in the Method field." _
, vbExclamation, "Nothing to find!"
Exit Sub
End If
Method = Right(Method, Len(Method) - 1)
For Each varItem In Me!Point.ItemsSelected
Point = Point & ",'" & Me!Point.ItemData(varItem) & "'"
Next varItem
If Len(Point) = 0 Then
MsgBox "You did not select anything in the Point field." _
, vbExclamation, "Nothing to find!"
Exit Sub
End If
Point = Right(Point, Len(Point) - 1)
For Each varItem In Me!Rank.ItemsSelected
Rank = Rank & ",'" & Me!Rank.ItemData(varItem) & "'"
Next varItem
If Len(Rank) = 0 Then
MsgBox "You did not select anything in the Rank field." _
, vbExclamation, "Nothing to find!"
Exit Sub
End If
Rank = Right(Rank, Len(Rank) - 1)
strSQL = "SELECT * FROM tblDataEntry " & _"WHERE tblDataEntry.District
IN(" & District & ") AND tblDataEntry.Circumstance IN(" & Circumstance &
") AND tblDataEntry.Location IN(" & Location & ") AND tblDataEntry.Method
IN (" & Method & ") AND tblDataEntry.Point IN (" & Point & ") AND
tblDataEntry.Rank IN(" & Rank & ");"
qdf.SQL = strSQL
DoCmd.OpenQuery "qryMultiselect"
Set db = Nothing
Set qdf = Nothing
End Sub
I still need to add the textboxes, but I'm not sure where. (Please note that I'm still learning VBA).
Firstly, since you are repeatedly performing the same operation for each form control (in this case, constructing a comma-delimited string from the selected items), you can abstract this operation away into a function, and pass such function each List Box function.
For example, you could define a function such as:
Function SelectedItems(objBox As ListBox) As String
Dim strRtn As String, varItm
For Each varItm In objBox.ItemsSelected
strRtn = strRtn & ",'" & objBox.ItemData(varItm) & "'"
Next varItm
If strRtn <> vbNullString Then SelectedItems = Mid(strRtn, 2)
End Function
Which could then be evaluated with a List Box control argument, and would return either a null string ("") or a comma-delimited string of the selected items in the list box, e.g. something like:
?SelectedItems(Forms!Form1!List1)
'A','B'
Furthermore, since your form controls appear to be named consistently relative to the fields in your table, you could further condense your code to something along the following lines:
Private Sub Command62_Click()
Dim strSQL As String
Dim strArr As String
Dim varItm
For Each varItm In Array("District", "Circumstance", "Location", "Method", "Point", "Rank")
strArr = SelectedItems(Me.Controls(varItm))
If strArr <> vbNullString Then
strSQL = strSQL & "t." & varItm & " in (" & strArr & ") and "
End If
Next varItm
If strSQL <> vbNullString Then strSQL = "where " & Left(strSQL, Len(strSQL) - 5)
With CurrentDb.QueryDefs("qryMultiselect")
.SQL = "select * from tblDataEntry t " & strSQL
End With
DoCmd.OpenQuery "qryMultiselect"
End Sub
Note that the above is entirely untested.
Here, the main for each loop iterates over an array of strings corresponding to the names of your form controls and the names of your table fields.
For each form control in this array, the function obtains a comma-delimited string of the selected items in the control, and concatenates this with the existing SQL code only if one or more items have been selected.
As such, if not items are selected, the field will not feature in the SQL where clause.
If any filter has been selected, the trailing five characters (and) are trimmed from the end of the SQL string, and the where keyword is concatenated to the start of the SQL string - this ensures that if no filter has been selected, the resulting SQL code will not include a where clause.
Finally, the SQL for the query definition is updated and the query is opened, per your original code.
Where textboxes are concerned, the task merely need to skip the call to SelectedItems and obtain the value of the textbox directly.
Here is an example incorporating both listboxes & textboxes:
Private Sub Command62_Click()
Dim strSQL As String
Dim strArr As String
Dim varItm
For Each varItm In Array("District", "Circumstance", "Location", "Method", "Point", "Rank")
strArr = vbNullString
Select Case Me.Controls(varItm).ControlType
Case acListBox
strArr = SelectedItems(Me.Controls(varItm))
Case acTextBox
If Not IsNull(Me.Controls(varItm).Value) Then
strArr = "'" & Me.Controls(varItm).Value & "'"
End If
End Select
If strArr <> vbNullString Then
strSQL = strSQL & "t." & varItm & " in (" & strArr & ") and "
End If
Next varItm
If strSQL <> vbNullString Then strSQL = "where " & Left(strSQL, Len(strSQL) - 5)
With CurrentDb.QueryDefs("qryMultiselect")
.SQL = "select * from tblDataEntry t " & strSQL
End With
DoCmd.OpenQuery "qryMultiselect"
End Sub
I hope this helps, but please note that the above is untested and only theory.

Ms Access VBA: Return the Formula behind a Query Field

I have a Sub Procedure that will create a table based on an existing query with 2 text fields (FieldName and SourceName). the value of FieldName will be the name of each field in the existing query, and the value of SourceName will be the name of the table or Query that the field comes from. See the code below. What I am looking to do is to also include the formulas for calculated fields in a 3rd field called FieldFormula. Does anyone know if this is possible? Thank you!
Option Compare Database
Public Sub MapQuery()
Dim strQueryName As String
Dim rst As DAO.Recordset
Dim fld As Field
Dim strSource As String
Dim strField As String
Dim strValue As String
Dim strSQL1 As String
Dim strSQL2 As String
Dim booExists As Boolean
strQueryName = InputBox("Please enter the name of the query that you are looking to map")
Set rst = CurrentDb.OpenRecordset(strQueryName)
intLen = Len(strQueryName)
strnewtablename = Right(strQueryName, intLen - 4)
On Error GoTo error1
booExists = IsObject(CurrentDb.TableDefs(strnewtablename & " Definitions"))
DoCmd.DeleteObject acTable, strnewtablename & " Definitions"
continue:
strSQL1 = "CREATE TABLE [" & strnewtablename & " Definitions]" & " (FieldName CHAR, SourceName CHAR);"
DoCmd.RunSQL (strSQL1)
DoCmd.SetWarnings False
For Each fld In rst.Fields
strField = fld.Name
strSource = fld.SourceTable
Debug.Print strValue
strSQL2 = "INSERT INTO [" & strnewtablename & " Definitions]" & "(FieldName, SourceName) VALUES(""" & strField & """, """ & strSource & """);"
DoCmd.RunSQL (strSQL2)
Next fld
error1:
If Err.Number = 3265 Then
Resume continue
Else
MsgBox Err.Description
End If
DoCmd.SetWarnings True
Exit Sub
DoCmd.SetWarnings True
End Sub
Pulling the expression from a table Calculated field is simple. I did a quick test in the VBA immediate window:
CurrentDb.TableDefs("Teams").Fields("Test").Properties("Expression")
And that returns the expression string. I expect your code will have to do conditional statement that checks if the field is a Calculated type.
However, if you want to pull expression of a calculated field in query, that is very different. There is no "Expression" property as there really is not a field entity. I would say #Andre explained it with 'exist only in the QueryDef.SQL property' as part of the statement string.

Access VBA Filtering code Syntax Error issue

I have the code below (courtesy of allenbrowne, his info are in the code). When I am filtering using one of the columns (One_or_Two_Pearl) it is giving me a (Syntax error missing operator in query expression). I can not trace the problem as everything look fine. That column is defined as Text type and contains data (1, 2, NA). This problem is only occurring for this column, and when I debug the yellow mark is indicating the (Me.Filter = strWhere) part.
Thank you in advance for your help.
'http://allenbrowne.com/ser-62.html
'Purpose: This module illustrates how to create a search form, _
where the user can enter as many or few criteria as they wish, _
and results are shown one per line.
'Note: Only records matching ALL of the criteria are returned.
'Author: Allen Browne (allen#allenbrowne.com), June 2006.
Option Compare Database
Option Explicit
Private Sub cmdFilter_Click()
'Purpose: Build up the criteria string form the non-blank search boxes, and apply to the form's Filter.
'Notes: 1. We tack " AND " on the end of each condition so you can easily add more search boxes; _
we remove the trailing " AND " at the end.
' 2. The date range works like this: _
Both dates = only dates between (both inclusive. _
Start date only = all dates from this one onwards; _
End date only = all dates up to (and including this one).
Dim strWhere As String 'The criteria string.
Dim lngLen As Long 'Length of the criteria string to append to.
Const conJetDate = "\#mm\/dd\/yyyy\#" 'The format expected for dates in a JET query string.
'***********************************************************************
'Look at each search box, and build up the criteria string from the non-blank ones.
'***********************************************************************
'Text field example. Use quotes around the value in the string.
If Not IsNull(Me.cboxprojphase) Then
strWhere = strWhere & "([Project_Phase] = """ & Me.cboxprojphase & """) AND "
End If
'Another text field example. Use Like to find anywhere in the field.
If Not IsNull(Me.cboxcontract) Then
strWhere = strWhere & "([Contract] = """ & Me.cboxcontract & """) AND "
End If
'Number field example. Do not add the extra quotes.
If Not IsNull(Me.cboxdesigndpm) Then
strWhere = strWhere & "([Design_DPM] = """ & Me.cboxdesigndpm & """) AND "
End If
'Text field example. Use quotes around the value in the string.
If Not IsNull(Me.cboxadmupc) Then
strWhere = strWhere & "([ADM/UPC] = """ & Me.cboxadmupc & """) AND "
End If
'Text field example. Use quotes around the value in the string.
If Not IsNull(Me.cboxpearl) Then
strWhere = strWhere & "([One_or_Two_Pearl] = """ & Me.cboxpearl & """) "
End If
'***********************************************************************
'Chop off the trailing " AND ", and use the string as the form's Filter.
'***********************************************************************
'See if the string has more than 5 characters (a trailng " AND ") to remove.
lngLen = Len(strWhere) - 5
If lngLen <= 0 Then 'Nah: there was nothing in the string.
MsgBox "No criteria", vbInformation, "Nothing to do."
Else 'Yep: there is something there, so remove the " AND " at the end.
strWhere = Left$(strWhere, lngLen)
'For debugging, remove the leading quote on the next line. Prints to Immediate Window (Ctrl+G).
'Debug.Print strWhere
'Finally, apply the string as the form's Filter.
Me.Filter = strWhere
Me.FilterOn = True
End If
End Sub
Private Sub cmdReset_Click()
'Purpose: Clear all the search boxes in the Form Header, and show all records again.
Dim ctl As Control
'Clear all the controls in the Form Header section.
For Each ctl In Me.Section(acHeader).Controls
Select Case ctl.ControlType
Case acTextBox, acComboBox
ctl.Value = Null
Case acCheckBox
ctl.Value = False
End Select
Next
'Remove the form's filter.
Me.FilterOn = False
Me.OrderByOn = False
End Sub
Private Sub Form_BeforeInsert(Cancel As Integer)
'To avoid problems if the filter returns no records, we did not set its AllowAdditions to No.
'We prevent new records by cancelling the form's BeforeInsert event instead.
'The problems are explained at http://allenbrowne.com/bug-06.html
Cancel = True
MsgBox "You cannot add new Records to the search form.", vbInformation, "Permission denied."
End Sub
Private Sub Form_Open(Cancel As Integer)
'Remove the single quote from these lines if you want to initially show no records.
'Me.Filter = "(False)"
'Me.FilterOn = True
Dim strURL As String
Dim objIE As Object
Dim arrSites(2) As String
Dim i As Integer
arrSites(0) = "http://google.com"
arrSites(1) = "http://google.com"
Set objIE = CreateObject("InternetExplorer.Application")
For i = 0 To 1 Step 1
strURL = arrSites(i)
If i = 0 Then
objIE.Navigate strURL
Else
objIE.Navigate2 strURL, 2048
End If
Next i
objIE.Visible = True
Set objIE = Nothing
'objIE.Quit
End Sub
Private Sub optSortorder_AfterUpdate()
If Me.optSortorder = 1 Then
Me.OrderBy = Me.cboSortField
Else
Me.OrderBy = Me.cboSortField & " DESC"
End If
Me.OrderByOn = True
End Sub
Both your problems are here:
strWhere = Left$(strWhere, lngLen)
'For debugging, remove the leading quote on the next line. Prints to Immediate Window (Ctrl+G).
'Debug.Print strWhere
Uncomment the Debug.Print line to see what is happening:
it tries to remove a trailing " AND " from your [One_or_Two_Pearl] line, but there is none.

How can I determine the difference between typing into a combo box and selecting from a drop down in Access VBA?

This question was asked in the topic with a similar name earlier, but the answer provided didn't really indicate HOW those events would help determine whether somebody was typing in the combo box or selecting an item in the list. I think that it really answered the other question about how to determine when somebody was done typing, but without seeing the event handlers, I can't be sure.
Unfortunately, I'm new here and don't have enough reputation to post a comment asking for clarification, so I have to start a new question. Here's what I'm trying to do:
I have a form with a combo box in the Header and, as I type in the combo box, I want the characters that I've typed to be used as a filter on the Details part of the form. Both the combo box control source and the form's record source use the same query string.
I've tried numerous iterations of the code below, but I can't get it to work correctly.
Private Sub cmbAppName_Change()
Dim strApp As String
Dim nSelStart As Integer
Dim nSelLen As Integer
Dim nSelected As Integer
Dim strMsg As String
On Error GoTo ERR_SUB
strMsg = ""
Me.cmbAppName.SetFocus
' Get current selection details
nSelStart = Me.cmbAppName.SelStart
nSelLen = Me.cmbAppName.SelLength
nSelected = Me.cmbAppName.ListIndex
Me.cmbAppName.SetFocus
strApp = Nz(Me.cmbAppName.Text, "")
Debug.Print "Index = " & nSelected & "; SelStart = " & nSelStart & "; SelLen = " & nSelLen
If nSelected = -1 Then
Debug.Print "Change by typing: " & strApp
Else
Debug.Print "Change by list selection: " & strApp
End If
' Get the part of the text that the user has typed
If nSelStart > 0 Then
strApp = Left(strApp, nSelStart)
Debug.Print "App piece = '" & strApp & "'"
End If
' If there is text, set a filter (MatchAppName = InStr(strApp, datbase_column_value)
If strApp <> "" Then
Me.Filter = "MatchAppName('" & strApp & "', " & DCApplications_Application_Col & ") > 0"
Me.FilterOn = True
' Me.txtApplication.SetFocus
' Call DoCmd.FindRecord(strApp, acStart, False, acSearchAll, False, acCurrent, True)
' Me.cmbAppName.SetFocus
Else
Me.Filter = ""
Me.FilterOn = False
End If
EXIT_SUB:
' Restore the selection in the combo box's text box
Me.cmbAppName.SetFocus
Me.cmbAppName.SelStart = nSelStart
Me.cmbAppName.SelLength = nSelLen
Exit Sub
ERR_SUB:
If ERR.Number = 2185 Then
strApp = Nz(Me.cmbAppName.Value, "")
Me.cmbAppName.SetFocus
Debug.Print "Using " & strApp
Resume Next
End If
Me.Filter = ""
Me.FilterOn = False
Debug.Print ErrorMessage(ERR.Description, "cmbAppName_Change", ERR.Number, "Value = '" & Me.cmbAppName.Value & "'", False)
Resume EXIT_SUB
End Sub ' cmbAppName_Change
As you can see from the error handling code, I'd often get an error 2185 telling me that my control didn't have focus when using the Text property despite having a SetFocus call right before it.
If somebody selects from the list (either by clicking or moving the selection), I'd like to go to that record, but I at least need the above piece working first.
After searching the Web, I found out that a Details section with zero records causes the 2185 error. Apparently, filtering like that causes problems when all records are filtered out.
The solutions on the Web said that you can set the Allow Additions property of the form to True, but that always displays one row in the Details section. This can be especially confusing if the rows in the Details section contain controls, which will be displayed in the "addition" row. Also, I would still get an error typing additional characters after the one that caused the Details section to have zero records.
Eventually, I replaced the combo box with a simple text control to filter the Details section. When the Details section has rows, I turn Allow Additions off and make the controls visible; when it doesn't have rows, I turn Allow Additions on and hide the controls.
Here's the code that I used:
Private Sub txtApplicationFilter_Change()
Dim strApp As String
Dim nSelStart As Integer
Dim nSelLen As Integer
Dim strFilter As String
Dim strQuery As String
Dim strWhere As String
Dim nRecs As Integer
On Error GoTo ERR_SUB
' Save text selection
nSelStart = Me.txtApplicationFilter.SelStart
nSelLen = Me.txtApplicationFilter.SelLength
' Get application name typed and selection information
strApp = Nz(Me.txtApplicationFilter.Text, "")
strFilter = "[" & DCApplications_Application_Col & "] LIKE '*" & EscapeQuotes(strApp) & "*'"
nRecs = DCount("[" & DCApplications_Application_Col & "]", LocalTableName(DCApplications_Tab), strFilter)
' Kludge code to prevent various errors (like 2185) when no records are returned in the form
Call UpdateList(nRecs)
' Update the record source to reflect the filtered list of apps
strWhere = " WHERE APPS." & strFilter
strQuery = strSelect & strFrom & strWhere & strOrderBy
Me.RecordSource = strQuery
' 20200423 SHM: Restore or update filter to avoid issues with Delete and Backspace and applications with spaces in their names
Me.txtApplicationFilter.SetFocus
Me.txtApplicationFilter = strApp
Me.txtApplicationFilter.SelStart = nSelStart
Me.txtApplicationFilter.SelLength = nSelLen
EXIT_SUB:
Me.btnAddNew.enabled = (Nz(Me.txtApplicationFilter, "") <> "")
Exit Sub
ERR_SUB:
' NOTE: ErrorMessage is a helper function that basically displays a form displaying the error
Call ErrorMessage(ERR.Description, "txtApplicationFilter_Change", ERR.Number, "Filter = " & strApp & " Records = " & nRecs)
Resume EXIT_SUB
Resume Next
End Sub ' txtApplicationFilter_Change
Private Sub UpdateList(nRecs As Integer)
Dim bShowControls As Boolean
On Error GoTo ERR_SUB
bShowControls = (nRecs > 0)
' Kludge code to turn off checkbox control source
If bShowControls Then
strSelect = strSelectStart & ", (" & strAppUser & ") AS " & strCtrlSource
Me.chkTestedByMe.ControlSource = strCtrlSource
Else
strSelect = strSelectStart
Me.chkTestedByMe.ControlSource = ""
End If
' Kludge code to prevent various errors (like 2185) when no records are returned in the form
' Turning on AllowAdditions prevents errors when no records are returned.
' However, that puts an empty row in the form, but the controls are showing, so we have to hide them to prevent confusing the user.
Me.AllowAdditions = Not bShowControls
Me.btnAddExisting.visible = bShowControls
Me.chkTestedByMe.visible = bShowControls
EXIT_SUB:
Exit Sub
ERR_SUB:
Call ErrorMessage(ERR.Description, "UpdateList", ERR.Number, " Records = " & nRecs)
Resume EXIT_SUB
Resume Next
End Sub ' UpdateList
I would use a work around to settle this issue
A simple code bellow demonstrate the work around using Tag property of Combo Box and keypress event along with change event, I hope it can be applied in your code
Private Sub Combo2_Change()
If Combo2.Tag = 1 Then
Text4 = "change - from key"
Else
Text4 = "change - from select"
End If
Combo2.Tag = 0
End Sub
Private Sub Combo2_KeyPress(KeyAscii As Integer)
Combo2.Tag = 1
End Sub
Don't forget to set Tag property of Combo Box to 0 on design view to avoid error at comparing empty Tag with number

Access 2007 VBA Error 2467 for function

Having a very weird problem. I have a function which is called when a form field gets focus. The function is passed four arguments, three of which are values from form fields and the fourth is a global variable which is set when the form loads. The function uses these variables to calculate the value for the field which called the function. This function is called in two different places. Everything was working fine, and now suddenly the function works when called from one place and doesn't work from the other, generating a 2467 run-time error, 'The expression you entered refers to an object that is closed or doesn't exists'. I've checked that the values of the arguments being passed are correct, the function exists OK, so can't see why I'm getting this error. Anyone any ideas?
Private Sub cboFinalStage_GotFocus()
'lookup stage based on TNM values
cboFinalStage = FindStage(cboFinalStageT, cboFinalStageN, cboFinalStageM, gblCancer)
End Sub
Public Function FindStage(cboT As ComboBox, cboN As ComboBox, cboM As ComboBox,
strCancer As String) As String
'use the TNM values entered to find the correct stage for the site and return it
'error handling
If gcfHandleErrors Then On Error GoTo PROC_ERR
'declare variables
Dim strTemp As String
Dim strTable As String
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strQuery As String
Dim strSite As String
Dim strSiteFull As String
Dim strT As String
Dim strN As String
Dim strM As String
'initialise variables - if there are no values entered in the 3 comboboxes, exit
'load tumour first in case it isn't already loaded
Forms!frmContainer.subTumour.SourceObject = "fsubTumour"
If Not IsNull(Forms!frmContainer.subTumour.Form!txtICD10) Then
strSite = Left(Forms!frmContainer.subTumour.Form!txtICD10, 3)
strSiteFull = Forms!frmContainer.subTumour.Form!txtICD10
End If
If Not IsNull(cboT.Value) Then
strT = cboT.Value
Debug.Print "T is " & strT
End If
If Not IsNull(cboN.Value) Then
strN = cboN.Value
Debug.Print "N is " & strN
End If
If Not IsNull(cboM.Value) Then
strM = cboM.Value
Debug.Print "M is " & strM
End If
If (IsNull(strT) Or IsNull(strN) Or IsNull(strM)) Then
Debug.Print "null so exiting"
Exit Function
End If
'identify the correct AJCC lookup table by cancer site
Select Case [strCancer]
Case "bla"
strTable = "lkp_AJCC_bladder"
Case "bre"
strTable = "lkp_AJCC_breast"
...
End Select
Debug.Print "AJCC table is " & strTable
'query the AJCC lookup table for the stage
strQuery = "SELECT c_stage FROM " & strTable & " WHERE (((t_value)='" & strT & "')
AND ((n_value)='" & strN & "') AND ((m_value)='" & strM & "'))"
Debug.Print "query is " & strQuery
Set db = CurrentDb
Set rs = db.OpenRecordset(strQuery)
If Not rs.EOF Then
strTemp = rs.Fields(0).Value
Debug.Print "result is " & strTemp
End If
rs.Close
db.Close
'return stage
FindStage = strTemp
'error handling
PROC_EXIT:
Exit Function
PROC_ERR:
If (Err.Number = 2467) Then
MsgBox "Unable to evaluate the stage", vbOKOnly, "Processing error"
Resume PROC_EXIT
Else
MsgBox "Error: (" & Err.Number & ") " & Err.Description, vbCritical
Resume PROC_EXIT
End If
End Function