Custom sort dynamic range using VBA - vba

I receive an Excel file every morning which I like to sort into a more logical manner. All of the column headings are always the same, but the number of rows may change.
I'm trying to put together a macro that highlights the entire region (starting in B2). It needs to sort column C (ascending), G (descending), H (ascending) and I (descending).
I started off by using the macro recorder and am now trying to clean up the code it spat out.
So far I've managed to put together code that selects the region from B2 to the right and then down. Then when defining the sorting criteria for each column, I've tried to make sure that the range selected goes from the top of the list in row 3 (row 2 has headers, row 3 is first item in the list) and then dynamically selects down for each relevant column. However, after the With statement I'm struggling to get the range to be dynamic (it's just the macro-recorded static range still).
I'm also getting an 'Run-time error '1004': Application-defined or object-defined error' after .Apply.
Sub Macro1()
Range("B2").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("G3",
Range("G3").End(xlToRight)) _
, SortOn:=xlSortOnValues, Order:=xlDescending,
DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("C3",
Range("C3").End(xlToRight)) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("H3",
Range("H3").End(xlToRight)) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("I3",
Range("I3").End(xlToRight)) _
, SortOn:=xlSortOnValues, Order:=xlDescending,
DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("B2:Q31") ' NOT SURE HOW TO MAKE DYNAMIC HERE
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply ' GETTING ERROR HERE
End With
End Sub

Just had to change the Range to Selection as you already have dynamically selected the Range in work:
Sub Macro1()
Range("B2").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=Range("G3", Range("G3").End(xlDown)), _
SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=Range("C3", _
Range("C3").End(xlDown)), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=Range("H3", _
Range("H3").End(xlDown)), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add2 Key:=Range("I3", _
Range("I3").End(xlDown)), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
'
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range(Selection.Address)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
See if it works now.

Related

How to make this recorded macro apply for all sheets in workbook

I have this recorded macro which works for one sheet, but I copied and pasted and changed all sheet names and when I ran it, it only worked for the last sheet (wasnt even correct sheet name). How can I sort all the sheets of the workbook (there's like 8).
Sub Sort_Design_NEB()
Range("A1").Select
ActiveWorkbook.Worksheets("NEB_D").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("NEB_D").Sort.SortFields.Add Key:= _
Range("E2:E55"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
ActiveWorkbook.Worksheets("NEB_D").Sort.SortFields.Add Key:= _
Range("H2:H55"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
ActiveWorkbook.Worksheets("NEB_D").Sort.SortFields.Add Key:= _
Range("G2:G55"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("NEB_D").Sort
.SetRange Range("A1:H55")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Try with a loop for all sheets of the workbook. Like this:
Dim WS_Count As Integer
Dim I As Integer
' Set WS_Count equal to the number of worksheets in the active
' workbook.
WS_Count = ActiveWorkbook.Worksheets.Count
' Begin the loop.
For I = 1 To WS_Count
Range("A1").Select
With ActiveWorkbook.Worksheets(I)
.Sort.SortFields.Clear
.Sort.SortFields.Add Key:= _
.Range("E2:E55"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
.Sort.SortFields.Add Key:= _
.Range("H2:H55"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
.Sort.SortFields.Add Key:= _
.Range("G2:G55"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
End With
With ActiveWorkbook.Worksheets(I).Sort
.SetRange Range("A1:H55")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Next I
Update with statement. Thank Thomas Inzina.

How to order a varying column in vba?

I want to order a column which will be at varying positions each time the macro is run. Here is my current code for completing the action:
Range(ActiveCell, ActiveCell.Offset(1000, 1)).Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range(ActiveCell), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range(ActiveCell, ActiveCell(1000, 1))
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
The reason for offsetting by 1000 is that I do not know how many entries there will be in the column, but I know it will be less than 1000... the offset by 1 it to order the numerical values (which are in that 1 column offset) and their company name identifiers, in the other column. Not sure how to fix the code, but in debugging, I get an error specifically after trying to run:
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range(ActiveCell), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
Any ideas?
Range(ActiveCell) does not work because ActiveCell is a range itself. So just use ActiveCell instead of Range(ActiveCell). Better yet, avoid Active... and .Select as Kyle suggested

Excel VBA Sort, error 1004 on .Apply

I'm having issues using sort in VBA. I saw this thread for which the answers don't work for me: Sort in VBA
I believe there is a maximum nr of records on which you can sort. Is that correct? I want to sort on 4 criteria in a sheet/table with 188,000 records.
I always get an error on the .Apply statement: "run-time error '1004': application-defined or object-defined error"
Below my code:
Sub Sort_Table()
Dim sht As Worksheet
Set sht = ActiveWorkbook.Worksheets("Sheet1")
sht.Activate
With sht.ListObjects("Table1").Sort
.SortFields.Clear
.SortFields.Add Key:=Range("Table1[Date]"), SortOn:=xlSortOnValues, Order:=xlAscending ', DataOption:=xlSortNormal
.SortFields.Add Key:=Range("Table1[Country Code]"), SortOn:=xlSortOnValues, Order:=xlAscending ', DataOption:=xlSortNormal
.SortFields.Add Key:=Range("Table1[Rating]"), SortOn:=xlSortOnValues, Order:=xlAscending ', DataOption:=xlSortNormal
.SortFields.Add Key:=Range("Table1[Segment]"), SortOn:=xlSortOnValues, Order:=xlAscending ', DataOption:=xlSortNormal
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Potential problem
Actually maybe you shouldn't the Apply inside the With since your object is really updated after the end of the With block.
For instance here your parameters (.SortFields etc ...) are not yet set when you use Apply. I'm not 100% sure because I doesn't have EXCEL to test right now, and it seem not everyone have this problem with this code as you pointed out, but that may be a reason.
(potential) Solution
Try doing:
With sht.ListObjects("Table1").Sort
.SortFields.Clear
.SortFields.Add Key:=Range("Table1[Date]"), SortOn:=xlSortOnValues, Order:=xlAscending ', DataOption:=xlSortNormal
.SortFields.Add Key:=Range("Table1[Country Code]"), SortOn:=xlSortOnValues, Order:=xlAscending ', DataOption:=xlSortNormal
.SortFields.Add Key:=Range("Table1[Rating]"), SortOn:=xlSortOnValues, Order:=xlAscending ', DataOption:=xlSortNormal
.SortFields.Add Key:=Range("Table1[Segment]"), SortOn:=xlSortOnValues, Order:=xlAscending ', DataOption:=xlSortNormal
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
End With
sht.ListObjects("Table1").Sort.Apply
Tell me if this doesn't solve the issue
Other potential problems/solutions
The sheet you work on (Sorting) is protected
Check out this question: Excel VBA Sort
Hope it helped anyway ...

Sorting a varying size table in excel

What I'm trying to do is select a table in a spreadsheet, and then sort according to 2 different columns
I generated this code with the record macro option. The table changes in size which is why I have used the xlDown, unfortunately the code later references the exact cells "B4:B52". Any idea how I might solve this issue?
Range("B4:J4").Select
Range(Selection, Selection.End(xlDown)).Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range( _
"B4:B52"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range( _
"G4:G52"), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("B4:J52")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Since you are sorting a Table (ListObject in VBA), you'll want to refer to it. This will dynamically adjust to encompass entire table columns. In this example the column headers/names to be sorted are "Data1" and "Data3":
Sub SortTable()
Dim lo As Excel.ListObject
'change this assignment to suit your table location and name
Set lo = ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1")
With lo
.Sort.SortFields.Clear
.Sort.SortFields.Add _
Key:=Range("Table1[data1]"), SortOn:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
.Sort.SortFields.Add _
Key:=Range("Table1[data3]"), SortOn:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
With .Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
End Sub
I would sort the column in the table in the following way:
Sub SortingTable()
Dim ws As Worksheet
set ws = ActiveSheet
Dim target_table As ListObject
Set target_table = ws.ListObjects(wsName)
Dim sort_column_index As Long
sort_column_index = target_table.ListColumns("ColumnToBeSortedName").Index
Dim sort_column As Range
Set sort_column = target_table.ListColumns(sort_column_index).Range
' Applying the sorting to the table
With target_table.Sort
.SortFields.Clear
.SortFields.Add Key:=sort_column _
, SortOn:=xlSortOnValues, Order:=xlAscending _
, DataOption:=xlSortNormal
.Apply
End With
End Sub
In fact, the only difference is that you declare a Range and assign it to the specific table column that should be sorted. Doing it this way, you're able to apply the macro to tables on different sheets assuming that the tables contain the column with name "ColumnToBeSortedName".

Excel 2007 returns `Application-defined or object-defined error`

I have Excel 2007 and Windows XP
When this code runs:
Columns("A:G").Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("B2:B20000") _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("A2:A20000") _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("F2:F20000") _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("A1:G20000")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Application.Calculation = xlCalculationAutomatic
It throws an error at .Apply:
Application-defined or object-defined error
One thing to note is that Application.Calculation = xlCalculationManual
Also, I cannot do anything in the UI except for switching tabs and opening the office menu, and I have to go to the Task Manager and click end task to exit, whereupon it asks if I want to save. Pressing cancel does not fix it. If I hit "no", it just closes. If I hit yes, it calculates and then asks if I want to have it recover my work.
I moved Application.Calculation = xlCalculationAutomatic to right before it and that fixed it.
Application.Calculation = xlCalculationAutomatic
Columns("A:G").Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("B2:B20000") _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("A2:A20000") _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("F2:F20000") _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("A1:G20000")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Edit: Oops, it doesn't after all.
Well, it turned out that it doesn't happen unless the computer is loaded with running programs. I did a pretty good rewrite of it and it is much faster now. The problem seems to be taken care of.