Excel VBA Autofiltering - vba

I am having difficulty getting autofiltering to work using VBA. My code works once, afterwards I get a runtime error code 91. Here is my code. I know it is simple, but what am I missing? Thanks in advance.
Dim MyWorksheet As Worksheet
Set MyWorksheet = Sheets("entity details - cost summary")
Sheets("entity details - cost summary").Select
Range("H6").Select
MyWorksheet.AutoFilter.sort.SortFields.Clear
MyWorksheet.AutoFilter.sort. _
SortFields.Add Key:=Range("H6"), SortOn:=xlSortOnValues, Order:= _
xlAscending, DataOption:=xlSortTextAsNumbers
With MyWorksheet.AutoFilter. _
sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Update:
The error occurs on line 5
MyWorksheet.AutoFilter.sort.SortFields.Clear
Row 5 are column headers, from column B through P. Each row represents a different piece of manufacturing equipment, and each column represents a different attribute or cost. Column H has possible entries. So I am trying to use auto-filter to group each of those entries.

The following will work on the range of data in columns B:P starting with a header row in row 5 and continuing on to the last value in column B.
Sub equip_sort()
With Worksheets("entity details - cost summary")
With .Range(.Cells(5, 2), .Cells(Rows.Count, 2).End(xlUp))
With .Resize(.Rows.Count, 15)
.Cells.Sort Key1:=.Columns(7), Order1:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlYes
.Columns(7).AutoFilter field:=1
End With
End With
End With
End Sub
The data gets sorted and a filter column is selected (column H). No filter is applied as nothing in that area has been specified and no sample data or expected results have been provided.

Related

needing code to use autofilter with variable range of rows

I'm trying to autofilter data in a sheet with 7 columns before copying to another workbook. This is to be used on different data that will have a different number of rows each time.
The issue is that when it autofilters the data it records the number of rows which is different each time (see Range("B1:B124")) below, which it will then apply the next time I try to use it
ChDir "F:\Work-Macro"
Workbooks.Open Filename:="F:\Work-Macro\usage.xls"
Cells.Select
With Selection.Font
.Name = "Calibri"
.Size = 10
End With
Range("D:E,I:L").Select
Range("I1").Activate
Selection.Delete Shift:=xlToLeft
Columns("A:F").Select
Range("F1").Activate
Selection.AutoFilter
ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort.SortFields.Add2 Key:= _
Range("B1:B124"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
there must be a way to apply the autofilter in a dynamic way without it recording the number of rows filtered
Instead of using a fixed range, you want to know the last cell that is in use:
Range("B2:B" & ActiveWorkbook.sheets("Sheet1").cells(rows.count,2).end(xlup).row)
The ActiveWorkbook.sheets("Sheet1").cells(rows.count,2).end(xlup).row) part will return the last row in use in column 2.
By the way, I suggest that you clean up your code after recording. Using Select and Activate is almost never necessary in a macro. It slows your code down and is very error sensitive.

Set Range Based on Last Cell with Value Plus 1

For reasons beyond my control, I must save and upload my data as a csv and i must manually select and clear the cells below my data set, the range changes daily.
Question: How can I edit my vba script to create a range based on the cell below my data set to :J10 and clear/delete it?
EDIT: Are there any changes you would implement?
Here's what I currently have, after exporting and saving as a csv, I reopen the new data and sort and attempt to clear. I have already tried Selection.SpecialCells(CellTypeBlanks).EntireRow.ClearContents & Selection.SpecialCells(CellTypeBlanks).ClearContents
I have 5 separate csv workbooks this macro currently opens and operates on but here is the final portion of my script that is giving me errors
Sub openCSV()
Dim lRow As Long
lRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = lRow To 2 Step -1
If ActiveSheet.Range("H" & i).Value = 0 Then
ActiveSheet.Rows(i).ClearContents
End If
Next i
Range("A2:J10").Select
ActiveWorkbook.Worksheets("BA").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("BA").Sort.SortFields.Add Key:=Range("H2") _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("BA").Sort
.SetRange Range("A2:J10")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
On Error Resume Next
Range("A2:H10").Select
Selection.SpecialCells(CellTypeBlanks).ClearContents
Range("A2:J10").Select
Selection.SpecialCells(CellTypeBlanks).EntireRow.ClearContents
ActiveWorkbook.Save
ActiveWorkbook.Close
SaveChanges = True
Thank you for your time and assistance

VBA sorting not working properly

This challenge came about following an answer to this question:
Excel VBA Sorting
I used the code provided as one of the answers there and attempted to edit it to my situation
I need to sort on column A, header in A1, A to Z - whilst maintaining row integrity, i.e. the row values follow the sorted cells
Here is my attempted code edit, but I've clearly not edited it properly because the column A values are not sorted alphabetically as I'd hoped - can someone please assist?
With ws_catalogue
'''''''''''''''''''''''''''''''''''''''''''
'Get range from B1 to last cell on sheet. '
'''''''''''''''''''''''''''''''''''''''''''
Set myRange = .Range(.Cells(1, 1), .Cells(.Cells.Find("*", , , , 1, 2).Row, .Cells.Find("*", , , , 2, 2).Column))
myRange.Select
With .Sort
.SortFields.Clear
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'As using late binding Access won't understand Excel values so: '
'xlSortOnValues = 0 xlYes = 1 '
'xlAscending = 1 xlTopToBottom = 1 '
'xlSortNormal = 0 xlPinYin = 1 '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
.SortFields.Add _
Key:=myRange.Offset(, 6).Resize(, 1), _
SortOn:=0, _
Order:=1, _
DataOption:=0
.SetRange myRange
.Header = 1
.MatchCase = False
.Orientation = 1
.SortMethod = 1
.Apply
End With
End With
If you want column A to be sorted, you need to include it on myRange. Currently you have
ws_catalogue.Sort.SetRange = myRange
Where myRange is from B1 to the bottom of the data (it does not include column A).
Additionally, if you want to order column A, you need to add something like this
.SortFields.Add _
Key:=myRange.Offset(0,0) _
SortOn:=0, _
Order:=1, _
DataOption:=0
#Xabier has you taken care of but a few other considerations, sorry this code is from another similar answer but it defines the worksheet, and the column names for easier reading code. I will skip the Dims and go to the meat of it, this was for a 3 column sort of unknown or changing row quantity. The example simply shows setting up for the range definition using the rows and columns and Cells to define the range. I stopped the code at the sort, the rest of the code generates a single email for each person with the dept names listed in the body of the email, not relevant to this question. Maybe another way to think about it. You can see the use of the sort key.
'set worksheet to work on as active (selected sheet)
Set emailWS = ThisWorkbook.ActiveSheet
startRow = 2 ' starting row
nameCol = 1 'col of names, can also do nameCol = emailWS.Range("A1").Column
deptCol = 3 'col of depts, can also do deptCol = emailWS.Range("A3").Column
'** Advantage of the optional way is if you have many columns and you don't want to count them
'find the last row with a name in it from the name column
lastRow = emailWS.Cells(emailWS.Rows.Count, nameCol).End(xlUp).Row
'sort the data first before going through the email process using Range sort and a key
'assumes these are the only columns 1 (nameCol) thru 3 (deptCol) to sort
'assumes you are sorting based on col 1 (nameCol)
emailWS.Range(Cells(startRow, nameCol), Cells(lastRow, deptCol)).Sort _
key1:=emailWS.Range(Cells(startRow, nameCol), Cells(lastRow, nameCol))
Cheers,
WWC
If you want to sort by values on Column A, in ascending order, then the following will do that taking the full sheet into consideration:
Sub sortColumnA()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
If ws.AutoFilterMode = False Then ws.Cells.AutoFilter
ws.AutoFilter.Sort.SortFields.Clear
ws.AutoFilter.Sort.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ws.Cells.AutoFilter
End Sub
UPDATE:
If you only want to sort a specific range then something like below should work too:
Sub sortColumnA()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
If ws.AutoFilterMode = False Then ws.Range("A1:Z1").AutoFilter
ws.AutoFilter.Sort.SortFields.Clear
ws.AutoFilter.Sort.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ws.Range("A1:Z1").AutoFilter
End Sub

VBA Macro to compare then organize data

I'm trying to architect a macro to do the following steps:
Compare two lists of data (in this case Column A against Column C)
Output in B any cell that exists in both A and C. Line up the match next to its match in Column A.
Sort both column A and B by their values so that the corresponding cells in A and B are still next to each other after the sort.
Desired result. Notice how the matches in column A and B are still together. This enables users of this macro to quickly eliminate data that only belongs to one of the respective columns and it allows us to retain any information that may be tied to column A, e.g., Column A contains email addresses, and there is a corresponding column next to it that contains phone #'s. We don't want to split that information up. This macro would enable that:
Pastebin of excel data I used: http://pastebin.com/mYuQRMjj
This is the macro I've written, which uses a second macro:
Sub Macro()
Range(Selection, Selection.End(xlDown)).Select
Application.Run "macro4.xlsm!Find_Matches"
Range("B1:B284").Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("B1:B284") _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("A1:B284")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
The second macro that does the comparison is literally ripped straight from Microsoft, with a little extra.
Sub Find_Matches()
Application.ScreenUpdating = False
Dim CompareRange As Variant, x As Variant, y As Variant
' Set CompareRange equal to the range to which you will
' compare the selection.
Set CompareRange = Range("C1:C500")
' NOTE: If the compare range is located on another workbook
' or worksheet, use the following syntax.
' Set CompareRange = Workbooks("Book2"). _
' Worksheets("Sheet2").Range("C1:C5")
'
' Loop through each cell in the selection and compare it to
' each cell in CompareRange.
For Each x In Selection
For Each y In CompareRange
If x = y Then x.Offset(0, 1) = x
Next y
Next x
Application.ScreenUpdating = True
End Sub
Using these two macros, I get exactly what I want, but I don't like using limited ranges. I want the macro to be smart enough to determine exactly what the range is, because the people who will be using this macro sometimes will be using a list of 200, sometimes a list of 2,000,000. I want this macro to be a "one size fits all" for range.
I looked into this and the command:
Range(Range("B1"),Range("A1").End(xlDown)).Select
gets exactly the selection I want after Find_Matches runs (I also realize that Find_Matches is using a finite compare range . . . solving my issue for this first Macro will solve that too).
The problem is that I am unsure how to plug that into my Macro. I've tried several implementations and I'm flat out stuck. I can't find an answer for something this specific, but I know I'm very close. Thank you for any help!
edit: This whole method is realllly slow on larger lists (20+ minutes on a list of 100k). If you can suggest some ways to speed it up that would be super helpful!
Sub MatchNSort()
Dim lastrow As Long
'Tell Excel to skip the calculation of all cells and the screen
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
'Find the last row in the data
With ActiveSheet
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lastrow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lastrow = 1
End If
End With
'Force a formula in column B to match a from c
ActiveSheet.Range("B1:B" & lastrow).Formula = _
"=IFERROR(IF(MATCH(C[-1],C[1]:C[1],0)>0,C[-1],""""),"""")"
'Force a recalculate
Application.Calculate
'Sort columns B and A
With ActiveSheet
.Range("A1:B" & lastrow).Select
.Sort.SortFields.Clear
'First key sorts column B
.Sort.SortFields.Add Key:=Range("B1:B" & lastrow) _
, SortOn:=xlSortOnValues, Order:=xlAscending _
, DataOption:=xlSortNormal
'Second key (optional) sort column A, after defering to column B
.Sort.SortFields.Add Key:=Range("A1:A" & lastrow) _
, SortOn:=xlSortOnValues, Order:=xlAscending _
, DataOption:=xlSortNormal
.Sort.SetRange Range("A1:B" & lastrow)
.Sort.Header = xlGuess
.Sort.MatchCase = False
.Sort.Orientation = xlTopToBottom
.Sort.SortMethod = xlPinYin
.Sort.Apply
End With
'Return autocalulation and screen updates
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.Calculate
End Sub
See Error in finding last used cell in VBA for the best way to find the last row of data.
Find the last row and then change your range selection to:
Range("C1:C"&Trim(CStr(lastrow)))
To speed up your macro execution start your macro with:
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
and to restore autocalc and screen updates, end your macro with:
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.Calculate

automatically sort alphabetically in vba

I want to sort info on my sheet according to their last name (which is column 1). there's a form control button on the sheet that filters the info in accordance to the name of the button. everytime each of these form control buttons are clicked, i want to sort the info alphabetically. so i've used the record on macro to see what excel does to get familiar with it but i'm quite stuck... the problem is the r and countA it gives me an error of type mismatch
in total i have 17 columns (A to Q - but i don't want to really set a range to the columns, just in case i add more columns later) that contains information related to the last name which is column 1 and starts from row 3
Sub btnPrinceRupert()
Dim ws As Worksheet
Dim r As Range
Set r = ws.Cells(2, 1)
Set ws = Worksheets("Master")
Call filterMyTable(xPrinceRupert)
Call changeTitle("PrinceRupert")
r.Select
ws.Sort.SortFields.Clear
ws.Sort.SortFields.Add Key:=r, _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.sort
.SetRange (WorksheetFunction.CountA(Range("A:A")))
'essentially, i want the range to be up to the last entry of the table
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
For the first issue, you need to set the ws before set the r value;
and the Second issue, the result of WorksheetFunction.CountA(Range("A:A")) is a number, not Range. so the code should write like this:
Sub btnPrinceRupert()
Dim ws As Worksheet
Dim r As Range
Set ws = Worksheets("Master")
Set r = ws.Cells(2, 1)
Call filterMyTable(xPrinceRupert)
Call changeTitle("PrinceRupert")
r.Select
ws.Sort.SortFields.Clear
ws.Sort.SortFields.Add Key:=r, _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.sort
.SetRange (Range("1:" & WorksheetFunction.CountA(Range("A:A")))
'essentially, i want the range to be up to the last entry of the table
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub