Home > Software engineering >  Sort ADO Recordset Fields based on Custom Order
Sort ADO Recordset Fields based on Custom Order

Time:11-25

I have created an ADO Recordset from a Range of a Worksheet as shown below that I want to custom sort on Groups field, Then Type field. The Sort Order should be such that, the values of Groups column should be arranged in a custom order as given in another worksheet range column Status1 AND the values of Type column should be arranged in a custom order as given in another worksheet range column Status2 for e.g. :

 ==== =========== ================ 
|    |     A     |       B        |
 ==== =========== ================ 
| 1  | Type      | Groups         |
 ---- ----------- ---------------- 
| 2  | Restage 2 | Target Group 6 |
 ---- ----------- ---------------- 
| 3  | Restage 3 | Target Group 6 |
 ---- ----------- ---------------- 
| 4  | Restage 1 | Target Group 6 |
 ---- ----------- ---------------- 
| 5  | Current   | Target Group 6 |
 ---- ----------- ---------------- 
| 6  | Restage 1 | Target Group 4 |
 ---- ----------- ---------------- 
| 7  | Current   | Target Group 4 |
 ---- ----------- ---------------- 
| 8  | Restage 2 | Target Group 4 |
 ---- ----------- ---------------- 
| 9  | Restage 3 | Target Group 4 |
 ---- ----------- ---------------- 
| 10 | Restage 3 | Target Group 2 |
 ---- ----------- ---------------- 
| 11 | Restage 1 | Target Group 2 |
 ---- ----------- ---------------- 
| 12 | Restage 2 | Target Group 2 |
 ---- ----------- ---------------- 
| 13 | Current   | Target Group 2 |
 ---- ----------- ---------------- 
| 14 | Current   | Non Buyers     |
 ---- ----------- ---------------- 
| 15 | Restage 1 | Non Buyers     |
 ---- ----------- ---------------- 
| 16 | Restage 3 | Non Buyers     |
 ---- ----------- ---------------- 
| 17 | Restage 2 | Non Buyers     |
 ---- ----------- ---------------- 
| 18 | Current   | GP             |
 ---- ----------- ---------------- 
| 19 | Restage 3 | GP             |
 ---- ----------- ---------------- 
| 20 | Restage 2 | GP             |
 ---- ----------- ---------------- 
| 21 | Restage 1 | GP             |
 ---- ----------- ---------------- 
| 22 | Restage 2 | Buyers         |
 ---- ----------- ---------------- 
| 23 | Restage 1 | Buyers         |
 ---- ----------- ---------------- 
| 24 | Current   | Buyers         |
 ---- ----------- ---------------- 
| 25 | Restage 3 | Buyers         |
 ==== =========== ================ 

to like this:

 ==== =========== ================ 
|    |     A     |       B        |
 ==== =========== ================ 
| 1  | Type      | Groups         |
 ---- ----------- ---------------- 
| 2  | Current   | GP             |
 ---- ----------- ---------------- 
| 3  | Restage 1 | GP             |
 ---- ----------- ---------------- 
| 4  | Restage 2 | GP             |
 ---- ----------- ---------------- 
| 5  | Restage 3 | GP             |
 ---- ----------- ---------------- 
| 6  | Current   | Buyers         |
 ---- ----------- ---------------- 
| 7  | Restage 1 | Buyers         |
 ---- ----------- ---------------- 
| 8  | Restage 2 | Buyers         |
 ---- ----------- ---------------- 
| 9  | Restage 3 | Buyers         |
 ---- ----------- ---------------- 
| 10 | Current   | Non Buyers     |
 ---- ----------- ---------------- 
| 11 | Restage 1 | Non Buyers     |
 ---- ----------- ---------------- 
| 12 | Restage 2 | Non Buyers     |
 ---- ----------- ---------------- 
| 13 | Restage 3 | Non Buyers     |
 ---- ----------- ---------------- 
| 14 | Current   | Target Group 2 |
 ---- ----------- ---------------- 
| 15 | Restage 1 | Target Group 2 |
 ---- ----------- ---------------- 
| 16 | Restage 2 | Target Group 2 |
 ---- ----------- ---------------- 
| 17 | Restage 3 | Target Group 2 |
 ---- ----------- ---------------- 
| 18 | Current   | Target Group 4 |
 ---- ----------- ---------------- 
| 19 | Restage 1 | Target Group 4 |
 ---- ----------- ---------------- 
| 20 | Restage 2 | Target Group 4 |
 ---- ----------- ---------------- 
| 21 | Restage 3 | Target Group 4 |
 ---- ----------- ---------------- 
| 22 | Current   | Target Group 6 |
 ---- ----------- ---------------- 
| 23 | Restage 1 | Target Group 6 |
 ---- ----------- ---------------- 
| 24 | Restage 2 | Target Group 6 |
 ---- ----------- ---------------- 
| 25 | Restage 3 | Target Group 6 |
 ==== =========== ================ 

The Custom order of the both columns are to be picked up from 2 single-column Excel ranges (can be converted to Arrays) as shown below:

Status1:

 === ================ 
|   |       A        |
 === ================ 
| 1 | GP             |
 --- ---------------- 
| 2 | Buyers         |
 --- ---------------- 
| 3 | Non Buyers     |
 --- ---------------- 
| 4 | Target Group 1 |
 --- ---------------- 
| 5 | Target Group 2 |
 --- ---------------- 
| 6 | Target Group 3 |
 --- ---------------- 
| 7 | Target Group 4 |
 --- ---------------- 
| 8 | Target Group 5 |
 --- ---------------- 
| 9 | Target Group 6 |
 === ================ 

and :

Status2:

 ==== ============ 
|    |     A      |
 ==== ============ 
| 1  | Current    |
 ---- ------------ 
| 2  | Restage 1  |
 ---- ------------ 
| 3  | Restage 2  |
 ---- ------------ 
| 4  | Restage 3  |
 ---- ------------ 
| 5  | Restage 4  |
 ---- ------------ 
| 6  | Restage 5  |
 ---- ------------ 
| 7  | Restage 6  |
 ---- ------------ 
| 8  | Restage 7  |
 ---- ------------ 
| 9  | Restage 8  |
 ---- ------------ 
| 10 | Restage 9  |
 ---- ------------ 
| 11 | Restage 10 |
 ==== ============ 

For example, :

Set oRS = CreateObject("ADODB.Recordset")
....
With oRS
  .Sort = "Groups <customorder>,Types <customorder>"
End With

Does anyone knows how to do a Custom Order sort using a Recordset object?

EDIT:

@CDP1802 thanks for your reply! It works, but i overlooked something that i have to edit my post. Hope you can figure out how to handle it.

Initially the A.[Groups] column in the Base table is blank and I am updating it in the recordset based on values from another column [segment]. So the sorting is coming all wrong!

Here is a main snapshot of the code for your inspection:

' Grab `Groups` Filters from Study Details
With shtStudyDetails
  xLastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
  If xLastRow <= 18 Then Exit Sub
  
  ' first check if `Assign` column has been filled in too
  Set xRg = .Range(.Cells(19, "B"), .Cells(xLastRow, "B"))
  If WorksheetFunction.CountA(xRg.Offset(0, 1).Cells) < WorksheetFunction.CountA(xRg.Cells) Then Exit Sub
  
  Set sRg = xRg.Resize(xRg.Rows.Count, 2)
  vArr = sRg.Value2
  
  ' Get Segment values excluding `Assign : Not Assigned`
  xStr = ""
  For j = 1 To UBound(vArr)
    If Not InStr(1, vArr(j, 2), "Not Assigned", vbTextCompare) > 0 Then xStr = xStr & "_" & j
  Next j
  If xStr = "" Then
    vIncludeArr = vArr
  Else
    vIncludeArr = Application.Index(vArr, Application.Transpose(Split(Mid(xStr, 2), "_")), Application.Transpose([row(1:2)]))
  End If
  If UBound(vIncludeArr) <= 1 And vIncludeArr(UBound(vIncludeArr), 1) = vbEmpty Then Exit Sub
    
  
  Set KeyValues1 = shtStudyDetails.Cells.Range("E45:F55") ' range1 table on whose values order to sort Groups
  Set KeyValues2 = shtStudyDetails.Cells.Range("G45:H106") ' range2 table on whose values order to sort Type

End With



With shtSummaryOfData
    xLastColumn = .Range("1:1").Cells(.Columns.Count).End(xlToLeft).Column
    If xLastColumn = 1 Then Exit Sub

    Set xRng = .Range(.Cells(1, 1), .Cells(1, xLastColumn))
    
    ' clear Summary of data sheet
    xLastRow = .Cells.SpecialCells(xlCellTypeLastCell).Row
    If xLastRow < 2 Then Exit Sub
    
    .Range(.Cells(2, 1), .Cells(xLastRow, xLastColumn)).ClearContents

    strSQL = ""
    xStr = ""
    strSQL = "SELECT "
    
    For Each xCell In xRng
      With xCell
          xStr = xCell.Value2
          If InStr(1, xStr, " ", vbTextCompare) > 0 Then xStr = WorksheetFunction.Substitute(xStr, " ", " ")
          If InStr(1, xStr, ".", vbTextCompare) > 0 Then xStr = WorksheetFunction.Substitute(xStr, ".", "#")
      End With
      strSQL = strSQL & "A.[" & xStr & "],"
      
    Next xCell

    strSQL = Left(strSQL, Len(strSQL) - 1)
    strSQL = strSQL & " FROM (([" & shtPasteData.Name & "$" & xRg.Address(False, False, xlA1) & "] AS A "
    
    strSQL = strSQL & " LEFT JOIN [" & shtStudyDetails.Name & "$" & KeyValues1.Address(False, False, xlA1) & "] AS G ON G.[Groups] = A.[Groups])"
    strSQL = strSQL & " LEFT JOIN [" & shtStudyDetails.Name & "$" & KeyValues2.Address(False, False, xlA1) & "] AS T ON T.[Type] = A.[Type])"
    
    ' Join Segments in `vIncludeArr` that did not have Assign:Not Assigned
    With Application
      xStr = "'" & Join(.Transpose(.Index(vIncludeArr, 0, 1)), "','") & "'"
    End With
    strSQL = strSQL & " WHERE A.[segment] IN (" & xStr & ")"
    
    strSQL = strSQL & " ORDER BY G.ITEM, T.ITEM "

End With


Set oCon = CreateObject("ADODB.Connection")
Set oRec = CreateObject("ADODB.Recordset")

With oCon
    .Mode = adModeReadWrite
    .CursorLocation = adUseClient
    .Open Join$(Array("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & _
    sPath$ & ";Extended Properties=""Excel 12.0 Xml; HDR=YES;IMEX=0"";"), vbNullString)
End With

With oRec
    .CursorLocation = adUseClient
    .CursorType = adOpenDynamic
    .LockType = adLockOptimistic
    Set .ActiveConnection = oCon
    .Open (strSQL)
    
    Set .ActiveConnection = Nothing
    
    ' updating Groups column based on values in `vIncludeArr`
    Do While Not .EOF
        For j = 1 To UBound(vIncludeArr, 1)
          If .Fields("segment").Value = vIncludeArr(j, 1) Then .Fields("Groups").Value = vIncludeArr(j, 2)
        Next j
      .MoveNext
    Loop
  
  .MoveLast
  .MoveFirst
'  .Sort = .Fields("Groups").Name & " ASC," & .Fields("Type").Name & " ASC"
  
  .MoveLast
  .MoveFirst
  shtSummaryOfData.Range("A2").CopyFromRecordset .DataSource
  .Close
End With

And here is the Unique Segments Table which is used to populate the Blank Groups column with the Assigned Groups based on the unique Segment names:

╔══════════════════════╤════════════════╗
║ Segments             │ Assign Groups  ║
╠══════════════════════╪════════════════╣
║ ALL RESPONSES        │ GP             ║
╟──────────────────────┼────────────────╢
║ Some xx Target Group │ Target Group 1 ║
╟──────────────────────┼────────────────╢
║ Some Buyer1          │ Buyers         ║
╟──────────────────────┼────────────────╢
║ Some Non-Buyer1      │ Target Group 2 ║
╟──────────────────────┼────────────────╢
║ Some yy Target Group │ Target Group 3 ║
╟──────────────────────┼────────────────╢
║ Some zz Target Group │ Target Group 5 ║
╚══════════════════════╧════════════════╝

CodePudding user response:

Add an Item column to the 2 custom order tables then join them to the data table and use the Item fields in the sort orders.

Sheet2 Sheet3

Option Explicit

Sub test()

   Dim con As ADODB.Connection, sCon As String
   sCon = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
           "Data Source=" & ThisWorkbook.FullName & ";" & _
           "Extended Properties='Excel 12.0 Macro;HDR=YES';"

   Set con = New ADODB.Connection
   With con
      .ConnectionString = sCon
      .Open
   End With
   
   Const SQL = " SELECT A.Type, A.Groups FROM (([Sheet1$] AS A" & _
               " LEFT JOIN [Sheet2$] AS T ON T.Type   = A.Type)" & _
               " LEFT JOIN [Sheet3$] AS G ON G.Groups = A.Groups)" & _
               " ORDER BY G.Item, T.Item"
               
   With Sheet4
       .Cells.Clear
       .Range("A1").CopyFromRecordset con.Execute(SQL)
   End With
   
End Sub
  • Related