0

EDIT: Query is called from vba, used to create array, passed to create form:

QueryFieldAsSeparatedString("Batch", "TLR", "Batch")  
strBndls = Replace(strBndls, ",", ";")
subNewControls strBndls, "frmSelectBundle"

The reason I thought this quicksort would work is because batch #13 gets lumped in with the 1's using the sortby clause.

Example table:

  • Order # | Batch
  • 1 | 1
  • 1 | 13
  • 1 | 1b
  • 1 | 2
  • 1 | 2a
  • 1 | 1a
  • 1 | 3
  • 1 | 6
  • 1 | 7
  • 1 | 9
  • 1 | 11
  • 1 | 6a
  • 1 | 7b
  • 1 | 8
  • 1 | 13a
  • 1 | 7a

desired string returned: 1, 1a, 1b, 2, 2a, 3, 6, 6a, 7, 7a, 7b, 8, 9, 11, 13, 13a

Current Output Side Note: there are duplicates in this table that have different information separating them (shipment_box# and product_size). I'm hoping to group them since the operator would be entering data against the whole batch on the same order and child batch (batches with a letter), regardless of other data

Original Post:

I am attempting to sort a column in an access table. I found this code from VBA array sort function? and am attempting to make it work. I would have commented on the post but am unable to comment since I am new to the forum.

Specifically I am looking at this bit of code:

Public Sub QuickSort(ByRef Field() As String, ByVal LB As Long, ByVal UB As Long)
Dim P1 As Long, P2 As Long, Ref As String, TEMP As String

P1 = LB
P2 = UB
Ref = Field((P1 + P2) / 2)

Do
    Do While (Field(P1) < Ref)
        P1 = P1 + 1
    Loop

    Do While (Field(P2) > Ref)
        P2 = P2 - 1
    Loop

    If P1 <= P2 Then
        TEMP = Field(P1)
        Field(P1) = Field(P2)
        Field(P2) = TEMP

        P1 = P1 + 1
        P2 = P2 - 1
    End If
Loop Until (P1 > P2)

If LB < P2 Then Call QuickSort(Field, LB, P2)
If P1 < UB Then Call QuickSort(Field, P1, UB)
End Sub

I use this block of code to create a delimited string of all records in a 'Product Batch' field.

Public Function QueryFieldAsSeparatedString(ByVal fieldName As String, _
                                        ByVal tableOrQueryName As String, _
                                        Optional ByVal criteria As String = "", _
                                        Optional ByVal sortBy As String = "", _
                                        Optional ByVal delimiter As String = ", " _
                                    ) As String

' Paramter description
'   fieldName           =   Is the name of the field containing the values
'                           we want in our comma separated string
'   tableOrQueryName    =   Is the name of table or query containing the column
'   criteria            =   The criteria to filter the data
'   sortBy              =   An optional sort expression to sort the data
'   delimiter           =   The delimiter used to separate the values. It defaults
'                           to a comma and a blank, but you can use anything you
'                           like there 


Dim db              As DAO.Database
Dim rs              As DAO.Recordset
Dim sql             As String
Dim whereCondition  As String
Dim sortExpression  As String
Dim retVal          As String

Set db = CurrentDb

' If there where any criteria passed to the function, we build a WHERE-condition for SQL
If Len(criteria) > 0 Then
    whereCondition = " WHERE " & criteria
End If

' If there was a sort expression passed to the function, we build a ORDER BY for SQL
If Len(sortBy) > 0 Then
    sortExpression = " ORDER BY " & sortBy
End If
    
' building the complete SQL string
sql = "SELECT " & fieldName & " FROM " & tableOrQueryName & whereCondition & sortExpression & 
";"

' opening a recordset
Set rs = db.OpenRecordset(sql, dbOpenForwardOnly, dbReadOnly)
Do Until rs.EOF
    ' here we are looping through the records and, if the value is not NULL,
    ' concatenate the field value of each record with the delimiter
    If Not IsNull(rs.Fields(0).Value) Then
        retVal = retVal & Nz(rs.Fields(0).Value, "") & delimiter
    End If
    rs.MoveNext
Loop

' we cut away the last delimiter
retVal = Left(retVal, Len(retVal) - Len(delimiter))

' setting the return value of the function
QueryFieldAsSeparatedString = retVal

' cleaning up our objects
rs.Close
Set rs = Nothing
Set db = Nothing

End Function

This list is put into an array and used to dynamically create a batch number selection form, where each item in the list becomes a checkbox with the batch as a label. So an operator can choose which batch(es) have been worked on that day.

What my challenge/question is how would I go about sorting the batch string? The format is: 1, 1a, 2, 2a, 2b, ...

but comes in, in the order it is in the table. So it looks like 2a, 1, 2b, 1a, 1b, 2, ...

I'm going between the quicksort and figuring out a way to order/group the table before the string is even created, which may be in the second block of code; just not used properly.

The end goal would be to create another array consisting of the selected batches to continue data entry.

Any thoughts or questions are greatly appreciated!

SamwiseVB
  • 51
  • 8
  • 1
    When calling QueryFieldAsSeparatedString with a sortBy parameter does it not sort it in the correct order? why do you need a separate sort routine (like QuickSort), the database would do it all for you. – tinazmu Dec 29 '21 at 21:07
  • Where is code that calls QueryFieldAsSeparatedString? Expression in query or textbox? Show it. Provide sample data as text table. How high will numeric parts go? 13a will sort before 2a. Edit question. – June7 Dec 29 '21 at 21:18
  • I edited the post adding the information. Also, numbers would go as high as mid 30s and the letters would go as high as e. Thanks for the quick response!! – SamwiseVB Dec 29 '21 at 23:06
  • 1
    Well, this is alpha sort so either split the value into number and alpha parts and order on those parts or build value with place-holder 0: 002a will sort before 017a. – June7 Dec 29 '21 at 23:14
  • Is there a way to hide the leading 0? I would rather not have that seen if that's the only route... – SamwiseVB Dec 29 '21 at 23:34

1 Answers1

0

elaborating on the comments. First use regular expressions to split batch into batch# and batchletters. https://medium.com/factory-mind/regex-tutorial-a-simple-cheatsheet-by-examples-649dc1c3f285 https://software-solutions-online.com/vba-regex-guide/

Public Function RegexMatch(value As String, pattern As String) As String
'this code depends on adding a reference microsoft vbscript regular expressions 5.5 (in code window go tools-references)
Dim result As String
   If IsNull(value) Then Exit Function
   Dim regex As RegExp
 ' Initialise the Regex object '
   Set regex = New RegExp
        With regex
            .Global = True
            .IgnoreCase = False
            .MultiLine = True
            .pattern = pattern
        End With
 
  ' Test the value against the pattern '
  Set Matches = regex.Execute(value)
  If Matches.Count > 0 Then
  result = Matches.Item(0) 
  End If
  RegexMatch = result
End Function
Batch#: RegexMatch([Batch],"(\d+)")
BatchLetters: RegexMatch([Batch],"(\D+)")

Then create a query selecting everything and adding Batch# and BatchLetters. arrange variables in order you want to sort. I chose Shipment_Box, Product_Size, Batch#, BatchLetters

query

results

Thats it. I saw no need to concatenate batch into a string as you can set the rowsource of a combobox or listbox directly to the query.

mazoula
  • 1,221
  • 2
  • 11
  • 20