I have a range that length keeps changing. I need to redefine the named range each time it changes and then sort it.
I have this so far:
Sub Macro2()
'
' Name and Sort
'
Range("A3").Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
ActiveWorkbook.Names.Add Name:="data4", RefersToR1C1:= _
"='Data Storage'!R3C1:R25C18"
ActiveWorkbook.Names("data4").Comment = ""
Application.Goto Reference:="data4"
ActiveWorkbook.Worksheets("Data Storage").sort.SortFields.Clear
ActiveWorkbook.Worksheets("Data Storage").sort.SortFields.Add Key:=Range( _
"D3:D25"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("Data Storage").sort
.SetRange Range("A3:R25")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
But the next time the range changes it only sorts on the previous range. I think it has to do with the R3C1:R25C18 reference but I don't know how to change that each time the range changes.
Thanks for any help.
This code checks for the last row with data, names the range, and sorts the named range
Dim lngRowLast As Long
'Find last row
lngRowLast = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'Your range goes here
Range(cells(3,1),cells(lngRowLast,18)).Name = "data4"
Range("data4").Sort Key1:=Cells(3, 1), Order1:=xlAscending, _
Header:=xlYes
Related
How to refer to dynamic sheet in Excel VBA instead of Sheet Name - Instead of "Sheet16", i want to refer to the ActiveSheet, please see below
Sub Macro1()
Cells.Select
Selection.Copy
Sheets.Add After:=ActiveSheet
ActiveSheet.Paste
Application.CutCopyMode = False
Selection.AutoFilter
ActiveWorkbook.Worksheets("Sheet16").AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet16").AutoFilter.Sort.SortFields.Add2 Key:= _
Range("M1:M12"), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption _
:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet16").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Just need to change it to (ActiveSheet.Name)
The usage of ActiveSheet (as well of that of ActiveCell, Selection and the like of) should be avoided in favor of that of variables of proper class (e.g.: Worksheet, Range) as follows:
Sub Macro1()
ActiveSheet.UsedRange.Copy ' handle only relevant cells
Sheets.Add After:=ActiveSheet
Dim newSh As Worksheet
Set newSh = ActiveSheet ' set the currently active sheet to the 'newSh' variable of 'Worksheet' class
With newSh ' reference 'newSh' variable
.Paste
Application.CutCopyMode = False
.UsedRange.AutoFilter
Dim keyRng As Range
Set keyRng = .Range("M1:M12") ' set M1:M12 cells range of the referenced sheet as the one for sort keys
With .AutoFilter.Sort ' reference 'Sort' property of 'Autofilter' object of referenced sheet
With .SortFields ' reference 'SortFields' object of referenced 'Sort' property
.Clear
.Add2 Key:=keyRng, _
SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
End With
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
End Sub
This worked perfectly fine for me :)
Sub Sortieren()
lr = Cells.Find("*", Cells(1, 1), xlFormulas, xlPart, xlByRows, xlPrevious, False).Row
Cells.Select
Selection.AutoFilter
Worksheets(ActiveSheet.Name).Sort.SortFields.Clear
Worksheets(ActiveSheet.Name).AutoFilter.Sort.SortFields.Add2 Key:= _
Range("N1:N" & lr), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption _
:=xlSortNormal
With ActiveWorkbook.Worksheets(ActiveSheet.Name).AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Below is the list of names, and the macro code to sort and output the data. The macro runs separately for each name. I would like it to reuse the main body of the code, with the macro choosing each name, in turn, from the list
List of names:
Manny
Joe
Tom
Mike
Sort and output code for Manny:
Sheets("Manny").Select
Range("A2:J1000").Select
Selection.ClearContents
Sheets("Master list").Select
Range("A1:J1000").Select
ActiveSheet.Range("$A1:J351").AutoFilter Field:=10, Criteria1:= _
"Manny"
Selection.Copy
Sheets("Manny").Select
Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Columns("H:H").Select
ActiveWorkbook.Worksheets("Manny").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Manny").Sort.SortFields.Add Key:=Range("H1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Manny").Sort
.SetRange Range("A2:J351")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Columns("A:A").EntireColumn.AutoFit
Columns("E:E").EntireColumn.AutoFit
Sheets("Master list").Select
ActiveSheet.Range("$A1:J350").AutoFilter Field:=10
Consider generalizing your process in a Sub or Function to receive the name as parameter. However, as commented see top answers of canonical question, How to avoid using Select in Excel VBA, where you can avoid any and all .Select, .Activate, .Selection, ActiveSheet, .ActiveWorkbook, and unqualified references to workbook, workhseets, columns, and cell ranges.
Below is refactored code to process sheets by input parameter name, using named range, direct assignment of range values, and With context block. Adjustments may be needed. Be sure to incorporate other best practices: On Error, Option Explicit, Set object = Nothing, etc.
Public Sub sort_data(name As String)
Dim master_rng As Range
Set master_rng = ThisWorkbook.Sheets("Master list").Range("$A1:J351")
master_rng.AutoFilter Field:=10, Criteria1:= name ' USE OF INPUT PARAMETER
With ThisWorkbook.Worksheets(name) ' USE OF INPUT PARAMETER
.Range("A2:J1000").ClearContents
.Range("A1:J351").Value = master_rng.value ' REPLACEMENT OF COPY/PASTE
.Columns("H:H").Sort.SortFields.Clear
.Columns("H:H").Sort.SortFields.Add Key:=.Range("H1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With .Sort
.SetRange ThisWorkbook.Worksheets(name).Range("A2:J351")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
.Columns("A:A").EntireColumn.AutoFit
.Columns("E:E").EntireColumn.AutoFit
End With
master_rng.AutoFilter Field:=10
Set master_rng = Nothing
End Sub
Then call above method individually or in loop for each needed name:
Call sort_data("Manny")
Call sort_data("Joe")
Call sort_data("Tom")
Call sort_data("Mike")
Dim nm As Variant
For Each nm in Array("Manny", "Joe", "Tom", "Mike")
Call sort_data(nm)
Next nm
Sub RRC()
Dim noOfLists As String
With Sheets("All_list")
Application.CutCopyMode = False
Application.AddCustomList ListArray:=Range("AU2:AU4")
noOfLists = Application.CustomListCount
noOfLists = noOfLists + 1
End With
ActiveWorkbook.Worksheets("All_list").ListObjects("All").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("All_list").ListObjects("All").Sort.SortFields.Add2 _
Key:=Range("All[RRC]"), SortOn:=xlSortOnValues, Order:=xlAscending, _
CustomOrder:=CVar(noOfLists), DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("All_list").ListObjects("All").Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Application.DeleteCustomList (noOfLists - 1)
End Sub
Could anyone Help to figure out why this does not work, it runs, but does not sort.
Range AU2:AU4 will be dynamic, meaning that sorting there will always be different, therefore the key moment here is to use the latest sort in that range when applying VBA
Thank you
This is what I would have used. Let me know if there's a reason you're using the CustomOrder in the actual sort
Sub RRC()
Dim currWorksheet As Worksheet
Set currWorksheet = ActiveWorkbook.Worksheets("All_list")
Dim newRangeSort As Range
Dim newRangeKey As Range
' Fields to be sorted
Set newRangeSort = currWorksheet.Range("AU2:AU4")
' "Header" column of which to sort from
Set newRangeKey = currWorksheet.Range("AU1")
'Your sort
Dim customSort As String
customSort = ("test")
'Actual sort
currWorksheet.Sort.SortFields.Clear
newRangeSort.Sort Key1:=newRangeKey, Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=Application.CustomListCount + 1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
' clean up
Set currWorksheet = Nothing
End Sub
There should be no reason to use a With here. This is a much better way of pulling a custom sort, as using vba - Application.AddCustomList is just an awful way to do things - very unfriendly
Here is what i did, after some intzernet research:
Sub Segment()
Dim x() As Variant
With Sheets("All_list")
.Range("AP2:AP10").Clear
.Range("AO2:AO10" & .Cells(.Rows.Count, "AO").End(xlUp).Row).Copy
.Range("AP2").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
x = Application.Transpose(Sheets("All_list").Range("AP2:AP10").Value)
ActiveWorkbook.Worksheets("All_list").ListObjects("All").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("All_list").ListObjects("All").Sort.SortFields.Add2 _
Key:=Range("All[Segment]"), SortOn:=xlSortOnValues, Order:=xlAscending, _
CustomOrder:=Join(x, ","), DataOption:=xlSortNormal
End With
With ActiveWorkbook.Worksheets("All_list").ListObjects("All").Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
First ranges just copy paste code cells into text, otherwise macro doe not run, join allowed to skip creation of custom list in excel
I recorded the following macro when sorting data:
Sub sort_sheet_test()
ActiveWindow.ScrollRow = 1
ActiveWindow.ScrollColumn = 1
Range("A1:AB40905").Select
ActiveWorkbook.Worksheets("flurry_an_output.csv").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("flurry_an_output.csv").Sort.SortFields.Add Key:= _
Range("AB2:AB40905"), SortOn:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("flurry_an_output.csv").Sort
.SetRange Range("A1:AB40905")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
I then wrote my own function to use generically in other sheets...etc:
Function sort_sheet_last_column(sheet_name As String)
Dim rows1 As Long
rows1 = Get_Rows_Generic(sheet_name, 1) ' get the number of rows in the sheet
Dim columns1 As Integer
columns1 = Range(find_last_column(sheet_name)).column ' get the number of columns in the sheet
Dim sort_range As Range
Dim key_range As Range
With Worksheets(sheet_name)
Set sort_range = .Range(.Cells(1, 1), .Cells(rows1, columns1)) ' set up range: the whole used portion of the sheet
Set key_range = .Range(.Cells(1, columns1), .Cells(rows1, columns1))
End With
With Worksheets(sheet_name).Sort
.SortFields.Clear
.SortFields.Add Key:=key_range, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange sort_range
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Function
It seems to reorder the rows based on the right key, but how do I know if my version is 1) working at all (it's hard to know if over 40,000 rows are ordered properly, and 2) how do I know if the rest of the data are in their proper order?
I always use Sheet.Range.Sort not Sheet.Sort
lLastRow = LastUsedRow(shMain)
shMain.Range("A1:W" & lLastRow).SORT Key1:=.Range("B2"), _
Order1:=xlAscending, _
Header:=xlYes, _
OrderCustom:=1, _
MatchCase:=False, _
Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
Never had a problem with this sorting the range and you can add Key2,Order2 and DataOption2 to sort by multiple columns
Hi I am working with a lot of random column cells. I am trying to use this option in excel vba. I used macro recorder but not working when I use this on another sheet.
Sorting also not working. Any idea??
For more details please check the below code :
Range("I1").Select
ActiveCell.FormulaR1C1 = "=RC[-3]/1000"
Range("I1").Select
Selection.AutoFill Destination:=Range("I1:I5396")
Range("I1:I5396").Select
Range("J1").Select
ActiveCell.FormulaR1C1 = ""
Columns("I:I").Select
Selection.Copy
Columns("J:J").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Columns("J:J").Select
Application.CutCopyMode = False
ActiveWorkbook.Worksheets("347").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("347").Sort.SortFields.Add Key:=Range("J1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("347").Sort
.SetRange Range("J1:J5396")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
To perform this in a loop on all of your worksheets in the ActiveWorkbook, you can use a For Each loop.
I declare a variable ws to represent the worksheet loop, and another variable rng to represent the column I, and sortRange to represent the column J which is to be sorted.
Dim ws as Worksheet
Dim rng as Range
Dim sortRange as Range
For each ws in ActiveWorkbook.Worksheets
'Simulate the ctrl+shift+down to assign this range
With ws
Set rng = .Range("I1", .Range("I1").End(xlDown))
End With
'Assign the sorted range is one column to the right:
Set sortRange = rng.Offset(0, 1)
'Fill the formula in Column I:
rng.FormulaR1C1 = "=RC[-3]/1000"
'"Paste" the values from column I into column J
sortRange.Value = rng.Value
'Set the sort fields:
With ws
With .Sort.SortFields
.Clear
.Add Key:=sortRange.Cells(1,1), _
SortOn:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
End With
.Sort.SetRange sortRange
.Sort.Header = xlGuess
.Sort.MatchCase = False
.Sort.Orientation = xlTopToBottom
.Sort.SortMethod = xlPinYin
.Sort.Apply
End With
Next
I have also modified this code to avoid relying on the Activate and Select methods. HERE is a good primer on why these methods are often problematic for many users. The macro recorder simply records very specific and explicit user actions. This is fine for giving you a "staring point", but in order to make most macros re-usable, it's necessary to modify away from simply "simulated keystrokes" and program directly to the object model, using variables rather than Selection.