I want to make sorting and summing very easy for a user by building a macro. The macro needs to find the final row, then sort, then subtotal and total. It should also use the current, active sheet. For example, I should turn the first spreadsheet into the second:
I'm able to do it for this dataset with a simple recording of the macro.
Sub Macro1()
'
' Macro1 Macro
'
' Keyboard Shortcut: Ctrl+Shift+B
'
ActiveWorkbook.Worksheets("Oct 2015").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Oct 2015").Sort.SortFields.Add Key:=Range("A2:A24" _
), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Oct 2015").Sort.SortFields.Add Key:=Range("B2:B24" _
), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Oct 2015").Sort
.SetRange Range("A1:C24")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Selection.Subtotal GroupBy:=1, Function:=xlSum, TotalList:=Array(3), _
Replace:=True, PageBreaks:=False, SummaryBelowData:=True
Selection.Subtotal GroupBy:=2, Function:=xlSum, TotalList:=Array(3), _
Replace:=False, PageBreaks:=False, SummaryBelowData:=True
Range("A1:C45").Select
End Sub
I have the following bit of code to find the last row, but not sure how to integrate it into the above to replace the hard-coded "range" value.
Sub GetLastRow(strSheet, strColum)
Dim MyRange As Range
Dim lngLastRow As Long
Set MyRange = Worksheets(strSheet).Range(strColum & "1")
lngLastRow = Cells(sheetvar.Rows.Count, MyRange.Column).End(xlUp).Row
End Sub
I'd also need to change the Active Worksheet value to the current open worksheet, since this value will change.
The column names and column order should be consistent. I would also need to put this script on a remote user's PC and make sure it was available whenever they opened Excel.
I'd also like to shade the subtotaled areas if possible, but this is a secondary request.
You were half way there.
First you declare your variables for current sheet, your range and your last row and column.
And then you implement all of them into the macro you just recorded.
Sub Macro1()
'
' Macro1 Macro
'
' Keyboard Shortcut: Ctrl+Shift+B
Dim sht As Worksheet
Dim lRow As Long, lCol As Long
Dim rng As Range
Set sht = ActiveWorkbook.ActiveSheet
With sht
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
lCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
Set rng = .Range(.Cells(lRow, 1), .Cells(lRow, lCol))
End With
sht.Sort.SortFields.Clear
sht.Sort.SortFields.Add Key:=rng, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
sht.Sort.SortFields.Add Key:=rng, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With sht.Sort
.SetRange rng
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Selection.Subtotal GroupBy:=1, Function:=xlSum, TotalList:=Array(3), _
Replace:=True, PageBreaks:=False, SummaryBelowData:=True
Selection.Subtotal GroupBy:=2, Function:=xlSum, TotalList:=Array(3), _
Replace:=False, PageBreaks:=False, SummaryBelowData:=True
End Sub
Related
I'm looking to use a VBA Macro which will 'sort' a column but 'hide' all the other text.
The column is populated with three letter text, i.e. MFA, KDB, OPA etc...
This is the code I currently have found:
Sub SortByName()
With ActiveSheet
.Sort.SortFields.Clear
.Sort.SortFields.Add Key:=.Range("V:V"), _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
CustomOrder:="MFA", _
DataOption:=xlSortNormal
.Sort.SetRange .Range("A:AA")
.Sort.Header = xlYes
.Sort.MatchCase = False
.Sort.Orientation = xlTopToBottom
.Sort.SortMethod = xlPinYin
.Sort.Apply
End With
End Sub
This code works well, but it does not hide the undesired rows with text that is not 'MFA'
Many thanks :)
As mentioned, use AutoFilter to hide rows not containing 'MFA'
Option Explicit
Public Sub SortByName()
Dim ws As Worksheet
Set ws = ActiveSheet
With ws
.Sort.SortFields.Clear
.Sort.SortFields.Add Key:=.Range("V:V"), _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
CustomOrder:="MFA", _
DataOption:=xlSortNormal
.Sort.SetRange .Range("A:AA")
.Sort.Header = xlYes
.Sort.MatchCase = False
.Sort.Orientation = xlTopToBottom
.Sort.SortMethod = xlPinYin
.Sort.Apply
.UsedRange.Columns("V").AutoFilter Field:=1, Criteria1:="MFA"
'Or: .Range("A:AA").AutoFilter Field:=22, Criteria1:="MFA"
End With
End Sub
In cells A1 and A2, I have a concatenate formula that produces X1:X2 and Y1:Y2 respectively, where in both the letter and numerical values are dependent on certain formulas in the worksheet.
In VBA, I wish to sort out the describe ranges in A1 and A2 separately. I tried the following formula, but it didn't work:
Sub Sort()
Dim myrange1 As String
Dim myrange2 As String
myrange1 = A1
myrange2 = a2
Range(myrange1).Select
ActiveWorkbook.Worksheets("Sample generator").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sample generator").Sort.SortFields.Add Key:=Range( _
"X2"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("Sample generator").Sort
.SetRange Range(myrange1)
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range(myrange2).Select
ActiveWorkbook.Worksheets("Sample generator").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sample generator").Sort.SortFields.Add Key:=Range( _
"X4"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("Sample generator").Sort
.SetRange Range(myrange2)
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Thanks!
The way you have written it:
Sub Sort()
Dim myrange1 As String
Dim myrange2 As String
myrange1 = A1
myrange2 = a2
A1 and a2 are variables. And below in your code Range(myrange1).Select, they are probably intended to be strings, as far as you are mentioning here "ranges in A1 and A2 separately".
Thus, try something like this:
myrange1 = "A1"
myrange2 = "a2"
Then Range(myrange1).Select would run quite well.
In general, read these two to make your code a bit better:
MSDN Option Explicit
How to avoid using Select in Excel VBA
And then try to refactor the whole code.
In A1 you have a formula that creates the string "X1:X2"; in A2 you have a formula that creates the string "Y1:Y2".
You want to sort X1:X2 in an ascending manner then sort the range Y1:Y2 in an ascending manner.
Option Explicit
Sub mySort()
Dim myrange1 As String, myrange2 As String
With ActiveWorkbook.Worksheets("Sample generator")
myrange1 = .Cells(1, "A").Value2
myrange2 = .Cells(2, "A").Value2
With .Range(myrange1)
.Cells.Sort Key1:=.Cells(1), Order1:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlNo
End With
With .Range(myrange2)
.Cells.Sort Key1:=.Cells(1), Order1:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlNo
End With
End With
End Sub
I would like to sort Columns E though "lastColumn" in ascending order.
The values to be used for sorting are in Row 14.
The data set is located in cells E8 to "lastColumn" "lastRow".
Below is what I have thus far, but I am getting an error that the reference is not valid. I'm guessing I am not using &lastRow& correctly, let alone trying to plug in the value for "lastColumn".
I am using lastColumn and lastRow as a means to ignore blank cells.
Sub SortColumns()
Dim lastColumn As Long
Dim lastRow As Long
lastColumn = Sheet1.Cells(8, Columns.Count).End(xlToLeft).Column
lastRow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Row
ActiveWorkbook.ActiveSheet.Sort.SortFields.Clear
ActiveWorkbook.ActiveSheet.Sort.SortFields.Add Key:=Range( _
"E14:Z" & lastRow&), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.ActiveSheet.Sort
.SetRange Range("E8:I" & lastRow)
.Header = xlGuess
.MatchCase = False
.Orientation = xlLeftToRight
.SortMethod = xlPinYin
.Apply
End With
End Sub
I think you only had a small mistake. I added a little more code as you should always be specific on which workbook and on which sheet you are working. Try this:
Dim lastColumn As Long
Dim lastRow As Long
Dim Sht1 As Worksheet
Sht1 = ActiveWorkbook.Sheets("Sheet1")
lastColumn = Sht1.Cells(8, Sht1.Columns.Count).End(xlToLeft).Column
lastRow = Sht1.Cells(Sht1.Rows.Count, 1).End(xlUp).Row
Sht1.Sort.SortFields.Clear
Sht1.Sort.SortFields.Add Key:=Range( _
"E14:Z" & lastRow), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With Sht1.Sort
.SetRange Range("E8:I" & lastRow)
.Header = xlGuess
.MatchCase = False
.Orientation = xlLeftToRight
.SortMethod = xlPinYin
.Apply
End With
EDIT: I just noticed the VBA script isn't working at all, it looks like it is just sorting by the first column as I am getting some funny results :S?
I am using the following VBA to sort by all columns on the sheet.
Sub SortVariableColumns()
Dim strLastCol As String
Dim lngLastCol As Long
Dim sht As Worksheet
Set sht = ActiveSheet
With ActiveSheet
lngLastCol = sht.Cells.Find("*", SearchOrder:=xlByColumns, LookIn:=xlValues, SearchDirection:=xlPrevious).Column
strLastCol = Split(sht.Cells(1, lngLastCol).Address, "$")(1)
sht.Columns("A:" & strLastCol).Select
sht.Sort.SortFields.Clear
sht.Sort.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal ', Header:=xlYes
End With
With sht.Sort
.SetRange Columns("A:" & strLastCol)
.Header = xlYes
.MatchCase = True
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range("A1").Select
End Sub
However, it isn't matching case for some reason. The sort works for everything but the case of the words.
Also, is there anyway to make this then move onto the next sheet (i.e. if I selected activeworksheets) - I tried using
Dim sht As Worksheet
For Each ws In ActiveWindow.SelectedSheets
this but kept failing, I guess it has something to do with having to reset the IngLastCOl/StrLastCol holding from the first part of the VBA?
Many thanks.
What's with this as well?
Dim sht As Worksheet
For Each ws In ActiveWindow.SelectedSheets
Where have you defined ws variable? I am not suprised if this code fails at every line or never run at all. These are some fundamental issues.
#boncoDigo
I think I mispasted the code - the code wasn't actually failing on anything related to that! Sorry.
This can now be closed. I have worked out how to do it.
For those interested, this is the code that I used (can be easily amended to loop through sheets):
Sub SortVariableColumns()
Dim finalcolumn As Integer
Dim FinalRow As Integer
Dim sht As Worksheet
Set sht = ActiveSheet
sht.Sort.SortFields.Clear
With ActiveSheet
finalcolumn = Cells(1, Application.Columns.Count).End(xlToLeft).Column
FinalRow = Cells(Application.Rows.Count, 2).End(xlUp).Row
For N = 1 To finalcolumn Step 1
sht.Sort.SortFields.Add Key:=Range(Cells(2, N), Cells(FinalRow, N)), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
Next N
End With
With sht.Sort
.SetRange Range(Cells(1, 1), Cells(FinalRow, finalcolumn))
.Header = xlYes
.MatchCase = True
.Orientation = xlTopToBottom
.Apply
End With
End Sub
It's been a while since I have used VBA on Excel.
I want to alphabetize the contents of each column on the sheet.
This is what I have:
Range("A1").Select
Range("A1:A19").Select
ActiveWorkbook.Worksheets("Sheet2").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet2").Sort.SortFields.Add Key:=Range("A1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet2").Sort
.SetRange Range("A1:A19")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range("B1").Select
End Sub
How can I make this into a for loop that keeps going as long as the range is active?
Like this?
Option Explicit
Sub sample()
Dim i As Long
With Sheets("Sheet1")
For i = 1 To .UsedRange.Columns.Count
.Columns(i).Sort Key1:=.Cells(1, i), Order1:=xlAscending, _
Header:=xlGuess, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
Next i
End With
End Sub
Here you go. This code assumes your data is laid out in some type of table format. Also, it assumes you want the entire column sorted (including blanks and such). If you want to make the range more specific or just set it with a hard reference adjust the code where I commented.
Sub sortRange()
Dim wks As Worksheet
Dim loopRange As Range, sortRange As Range
Set wks = Worksheets("Sheet1")
With wks
'can change the range to be looped, but if you do, only include 1 row of the range
Set loopRange = Intersect(.UsedRange, .UsedRange.Rows(1))
For Each cel In loopRange
Set sortRange = Intersect(cel.EntireColumn, .UsedRange)
With .Sort
.SortFields.Clear
.SortFields.Add Key:=sortRange
.SetRange sortRange
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Next
End With
End Sub