简体   繁体   English

使用VBA代码自定义排序

[英]Custom Sort using vba code

For the following piece of code, I am getting a Runtime error '13', Type Mismatch Error when it reaches the following piece of code 对于以下代码,我遇到运行时错误“ 13”,到达以下代码时,键入“ Mismatch Error”

ActiveWorkbook.Worksheets("3. PMO Internal View").Sort.SortFields.Add Key:= _
f, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal

That piece of code above is in the full code below, I have placed it in bold, it is towards the end of the code. 上面的代码在下面的完整代码中,我将其以粗体显示,即将结束。

What I am trying to do is Filter by the Current State Column (which works fine), then I want it to do a custom sort by the 2nd and 3rd columns ("PCR No." and "Accn. ID" respectively). 我想做的是按“当前状态”列过滤(效果很好),然后我希望它按第二和第三列(分别为“ PCR No.”和“ Accn。ID”)进行自定义排序。 It will work fine if I just used the original recorded code (Range("B2:B2000"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=) but the thing is I want to ensure the macro does not break if I decided to a column later at the beginning so I am trying to get it to do the custom sort by column name not column number. 如果我只是使用原始记录的代码(Range(“ B2:B2000”),SortOn:= xlSortOnValues,Order:= xlAscending,DataOption:=),它将可以正常工作,但我想确保如果我决定在一开始以后再创建一列,所以我试图让它按列名而不是列号进行自定义排序。

Any help would be appreciated here. 任何帮助将不胜感激。

Sub CommercialView() ' ' CommercialView Macro '

  ' Dim wrkbk, sourceBk As Workbook Set sourceBk = Application.ActiveWorkbook 'Clear Filter for all Columns START With ActiveSheet If .AutoFilterMode Then If .FilterMode Then .ShowAllData End If Else If .FilterMode Then .ShowAllData End If End If End With 'Clear Filter from all Columns END

  'Copy the required columns and add them to the destination spreadsheet START
  Workbooks.Add
  Set wrkbk = Application.ActiveWorkbook
  sourceBk.Activate
  wrkbk.Activate
  sourceBk.Activate

  Dim aCell1, aCell2, aCell3, aCell4, aCell5, aCell6, aCell7, aCell8, aCell9, aCell10, aCell11, aCell12 As Range
  Dim strSearch1, strSearch2, strSearch3, strSearch4, strSearch5, strSearch6, strSearch7, strSearch8, strSearch9, strSearch10, strSearch11, strSearch12 As String

  strSearch1 = "Change Request Description"
  strSearch2 = "PCR No."
  strSearch3 = "Accn. ID"
  strSearch4 = "Current State"
  strSearch5 = "Approved Date"
  strSearch6 = "Project"
  strSearch7 = "Planned Commencement Date"
  strSearch8 = "Notes"
  strSearch9 = "Total Price (IIA, DIA, Execution ($)"
  strSearch10 = "Price Calculator Status"
  strSearch11 = "OM Entry"
  strSearch12 = "CVP Ref. No."

  Set aCell1 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch1, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell2 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch2, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell3 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch3, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell4 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch4, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell5 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch5, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell6 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch6, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell7 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch7, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell8 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch8, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell9 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch9, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell10 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch10, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell11 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch11, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  Set aCell12 = Sheets("3. PMO Internal View").Rows(1).Find(What:=strSearch12, LookIn:=xlValues, _
      LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
      MatchCase:=False, SearchFormat:=False)

  '~~> Do the copying here

  Sheets("3. PMO Internal View").Range(Sheets("3. PMO Internal View").Columns(aCell1.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell2.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell3.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell4.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell5.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell6.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell7.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell8.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell9.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell10.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell11.Column).Address & "," _
        & Sheets("3. PMO Internal View").Columns(aCell12.Column).Address).Copy

  'Range("A1,B1,C1,D1,E1,G1,H1,I1,R1,V1,W1,X1").EntireColumn.Select
  'Selection.Copy

  Range("A2").Select
  wrkbk.Activate
  ActiveSheet.Paste
  Selection.AutoFilter
  'Copy the required columns and add them to the destination spreadsheet END

  'To remove data validation START
  Cells.Select
  With Selection.Validation
      .Delete
      .Add Type:=xlValidateInputOnly, AlertStyle:=xlValidAlertStop, Operator _
      :=xlBetween
      .IgnoreBlank = True
      .InCellDropdown = True
      .InputTitle = ""
      .ErrorTitle = ""
      .InputMessage = ""
      .ErrorMessage = ""
      .ShowInput = True
      .ShowError = True
  End With
  'To remove data validation END

  wrkbk.Activate
  wrkbk.Sheets("Sheet1").Select

  'Filter Column Price Calculator Status with those that Require Review from Pricing START

  Dim p As Integer, rngData As Range
  Set rngData = Range("A1").CurrentRegion
  p = Application.WorksheetFunction.Match("Price Calculator Status", Range("A1:AZ1"), 0)

  rngData.AutoFilter Field:=p, Criteria1:="=Completed - Requires Review from Pricing"

  'Filter Column Price Calculator Status with those that Require Review from Pricing END

  'Copy the Status Definitions tab to the new worksheet START

  sourceBk.Sheets("2. Status Definitions").Copy _
  after:=ActiveWorkbook.Sheets("Sheet1")

  'Copy the Status Definitions tab to the new worksheet END

  wrkbk.Sheets("Sheet1").Select
  Range("A5").Select

  'Save to Desktop Directory as DOD folder name - Compatible for any user who runs the macro START

  Dim uName As String: uName = Environ("Username")

  fpath1 = "C:\Users\" & uName & "\Desktop\DOD"
  fpath2 = "C:\Users\" & uName & "\Desktop\DOD\Change Status Request Report"
  fpath3 = "C:\Users\" & uName & "\Desktop\DOD\Change Status Request Report\Commercial View"

  If Dir(fpath1, vbDirectory) = vbNullString Then MkDir fpath1
  If Dir(fpath2, vbDirectory) = vbNullString Then MkDir fpath2
  If Dir(fpath3, vbDirectory) = vbNullString Then MkDir fpath3
  ActiveWorkbook.SaveAs (fpath3 & "\Internal Change Status Request Report - Commercial View - " & Format(Now, "yyyy-mm-dd"))
  ActiveWorkbook.Close

  'Save to Desktop Directory as DOD folder name - Compatible for any user who runs the macro END

  'Return back to Overall CR Tracker and filter out Approved and Cancelled CRs START

  Dim s, f, g As Integer, rngData2, rngData5, rngData6 As Range
  Set rngData2 = Range("A1").CurrentRegion
  s = Application.WorksheetFunction.Match("Current State", Range("A1:AZ1"), 0)

  rngData2.AutoFilter Field:=s, Criteria1:=Array( _
  "Detailed Impact Assessment", "Draft – Yet to be Tabled at CCCM", _
  "Initial Impact Assessment", "New", "On Hold", "Pending Approval - Execution", _
  "Pending Approval - IIA"), Operator:=xlFilterValues

  Set rngData5 = Range("B1").CurrentRegion
  f = Application.WorksheetFunction.Match("PCR No.", Range("A1:AZ1"), 0)
  Set rngData6 = Range("C1").CurrentRegion
  g = Application.WorksheetFunction.Match("Accn. ID", Range("A1:AZ1"), 0)

  ActiveWorkbook.Worksheets("3. PMO Internal View").Sort.SortFields.Clear
  **ActiveWorkbook.Worksheets("3. PMO Internal View").Sort.SortFields.Add Key:= _
  f, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
  xlSortNormal**
  ActiveWorkbook.Worksheets("3. PMO Internal View").Sort.SortFields.Add Key:= _
  g, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
  xlSortNormal
  With ActiveWorkbook.Worksheets("3. PMO Internal View").Sort
    .SetRange Range("A1:X2000")
    .Header = xlYes
    .MatchCase = False
    .Orientation = xlTopToBottom
    .SortMethod = xlPinYin
    .Apply
  End With

  'Return back to Overall CR Tracker and filter out Approved and Cancelled CRs END
End Sub

The Key parameter of the Sort should have a range or a cell address. 排序的Key参数应具有范围或单元格地址。 Your f is defined as f = Application.WorksheetFunction.Match() which returns a number. 您的f定义为f = Application.WorksheetFunction.Match() ,该f = Application.WorksheetFunction.Match()返回一个数字。

You should have something like Set f = Range("A1") or f = "A1" . 您应该具有Set f = Range("A1")f = "A1" Excel will use the column that contains the specified cell. Excel将使用包含指定单元格的列。

EDIT 1: 编辑1:

Instead of: 代替:

f = Application.WorksheetFunction.Match("PCR No.", Range("A1:AZ1"), 0)
ActiveWorkbook.Worksheets("3. PMO Internal View").Sort.SortFields.Add Key:= f

You should use: 您应该使用:

f = Application.WorksheetFunction.Match("PCR No.", Range("A1:AZ1"), 0)
ActiveWorkbook.Worksheets("3. PMO Internal View").Sort.SortFields.Add Key:= Cells(1, f)

Some other comments that come to mind looking at your code: 在查看您的代码时,我会想到一些其他注释:

You variable declarations don't do what you think: 您的变量声明不符合您的想法:

Dim s, f, g As Integer, rngData2, rngData5, rngData6 As Range
'is equivalent to
Dim s As Variant, f As Variant, g As Integer, rngData2 As Variant, rngData5 As Variant, rngData6 As Range

'you should write
Dim s As Integer, f As Integer, g As Integer, rngData2 As Range, rngData5 As Range, rngData6 As Range

You paste too much code. 您粘贴太多的代码。 When I saw it, I just skimmed through it and I was lucky I saw the problem. 当我看到它时,我只是浏览了一下,很幸运地看到了问题。 I would usually skip questions like this. 我通常会跳过这样的问题。 You should try to write a function as short as possible that reproduces the same problem. 您应该尝试编写一个尽可能短的函数,以产生相同的问题。 This helps you for two reasons: it's more likely that someone will read it and give you a solution, and it's more likely that you figure it out on your own during the process of reducing the problem. 这对您有帮助,其原因有两个:更有可能有人阅读它并为您提供解决方案,并且更有可能您在减少问题的过程中自行解决了问题。 I often start writing questions here, but I don't post them because just thinking about how to write it so you can understand it, makes me understand it. 我经常在这里开始写问题,但是我不发布它们,因为只是思考如何写它,以便您理解它,使我理解它。

Mark the answers that help you as answers. 将有助于您的答案标记为答案。 I noticed that you never do that, and many people like to help others in exchange for that little gratifying check mark. 我注意到您永远不会那样做,许多人喜欢帮助别人以换取那可喜的复选标记。 If you are the guy that doesn't gratify, people don't help you. 如果您是不满意的人,那么人们就不会帮助您。

EDIT 2: 编辑2:

I think this is what you need (this time I tested it): 我认为这是您需要的(这次我测试了):

  Dim f As Integer, g As Integer, Sh As Worksheet
  Set Sh = Sheets("3. PMO Internal View")
  f = WorksheetFunction.Match("PCR No.", Sh.Range("A1:AZ1"), 0)
  g = WorksheetFunction.Match("Accn. ID", Sh.Range("A1:AZ1"), 0)
  Sh.Range("A1:X2000").Sort Key1:=Sh.Cells(1, f), Order1:=xlAscending, Key2:=Sh.Cells(1, g), Order2:=xlAscending

Notice that I always use the Sh sheet to specify the sheet the Range and the Cells properties refer to. 请注意,我始终使用Sh表来指定RangeCells属性所引用的表。 This allows you to use this function regardless of the active sheet. 这样,无论活动的工作表如何,都可以使用此功能。 Using Cells(...) or Range(...) without specifying the sheet defaults to the active sheet, and forces you to activate the sheet you want to sort before sorting it. 在不指定工作表的情况下使用Cells(...)Range(...) ,默认使用的是活动工作表,并迫使您在排序之前激活要排序的工作表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM