How to sort with more than three columns? - excel

My worksheet has a large table with five columns. Row 1 has headers. I would like to sort the entire table using four column headers as sort fields.
VBA only allows three, so I tried the following
Sub CreateTimeSeries()
With Range("A1", Range("A1").SpecialCells(xlCellTypeLastCell)).Sort
.SortFields.Clear
.SortFields.Add Key:=Range("B1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("C1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("D1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.Header = xlYes
.Apply
End With
End Sub
I get
Run-time error '1004':
Unable to get the Sort property of the Range class.
It can't be the worksheet. I select the worksheet before running the routine. Trying various solutions on StackOverflow has not fixed the error.

This works for me:
Sub CreateTimeSeries()
Dim tbl As Range
With ActiveSheet
Set tbl = .Range("A1", .Range("A1").SpecialCells(xlCellTypeLastCell))
End With
With tbl.Parent.Sort
.SortFields.Clear
.SortFields.Add Key:=Range("B1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("C1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("D1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange tbl '<<<<<<<
.Header = xlYes
.Apply
End With
End Sub

Related

sorting every cell with data in excel using VBA

I recorded a macro for sorting this sheet. how do I replace the hardcoded ranges so that this script works with any number of rows?
Worksheets(1).sort.SortFields. _
Clear
Worksheets(1).sort.SortFields. _
Add2 Key:=Range("A2:A130008"), SortOn:=xlSortOnValues, Order:=xlAscending _
, DataOption:=xlSortNormal
Worksheets(1).sort.SortFields. _
Add2 Key:=Range("B2:B130008"), SortOn:=xlSortOnValues, Order:=xlAscending _
, DataOption:=xlSortNormal
Worksheets(1).sort.SortFields. _
Add2 Key:=Range("C2:C130008"), SortOn:=xlSortOnValues, Order:=xlAscending _
, DataOption:=xlSortNormal
Worksheets(1).sort.SortFields. _
Add2 Key:=Range("D2:D130008"), SortOn:=xlSortOnValues, Order:=xlAscending _
, DataOption:=xlSortNormal
Worksheets(1).sort.SortFields. _
Add2 Key:=Range("E2:E130008"), SortOn:=xlSortOnValues, Order:=xlAscending _
, DataOption:=xlSortNormal
Worksheets(1).sort.SortFields. _
Add2 Key:=Range("P2:P130008"), SortOn:=xlSortOnValues, Order:= _
xlDescending, DataOption:=xlSortNormal
Worksheets(1).sort.SortFields. _
Add2 Key:=Range("Q2:Q130008"), SortOn:=xlSortOnValues, Order:= _
xlDescending, DataOption:=xlSortNormal
With Worksheets(1).sort
.SetRange Range("A1:R130008")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
This ought to do the job. Please try it.
Sub StackOverflow()
Dim Rng As Range ' range to sort
With Worksheets(1)
Set Rng = .Range(.Cells(2, "A"), .Cells(.Rows.Count, "A").End(xlUp)) _
.Resize(, .Columns("R").Column)
' .Columns("R").Column = 18 and may be replaced with this number
With .Sort.SortFields
.Clear
' specify the columns to sort on in sequence of priority
.Add2 Key:=Rng.Cells(1), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add2 Key:=Rng.Cells(2), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add2 Key:=Rng.Cells(3), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add2 Key:=Rng.Cells(4), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add2 Key:=Rng.Cells(5), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add2 Key:=Rng.Cells(16), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add2 Key:=Rng.Cells(17), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
End With
With .Sort
.SetRange Rng
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
End Sub
Note that in .Sort.SetRange the entire range must be specified whereas for setting each of the Keys just one cell is required to identify a column. Since the cells in a range are numbered 1 and up first across and then down the first 18 cell numbers in the range coincide with the column numbers in the underling sheet range. So Key:=Rng.Cells(1) happens to be Worksheets(1).Cells(2, "A") based on how Rng was specified. I chose the shorter syntax but the effect is that the entire range will first be sorted on column A before other keys are applied.

Dynamic sort with large workbook

I can do some basic sortinng using vba however i cannot get things to work when i want to make it dynamic...
what i have done now is set a hard stop at 10k, however the workbooks i need to sort change rapidly in size.
what would be the best approach and why?
i have tried to set the "Range" to Range("a1:B" & lastrow), respectively for each select however this seems to hang and not execute the macro.
ActiveWorkbook.Worksheets("Rapportage").Sort.SortFields.Add2 Key:=Range( _
"A1:BZ1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("Rapportage").Sort
.SetRange Range("A1:BZ9999")
.Header = xlYes
.MatchCase = False
.Orientation = xlLeftToRight
.SortMethod = xlPinYin
.Apply
End With
Application.CutCopyMode = False
Range("q3", Range("q5 : q9999")).FormulaR1C1 = "=RC[1]+RC[2]"
Rows("5:9999").Select
ActiveWorkbook.Worksheets("Rapportage").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Rapportage").Sort.SortFields.Add2 Key:=Range( _
"B5:B9999"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
ActiveWorkbook.Worksheets("Rapportage").Sort.SortFields.Add2 Key:=Range( _
"C5:C9999"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
ActiveWorkbook.Worksheets("Rapportage").Sort.SortFields.Add2 Key:=Range( _
"F5:F9999"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
ActiveWorkbook.Worksheets("Rapportage").Sort.SortFields.Add2 Key:=Range( _
"E5:E9999"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
ActiveWorkbook.Worksheets("Rapportage").Sort.SortFields.Add2 Key:=Range( _
"I5:I9999"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortTextAsNumbers
With ActiveWorkbook.Worksheets("Rapportage").Sort
.SetRange Range("A5:BZ9999")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With```
I think your code should look somewhat like the procedure below. Note that the Key defines the column to be sorted on. It's specified by a single cell in it, usually in the first row but I chose the fifth because the first row is excluded from your range - not that VBA or Excel would take offence.
Sub TestSort()
' 041
Dim Cell As Range
Dim SortRng As Range
With ActiveWorkbook.Worksheets("Rapportage")
Set Cell = .Cells(5, 2)
With .Sort.SortFields
.Clear
.Add Key:=Cell, SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add Key:=Cell.Offset(, 1), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add Key:=Cell.Offset(, 4), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add Key:=Cell.Offset(, 3), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add Key:=Cell.Offset(, 7), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
End With
Set SortRng = .Range(.Cells(5, "A"), _
.Cells(.Rows.Count, "A").End(xlUp).Offset(, 77))
With .Sort
.SetRange SortRng
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
End Sub
Specifying the column to sort on is different from specifying the range to be sorted. That enters the code only after the keys have all been set and the actual sorting process is initiated.

SortFields.Clear Clarification

If this is my only sort statement in my sub then can I just delete SortFields.Clear?
Any useful applications of using SortFields.Clear?
I don't think I have any existing sort fields at the start of my code. Or in the actual worksheet.
Code in question
With ws_raw.Sort
.SortFields.Clear
.SortFields.Add2 Key:=Range("A1"), Order:=xlAscending
.SortFields.Add2 Key:=Range("L2"), Order:=xlDescending
.SetRange rng_raw
.Header = xlYes
.Apply
End With
What I am trying to accomplish, looking for a similar code:
With ws_raw.Sort
.SortFields.Add2 Key:=Range("A1"), Order:=xlAscending
.SortFields.Add2 Key:=Range("L2"), Order:=xlDescending
.SetRange rng_raw
.Header = xlYes
.Apply
End With
' main code
With ws_raw.Sort
.SortFields.Clear
.Header = xlYes
.Apply
End With

Excel Macro to perform multi column sort

I'm trying to create a macro in Excel that will sort spreadsheets by columns A, C and F. I found information online to get me started. Below is the code. The challenge I'm having is, the spreadsheet will contain a different number of rows each day. (The columns will always be the same but the row count will change). The below script will sort my data as long as the spreadsheet does not contain more than 9999 rows (that includes column headings). If I have 10,000 or more rows, the macro fails.
How do I update the below code to allow it to run regardless of the number of rows? Any help you can provide would be appreciated. Thank you
Sub Multi_Sort()
'
' Multi_Sort Macro
'
Dim lngLast As Long
lngLast = Range("A" & Rows.Count).End(xlUp).Row
With Worksheets("Sheet1").Sort
.SortFields.Clear
.SortFields.Add Key:=Range("A1:A1" & lngLast), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("C1:C1" & lngLast), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("F1:F1" & lngLast), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange Range("A1:F" & lngLast)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
I can't replicate your error in Excel 2013, but I'm guessing the extra "1" in your range assignments is the problem (i.e., change =Range("A1:A1" & lngLast) to =Range("A1:A" & lngLast), etc.).
Also, a good practice would be to be explicit in your range calls (include the worksheet).
Sub Multi_Sort()
Dim lngLast As Long
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
lngLast = ws.Range("A" & .Rows.Count).End(xlUp).Row
With .Sort
.SortFields.Clear
.SortFields.Add Key:=ws.Range("A1:A" & lngLast), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=ws.Range("C1:C" & lngLast), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=ws.Range("F1:F" & lngLast), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange ws.Range("A1:F" & lngLast)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub

Sort Numbers/Text in one column

I have wrote the following code to sort data on my workbook
With gwksSheet
With .Sort
.SortFields.Clear
.SortFields.Add Key:=Columns(glAssetTypeCol), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Columns(glFundCodeCol), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Columns(glOberonCol), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange Range(Cells(1, 1), Cells(glLastRow, glLastCol))
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
In the column "glOberonCol" I have numbers (e.g. 2561236) & Text (e.g. 2561236R). When it sorts it sorts the numbers and then the text. I want to sort it so I get 2561236 & 2561236R beside each other. What do I need to do. Appreciate any help.
Thanks,
Ciaran.
Follow the steps bellow:
Create another column
Add formula "=TEXT(RC[-1],"###")"
Copy this value and override the old values forcing Excel to see numbers as strings.
Now you can use your macro or just use Filter button.

Resources