1

I have a requirement to allow a user to search between two dates on a form and filter the data down further using multiple list boxes

Currently I allow the user to search between a from and to date... And also filter by products from a listbox.

If no products are selected in the list box, only display the results of the query between the two dates.

If the selection critera of the listbox is not empty, build the query WHERE with IN clause and then concanenate it to the SELECT statement, then execute the query to give desired results.

My question is... How would I do this for another four or five multi value list boxes? For example: Suppliers, Depots, Countries, Varieties etc etc

SearchAllReject is simply a function to query from and to date with no product filters.

Here is the code I already have:

Dim SQLAllReject As String

Dim strDateFrom As String
Dim strDateTo As String
Dim strFirstDate As Date
Dim strSecondDate As Date
Dim strINPRODUCT As String
Dim strWHERE As String
Dim strSTRING As String
Dim i As Integer

If Len(Me.txtDate.Value & vbNullString) = 0 Then
    MsgBox ("Please input date from")
    Exit Sub
ElseIf Len(Me.txtDateTo.Value & vbNullString) = 0 Then
    MsgBox ("Please input date to")
    Exit Sub
End If

strDateFrom = txtDate.Value
strDateTo = txtDateTo.Value

strFirstDate = Format(CDate(strDateFrom), "mm/dd/yyyy")
strSecondDate = Format(CDate(strDateTo), "mm/dd/yyyy")

For i = 0 To lstProduct.ListCount - 1
    If lstProduct.Selected(i) Then
        strINPRODUCT = strINPRODUCT & "'" & lstProduct.Column(1, i) & "',"
    End If
Next i

If Len(strINPRODUCT & vbNullString) = 0 Then

    SearchAllReject
    
Else
    
    strWHEREPRODUCT = "AND dbo_busobj_file_rejections_load_temp5.Tesco_Product_Name IN " & _
        "(" & Left(strINPRODUCT, Len(strINPRODUCT) - 1) & "))"
    
    SQLAllReject = "SELECT dbo_busobj_file_rejections_load_temp5.Reject_Date AS [Date], " & _
                    "dbo_busobj_file_rejections_load_temp5.Depot_Number AS [Depot No], " & _
                    "dbo_busobj_file_rejections_load_temp5.Depot_Name AS [Depot], dbo_busobj_file_rejections_load_temp5.Tesco_Product_Name AS [Product]," & _
                    "dbo_busobj_file_rejections_load_temp5.Tesco_Brand_Name AS [Brand], dbo_busobj_file_rejections_load_temp5.Tesco_Packsize AS [Packsize], " & _
                    "dbo_busobj_file_rejections_load_temp5.TPNB, dbo_busobj_file_rejections_load_temp5.EAN, " & _
                    "dbo_busobj_file_rejections_load_temp5.Tesco_Country_of_Origin AS [Country], " & _
                    "dbo_busobj_file_rejections_load_temp5.Tesco_Variety AS [Variety], dbo_busobj_file_rejections_load_temp5.Tesco_Producer AS [Producer], " & _
                    "dbo_busobj_file_rejections_load_temp5.reject_qty AS [Quantity], dbo_busobj_file_rejections_load_temp5.batch_code AS [Batch Code], " & _
                    "dbo_busobj_file_rejections_load_temp5.site AS [Site], dbo_busobj_file_rejections_load_temp5.Tesco_Comment AS [Comment], " & _
                    "dbo_busobj_file_rejections_load_temp5.Tesco_Reason AS [Reason] " & _
                    "FROM dbo_busobj_file_rejections_load_temp5 " & _
                    "WHERE (((dbo_busobj_file_rejections_load_temp5.Reject_Date) Between #" & strFirstDate & "# And #" & strSecondDate & "#) "
    
    strSTRING = SQLAllReject & strWHEREPRODUCT

    Debug.Print strSTRING

    Me.lstDeleteReject.RowSource = strSTRING
    Me.lstDeleteReject.Requery
3
  • Here is the code I already have ... what is the issue with your code? It works but for only one multi-value listbox? Why not extend it for the other multi-value listboxes (i.e., concatenate to strWHEREPRODUCT)? Commented Feb 16, 2022 at 20:50
  • I dont understand. Do you mean to just loop other listboxes to build the IN clause how ever many times I need to and concat the existing strWHEREPRODUCT? Commented Feb 16, 2022 at 22:28
  • Yes, conditionally build WHERE clause. Can have has many IN() criteria as you want. Here is example of conditionally building WHERE clause allenbrowne.com/ser-62code.html Commented Feb 17, 2022 at 0:49

1 Answer 1

1

Consider building an entity-attribute table of all possible listbox values and use a saved SQL query which avoids any messy concatenation of SQL in VBA. A parameterized query using QueryDef is used to update the selected options of table of all list box values.

Table (myListBoxValues) (built once and updated with new values/categories)

Category|Value     |Selected
--------|----------|--------
Product |Product A |       1
Product |Product B |       1
Product |Product C |       1
...
Country |USA       |       1
Country |Canada    |       1 
Country |Japan     |       1

Above can be populated with multiple append queries using SELECT DISTINCT:

INSERT INTO myListBoxValues ([Category], [Value], [Selected])
SELECT DISTINCT 'Product', Tesco_Product_Name, 1
FROM dbo_busobj_file_rejections_load_temp5 b

NOTE: It is very important to default all Selected to 1 for VBA purposes. See further below. Also, if you have a mix of number and string, consider using TextValue and NumberValue columns and adjust in SQL IN clauses. Save above query as a new object and place the named object behind target: lstDeleteReject.


SQL (built once, adjust form name)

Notice the form date values are directly incorporated into WHERE clause without any date formatting conversion or concatenation needs. Also, table alias is used to avoid long name repetition.

SELECT b.Reject_Date AS [Date],
       b.Depot_Number AS [Depot No], 
       b.Depot_Name AS [Depot], b.Tesco_Product_Name AS [Product],
       b.Tesco_Brand_Name AS [Brand], b.Tesco_Packsize AS [Packsize], 
       b.TPNB, b.EAN, 
       b.Tesco_Country_of_Origin AS [Country], 
       b.Tesco_Variety AS [Variety], b.Tesco_Producer AS [Producer], 
       b.reject_qty AS [Quantity], b.batch_code AS [Batch Code], 
       b.site AS [Site], b.Tesco_Comment AS [Comment], 
       b.Tesco_Reason AS [Reason] 
FROM dbo_busobj_file_rejections_load_temp5 AS b
WHERE b.Reject_Date BETWEEN Forms!myFormName!txtDate 
                        AND Forms!myFormName!txtDateTo
  AND b.Tesco_Product_Name IN (
      SELECT [Value] FROM myListBoxValues 
      WHERE [Category] = 'Product' AND [Selected] = 1
  )
  AND b.site IN (
      SELECT [Value] FROM myListBoxValues 
      WHERE [Category] = 'Site' AND [Selected] = 1
  )
  AND b.Tesco_Producer IN (
      SELECT [Value] FROM myListBoxValues 
      WHERE [Category] = 'Producer' AND [Selected] = 1
  )
  AND b.Depot_Name IN (
      SELECT [Value] FROM myListBoxValues 
      WHERE [Category] = 'Depot' AND [Selected] = 1
  )
  AND b.Tesco_Country_of_Origin IN (
      SELECT [Value] FROM myListBoxValues 
      WHERE [Category] = 'Country' AND [Selected] = 1
  )

VBA (adjust list box names to actuals)

Dim qdef As QueryDef
Dim lstname As Variant
Dim sql As String
Dim i As Integer

sql = "PARAMETERS paramValue TEXT, paramCateg INTEGER; " _
      & "UPDATE myListBoxes SET [Selected] = 0 " _
      & "WHERE [Value] = paramValue AND [Category] = paramCateg"

Set qdef = CurrentDb.CreateQueryDef("", sql)

' ITERATE THROUGH ALL LISTBOXES BY NAME
For Each lstname in Array("lstProduct", "lstSite", "lstProducer", "lstDepot", "lstCountry")
    For i = 0 To Me.Controls(lstname).ListCount - 1  
      ' UPDATE IF AT LEAST ONE ITEM IS SELECTED
      If Me.Controls(lstname).ItemsSelected.Count > 0
        ' UPDATE [SELECTED] COLUMN TO ZERO IF VALUES ARE NOT SELECTED       
        If Me.Controls(lstname).Selected(i) = False Then
            qdef!paramValue = Me.Controls(lstname).Value
            qdef!paramCategory = Replace(lstName, "lst", "")
            qdef.Execute
        End If
      End If
    Next i
Next lstname

Set qdef = Nothing

' REQUERY LISTBOX
Me.lstDeleteReject.Requery

' RESET ALL SELECTED BACK TO 1
CurrentDb.Execute "UPDATE myListBoxValues SET [Selected] = 1"

As you can see, much better readability and maintainability. Also, if users do not select any option, the date range filters are still applied and using your universal table of all list box values, all values will be selected to returns all non-NULL values.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.