Reputation: 143
I have a (poorly designed) db that contains a table of Volunteers. Within this table are 70+ Yes/No fields. Each field represents a County that each Volunteer could elect to serve. Each Volunteer could select multiple Counties.
I have a report that must allow selection of multiple Counties. That list must then be compared to the Boolean fields selection by selection, retaining records with only True values.
If you check some of my recent questions, I've had similar problems, but the difference was displaying boolean selections as text on the report. Only just now discovered selection criteria code isn't doing what I thought ... Here's what's been done so far:
Dim s As Variant
Dim ctl As Control
Dim t As TCondition 'this is to compile multiple variables into one large "where" clause to run the report. 3 such variables are coded in this function.
Set ctl = Me.Counties
If ctl.ItemsSelected.Count <> 0 Then
If t.WhereCondition = "" Then
For Each s In ctl.ItemsSelected
t.WhereCondition = (ctl.ItemData(s) & " = -1")
Next s
Else
For Each s In ctl.ItemsSelected
t.WhereCondition = t.WhereCondition & " AND (ctl.ItemData(s) = -1)"
Next s
End If
End If
Where this broke on me was if someone selected more than one County. I realized they were only getting the last County selected.
For Example - Counties: red, blue, silver, and green would only return Green.
A similar issue had come up with Volunteer Positions. I needed to account for selecting multiple
So I found the following:
Public Function listBoxToString(ByRef theListBox As ListBox, Optional ByVal theDelimiter As String = vbNullString)
Dim varTemp As Variant
listBoxToString = vbNullString
For Each varTemp In theListBox.ItemsSelected
If listBoxToString <> vbNullString Then listBoxToString = listBoxToString & ","
listBoxToString = listBoxToString & theDelimiter & theListBox.ItemData(varTemp) & theDelimiter
Next varTemp
End Function
This takes all selections of a ListBox and makes a comma separated list of them. This WORKED for the Positions fields (there are multiple) because those field values are TEXT.
I tried to apply that to Counties as follows:
Dim s As String
Dim ctl As Control
Dim t As TCondition
Set ctl = Me.Counties
If ctl.ItemsSelected.Count <> 0 Then
s = listBoxToString(Me.Counties, Chr(34))
If t.WhereCondition = "" Then
t.WhereCondition = (ctl.ItemData(s) & " = -1")
Else
t.WhereCondition = t.WhereCondition & " AND (ctl.ItemData(s) = -1)"
End If
End If
It does NOT work for Counties, because ListBox returns TEXT that must then be compared to values in County that are BOOLEAN. So, logically, I get Data Type Mismatch error.
I have a separate piece of code, used to help display the Counties list on the report. It pulls records at runtime, takes the ID of the record, zeroes in on the Indexes of the Boolean fields, and converts them to the Name of the fields:
Public Function MakeListCounties(intID As Integer) As String
Dim rs As DAO.Recordset
Dim strList As String
Dim x As Integer
Set rs = CurrentDb.OpenRecordset("SELECT * FROM Volunteer WHERE ID=" & intID)
For x = 44 To 105
If rs(x).Type = dbBoolean Then
If rs(x) = True Then strList = strList & rs(x).Name & ", "
End If
Next
If strList <> "" Then MakeListCounties = Left(strList, (Len(strList) - 2))
rs.Close
Set rs = Nothing
End Function
Is there a way to work with this to get what I want? This may be superfluous, and, if so, apologies, and completely ignore that part.
To recap - I need to iterate through a ListBox of values, compare them with values of 70+ Boolean fields, retaining only records where Boolean = True for field names matching value(s) in the ListBox
Upvotes: 0
Views: 107
Reputation: 521
Change your first code snippet to the following. The reason you were always getting the last county is because your loop was overwriting the previous WHERE clause values.
Dim s As Variant
Dim ctl As Control
Dim t As TCondition
Set ctl = Me.Counties
If ctl.ItemsSelected.Count <> 0 Then
For Each s In ctl.ItemsSelected
t.WhereCondition = t.whereCondition & ctl.ItemData(s) & " = -1 OR"
Next s
' trim trailing " OR"
t.WhereCondition = Left(t.WhereCondition, Len(t.WhereCondition)-3)
End If
Upvotes: 1
Reputation: 21370
Build function in a general module that returns a True or False. Call from query with expression like: MC: MatchCounties([ID])
with filter criteria of =True
.
Assuming the combobox lists county names exactly matching the yes/no field names, consider:
Function MatchCounties(intID As Integer) As Boolean
Dim rs As DAO.Recordset
Dim varItem As Variant
With Forms!formname.Counties
If .ItemsSelected.Count <> 0 Then
Set rs = CurrentDb.OpenRecordset("SELECT * FROM Volunteer WHERE ID=" & intID)
For Each varItem In .ItemsSelected
If rs(.ItemData(varItem)) Then 'use the listbox value as field name and test for True
MatchCounties = True
Exit For 'only need to match 1 yes/no county field to retrieve record
End If
Next
rs.Close
Set rs = Nothing
End If
End With
End Function
If no items selected in listbox, no records will return because the function will return False. If you want to allow no selection and still return records, then likely want the function to return True if .ItemsSelected.Count = 0. Adjust code with an Else.
Upvotes: 2