根据自定义顺序对 ADO 记录集字段进行排序

Sort ADO Recordset Fields based on Custom Order

我已经从工作表的范围创建了一个 ADO 记录集,如下所示,我想自定义排序 Groups 字段,然后是 Type 字段。排序顺序应该是 Groups 列的值应按照另一个工作表范围列 Status1 中给出的自定义顺序排列,并且 Type 列的值应排列在另一个工作表范围列 Status2 中给出的自定义顺序,例如:

+====+===========+================+
|    |     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         |
+====+===========+================+

喜欢这个:

+====+===========+================+
|    |     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 |
+====+===========+================+

两列的自定义顺序将从 2 个单列 Excel 范围中选取(可以是 转换为数组)如下图:

状态 1:

+===+================+
|   |       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 |
+===+================+

和:

状态 2:

+====+============+
|    |     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 |
+====+============+

例如:

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

有谁知道如何使用 Recordset 对象进行自定义顺序排序?

编辑:

@CDP1802 感谢您的回复!它有效,但我忽略了一些我必须编辑我的 post 的东西。希望你能想出如何处理它。

最初,Base table 中的 A.[Groups] 列是空白的,我正在根据另一列 [segment] 的值在记录集中更新它。所以排序全错了!

这是供您检查的代码的主要快照:

' 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

这里是唯一细分 Table,用于根据唯一细分名称使用分配的组填充空白 Groups 列:

╔══════════════════════╤════════════════╗
║ 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 ║
╚══════════════════════╧════════════════╝

向 2 个自定义顺序 table 添加项目列,然后将它们加入数据 table 并在排序顺序中使用项目字段。

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