Why does this work:
Range(Cells(1, 1), Cells(5, 5)).Select
Selection.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlNo, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
But this doesn't?:
Range(Cells(1, 1), Cells(5, 5)).Select
Selection.Sort Key1:=Range(Cells(1,1)), Order1:=xlAscending, Header:=xlNo, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
Saying the
Method Range failed
EDIT
The reason for asking is that I would like the sort key to be dynamic, such as:
Selection.Sort Key1:=Range(Cells(intRow, intCol))
I can't see how this is done.
The Cells call is already returning a Range object, so you should use
Selection.Sort Key1:=Cells(1,1), Order1:=xlAscending, Header:=xlNo, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
I think that your confusion is stemming from the fact that passing two Cells parameters to Range is valid, i.e. Range(Cells(1, 1), Cells(5, 5)), but it is not valid to only pass one Cells parameter, i.e. Range(Cells(1, 1))
You can see this for yourself with the following snippet
Public Sub test()
Dim rng As Range
Set rng = Range(Cells(1, 1), Cells(3, 1))
MsgBox rng.Cells.Count
Set rng = Range(Cells(1, 1))
MsgBox rng.Cells.Count
End Sub
You will get a message saying 3 for the first msgbox call, but you get an exception when trying to set rng the second time.
As to why the second format is not valid, I have no idea. If you find out why the devs built it this way, let us know.
It's always best to qualify exactly which objects you are working with and work directly with the objects, as opposed to using Selection or just Range, as it can sometimes lead to unintended consequences or slow your code down.
Try this:
Dim ws as Worksheet
Set ws = Sheets("Sheet1") ' replace with your sheet name
'assume you wrap this around a loop to move through intRow and intCol _
or set them in some other fasion
With ws.Range(Cells(1,1), Cells(5,5)
.Sort Key1:=.Cells(intRow, intCol), Order1:=xlAscending, Header:=xlNo, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
End With
The reason for asking is that I would like the sort key to be dynamic ...
At least part of the problem is relying on .Select and the subsequent Selection as the working area. If your intention is to work with the Range.CurrentRegion property (the 'island' of data origination in A1) then use a With ... End With statement to define the .CurrentRegion and work with it.
with worksheets("Sheet1") `<~~ set the parent worksheet!
with .Cells(1, 1).CURRRENTREGION `<~~ set the 'island' of data
.cells.Sort Key1:=.cells(1), Order1:=xlAscending, Header:=xlNo, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
end with
end with
I'm a little unclear on what you mean by 'dynamic'. The above will use the cell in the top-left of the area defined by .CurrentRegion. If you used With .Range("D5:H99") then .Cells(1) would refer to D5.
See How to avoid using Select in Excel VBA macros for more methods on getting away from relying on select and activate to accomplish your goals.
Related
I have the following code that dos what I want except for being applied to a specific range. In other words, it does sort on multiple columns, and it does auto update when data is changed:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
If Not Intersect(Target, Range("D3:F")) Is Nothing Then
Columns("A:Z").Sort Key1:=Range("F3"), Key2:=Range("E3"), Key3:=Range("D3"), _
Order1:=xlAscending, Order2:=xlAscending, Order3:=xlAscending, Header:=xlYes, _
OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom
End If
End Sub
However, what it does is that it is applied to the whole range of "A:Z", whereas I want it to be applied to a specific range only (say, "A3:Z").
I have very limited knowledge of Excel VBAs, and did what I thought was the solution, changing Columns("A:Z").Sort to Columns("A3:Z").Sort, and Range("A3:Z").Sort, but the code stops working after this change.
Any help would be greatly appreciated!
Please, try replacing of
Columns("A3:Z").Sort
with
Range("A3:Z" & Range("A" & Rows.count).End(xlUp).Row).Sort
This will set the range to be sorted like starting from A3 to last cell in column Z:Z, but based on the last cell in column A:A.
Edited:
Your event code should look like this:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D3:F" & Rows.Count)) Is Nothing Then
Range("B2:Z" & Range("A" & Rows.Count).End(xlUp).Row + 1).Sort Key1:=Range("F2"), Key2:=Range("E2"), Key3:=Range("D2"), _
Order1:=xlAscending, Order2:=xlAscending, Order3:=xlAscending, Header:=xlYes, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
End If
End Sub
Please, copy the above code instead of yours and test it. When you set the range for the second row, of course, the Keys should be adapted to this row, too. And your code should neve reach the sorting part using Range("D3:F").
Besides all that, you never should use On error resume next until you have a working code and need after that to create a error handler. Otherwise, it only not let you seeing the code real problems/errors...
Edited:
You can also use the next approach (using SortFields):
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D3:F" & Rows.Count)) Is Nothing Then
With ActiveSheet
.Sort.SortFields.Clear
.Sort.SortFields.Add2 Key:=Range("F3:F" & Rows.Count) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.Sort.SortFields.Add2 Key:=Range("E3:E" & Rows.Count) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.Sort.SortFields.Add2 Key:=Range("D3:D" & Rows.Count) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With .Sort
.SetRange Range("B2:Z" & Range("B" & Rows.Count).End(xlUp).Row + 1)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
End If
End Sub
I think it is obvious that you should choose between one of them. If both of them on the sheet code module, an error will be raised...
In case someone really naïve like me had the same problem, here's what works:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
If Not Intersect(Target, Range("D3:F")) Is Nothing Then
Range("A3", Range("Z3").End(xlDown)).Sort Key1:=Range("F3"), Key2:=Range("E3"), Key3:=Range("D3"), _
Order1:=xlAscending, Order2:=xlAscending, Order3:=xlAscending, Header:=xlNo, _
OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom
End If
End Sub
Applying the formula to all the rows below A3
I am trying to sort my records based on Col A values, there are 5 different values and many rows (in a table). Also I have the custom list created in excels built in sort feature.
I am getting an error Sort method of range class failed on
oRangeSort.Sort Key1:=oRangeKey, Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=Application.CustomListCount + 1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
Here is my code:
Sub Sort()
Dim oWorksheet As Worksheet
Set oWorksheet = ActiveWorkbook.Worksheets("database")
Dim oRangeSort As Range
Dim oRangeKey As Range
' one range that includes all colums do sort
Set oRangeSort = oWorksheet.Range("A2:FR20000")
' start of column with keys to sort
Set oRangeKey = oWorksheet.Range("A2")
' custom sort order
Dim sCustomList(1 To 5) As String
sCustomList(1) = "sort1"
sCustomList(2) = "sort2"
sCustomList(3) = "sort3"
sCustomList(4) = "sort4"
sCustomList(5) = "sort5"
Application.AddCustomList ListArray:=sCustomList
oWorksheet.Sort.SortFields.Clear
oRangeSort.Sort Key1:=oRangeKey, Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=Application.CustomListCount + 1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
' clean up
ActiveSheet.Sort.SortFields.Clear
Application.DeleteCustomList Application.CustomListCount
Set oWorksheet = Nothing
End Sub
Try a VBA sort as opposed to rewriting the recorded sort code.
Sub custom_sort()
Dim vCustom_Sort As Variant, rr As Long
vCustom_Sort = Array("sort1", "sort2", "sort3", "sort4", "sort5")
Application.AddCustomList ListArray:=vCustom_Sort
With ActiveWorkbook.Worksheets("database")
.Sort.SortFields.Clear
rr = .Cells(.Rows.Count, "A").End(xlUp).Row
With .Range("A2:FR" & rr)
.Cells.Sort Key1:=.Columns(1), Order1:=xlAscending, DataOption1:=xlSortNormal, _
Orientation:=xlTopToBottom, Header:=xlYes, MatchCase:=False, _
OrderCustom:=Application.CustomListCount + 1
End With
.Sort.SortFields.Clear
End With
End Sub
Looking to augment my existing code to paste only values, and would like to change the copy range to select columns only.
Sub CopySort()
Dim dEnd As Integer
Sheets("Sorted").Range("A2:R250").ClearContents
Sheets("Portfolio").Select
Range("a1").Select
dEnd = Selection.End(xlDown).Row
Range("A5:" & "Z" & dEnd).Copy
Sheets("Sorted").Select
Range("A2").Select
ActiveSheet.Paste
Columns("A:R").Sort key1:=Range("A:A"), order1:=xlAscending, Header:=xlYes, _
key2:=Range("F:F"), order2:=xlAscending, Header:=xlYes, _
OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
Application.CutCopyMode = False
End Sub
Cells.Sort Key1:=Range(rng1), Order1:=xlAscending, Key2:=Range(rng2) _
, Order2:=xlAscending, Header:=xlYes, OrderCustom:=1, MatchCase:= _
False, Orientation:=xlTopToBottom, DataOption1:=xlSortTextAsNumbers, DataOption2 _
:=xlSortNormal
It's throwing an error called application error or object defined error.
Try this sort operation coding alternative. It is pared down to only what you absolutely need.
dim rng1 as range, rng2 as range
With ActiveSheet '<-set this properly as With Sheets("Sheet1")
set rng1 = .Range("A1") 'Top cell of the primary sort key
set rng2 = .Range("B1") 'Top cell of the secondary sort key
With .Range("A1").CurrentRegion '<-sort the 'island' of data that surrounds A1 (with a header)
.Cells.Sort Key1:=rng1, Order1:=xlAscending, _
Key2:=rng2, Order2:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlYes
End With
End With
I have very recently started writing in VBA having written in various other languages over the years. I am currently having some strange issues using filters in Excel VBA and wondered if anyone could shed any light on the behaviour I am experiencing.
I would like to filter by dataset by a number of different columns, one at a time, I am doing this by copying my data set to a new sheet and sorting the data there. For the first filter I am using:
Sheets("Temp Data").Range("A:T").ClearContents
Sheets("Main Sheet").Range("A1", "T" & CountLV_Rows).Copy Sheets("Temp Data").Range("A1", "T" & CountLV_Rows)
Sheets("Temp Data").Range("A1", "T" & CountLV_Rows).Sort Key1:=Range("R1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
This works successfully. I would now like to filter by the values in Col C INSTEAD, I repeat the above code (including the clearcontents command as I thought that would improve my chances of success... and just swap the Key1 value to C1
For second (hopefully new filter), I used:
`Sheets("Temp Data").Range("A:T").ClearContents
Sheets("Main Sheet").Range("A1", "T" & CountLV_Rows).Copy Sheets("Temp Data").Range("A1", "T" & CountLV_Rows)
'Sort the data so ascending site numbers in column C
Sheets("Temp Data").Range("A1", "T" & CountLV_Rows).Sort Key1:=Range("C1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal`
However, my data is sorted by column C after it is first sorted by column R...
How can I wipe any previous sorts applied?
Thanks for your help
I think it might have to do with the fact that you aren't qualifying your worksheets and ranges, i.e., explicitly specifying which workbook or worksheet they are in. That's something you always want to do.
I've done that below and it works for me in Excel 2010:
Sub test()
Dim CountLV_Rows As Long
Dim wbActive As Excel.Workbook
Set wbActive = ActiveWorkbook
With wbActive
.Sheets("Temp Data").Range("A:T").ClearContents
CountLV_Rows = .Sheets("Main Sheet").Range("A" & Rows.Count).End(xlUp).Row
.Sheets("Main Sheet").Range("A1", "T" & CountLV_Rows).Copy _
Destination:=.Sheets("Temp Data").Range("A1", "T" & CountLV_Rows)
With .Sheets("Temp Data")
.Range("A1", "T" & CountLV_Rows).Sort Key1:=.Range("R1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
.Activate
MsgBox "Sorted by R"
.Range("A1", "T" & CountLV_Rows).Sort Key1:=.Range("C1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
End With
End With
End Sub