automatically sort alphabetically in vba - vba

I want to sort info on my sheet according to their last name (which is column 1). there's a form control button on the sheet that filters the info in accordance to the name of the button. everytime each of these form control buttons are clicked, i want to sort the info alphabetically. so i've used the record on macro to see what excel does to get familiar with it but i'm quite stuck... the problem is the r and countA it gives me an error of type mismatch
in total i have 17 columns (A to Q - but i don't want to really set a range to the columns, just in case i add more columns later) that contains information related to the last name which is column 1 and starts from row 3
Sub btnPrinceRupert()
Dim ws As Worksheet
Dim r As Range
Set r = ws.Cells(2, 1)
Set ws = Worksheets("Master")
Call filterMyTable(xPrinceRupert)
Call changeTitle("PrinceRupert")
r.Select
ws.Sort.SortFields.Clear
ws.Sort.SortFields.Add Key:=r, _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.sort
.SetRange (WorksheetFunction.CountA(Range("A:A")))
'essentially, i want the range to be up to the last entry of the table
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub

For the first issue, you need to set the ws before set the r value;
and the Second issue, the result of WorksheetFunction.CountA(Range("A:A")) is a number, not Range. so the code should write like this:
Sub btnPrinceRupert()
Dim ws As Worksheet
Dim r As Range
Set ws = Worksheets("Master")
Set r = ws.Cells(2, 1)
Call filterMyTable(xPrinceRupert)
Call changeTitle("PrinceRupert")
r.Select
ws.Sort.SortFields.Clear
ws.Sort.SortFields.Add Key:=r, _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.sort
.SetRange (Range("1:" & WorksheetFunction.CountA(Range("A:A")))
'essentially, i want the range to be up to the last entry of the table
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub

Related

VBA sorting not working properly

This challenge came about following an answer to this question:
Excel VBA Sorting
I used the code provided as one of the answers there and attempted to edit it to my situation
I need to sort on column A, header in A1, A to Z - whilst maintaining row integrity, i.e. the row values follow the sorted cells
Here is my attempted code edit, but I've clearly not edited it properly because the column A values are not sorted alphabetically as I'd hoped - can someone please assist?
With ws_catalogue
'''''''''''''''''''''''''''''''''''''''''''
'Get range from B1 to last cell on sheet. '
'''''''''''''''''''''''''''''''''''''''''''
Set myRange = .Range(.Cells(1, 1), .Cells(.Cells.Find("*", , , , 1, 2).Row, .Cells.Find("*", , , , 2, 2).Column))
myRange.Select
With .Sort
.SortFields.Clear
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'As using late binding Access won't understand Excel values so: '
'xlSortOnValues = 0 xlYes = 1 '
'xlAscending = 1 xlTopToBottom = 1 '
'xlSortNormal = 0 xlPinYin = 1 '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
.SortFields.Add _
Key:=myRange.Offset(, 6).Resize(, 1), _
SortOn:=0, _
Order:=1, _
DataOption:=0
.SetRange myRange
.Header = 1
.MatchCase = False
.Orientation = 1
.SortMethod = 1
.Apply
End With
End With
If you want column A to be sorted, you need to include it on myRange. Currently you have
ws_catalogue.Sort.SetRange = myRange
Where myRange is from B1 to the bottom of the data (it does not include column A).
Additionally, if you want to order column A, you need to add something like this
.SortFields.Add _
Key:=myRange.Offset(0,0) _
SortOn:=0, _
Order:=1, _
DataOption:=0
#Xabier has you taken care of but a few other considerations, sorry this code is from another similar answer but it defines the worksheet, and the column names for easier reading code. I will skip the Dims and go to the meat of it, this was for a 3 column sort of unknown or changing row quantity. The example simply shows setting up for the range definition using the rows and columns and Cells to define the range. I stopped the code at the sort, the rest of the code generates a single email for each person with the dept names listed in the body of the email, not relevant to this question. Maybe another way to think about it. You can see the use of the sort key.
'set worksheet to work on as active (selected sheet)
Set emailWS = ThisWorkbook.ActiveSheet
startRow = 2 ' starting row
nameCol = 1 'col of names, can also do nameCol = emailWS.Range("A1").Column
deptCol = 3 'col of depts, can also do deptCol = emailWS.Range("A3").Column
'** Advantage of the optional way is if you have many columns and you don't want to count them
'find the last row with a name in it from the name column
lastRow = emailWS.Cells(emailWS.Rows.Count, nameCol).End(xlUp).Row
'sort the data first before going through the email process using Range sort and a key
'assumes these are the only columns 1 (nameCol) thru 3 (deptCol) to sort
'assumes you are sorting based on col 1 (nameCol)
emailWS.Range(Cells(startRow, nameCol), Cells(lastRow, deptCol)).Sort _
key1:=emailWS.Range(Cells(startRow, nameCol), Cells(lastRow, nameCol))
Cheers,
WWC
If you want to sort by values on Column A, in ascending order, then the following will do that taking the full sheet into consideration:
Sub sortColumnA()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
If ws.AutoFilterMode = False Then ws.Cells.AutoFilter
ws.AutoFilter.Sort.SortFields.Clear
ws.AutoFilter.Sort.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ws.Cells.AutoFilter
End Sub
UPDATE:
If you only want to sort a specific range then something like below should work too:
Sub sortColumnA()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
If ws.AutoFilterMode = False Then ws.Range("A1:Z1").AutoFilter
ws.AutoFilter.Sort.SortFields.Clear
ws.AutoFilter.Sort.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ws.Range("A1:Z1").AutoFilter
End Sub

Sorting data using VBA and data in cell

I'm quite new to VBA and macros, and was looking for a bit of help sorting data using a macro. I've recorded doing what I was, and it has produced this:
Macro1 Macro
Range("A19:L28").Select
ActiveWorkbook.Worksheets("EuropeanStocks").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("EuropeanStocks").Sort.SortFields.Add Key:=Range( _
"h20:h28"), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("EuropeanStocks").Sort
.SetRange Range("A19:L28")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
My question is how do I make is so that the sort range is defined by the data in a cell. For this example with the sort range of h20:h28, the 20 and 28 parts would be constant, and I'd have a cell in the worksheet
E.g A1, which contains the letter of the column that needs to be sorted, E.g. "i","j", etc..
How would I make it so A1 was read into the sort range?
See the code below. You need to place the value in Range("A1") into a variable and then set your range in the code with that variable.
Dim ws As Worksheet, c As String, rSort As Range, rData As Range
ws = Sheets("EuropeanStock")
With ws
c = .Range("A1").Value
Set rData = .Range("A19:L28")
Set rSort = .Range(c & "20:" & c & "28")
With rData.Sort
With .SortFields
.Clear
.Add Key:=rSort, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
End With
.SetRange rData
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
The most versatile way would be to define a named range for the range you want to sort (or the range containing the range you want to sort), but for this simple requirement, you can simply wrap a Range call to the cell containing the sort range (e.g. A1) in another Range call, thus obtaining the desired range. E.g.:
.SetRange Range(Range("A1"))
EDIT: This assumes that A1 contains a full range reference (e.g. it contains "A19:L28"). If you want to construct the target range from other cells partially, one solution could be to construct the range reference, for example:
.SetRange Range(Range("A1") & "19" & ":" & Range("A2") & "28")
Just place the columns that you want to sort in A1, and separate them with a slash / (i.e. a/f/h/s)
This will sort all of them one by one :
Dim NewRange As String, _
DataRange As String, _
Sp() As String
Sp = Split(Range("A1"), "/")
With ActiveWorkbook.Worksheets("EuropeanStocks")
For i = LBound(Sp) To UBound(Sp)
NewRange = Sp(i) & "19:" & Sp(i) & "28"
DataRange = Sp(i) & "20:" & Sp(i) & "28"
With .Sort
.SortFields.Clear
.SortFields.Add _
Key:=Range(DataRange), _
SortOn:=xlSortOnValues, _
Order:=xlDescending, _
DataOption:=xlSortNormal
.SetRange Range(NewRange)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Next i
End With

VBA code not sorting by CASE - also can't apply to multiple sheets

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

Combining two VBA tasks

I'm trying to combine two functions. I have a VBA script which goes through a set range and sorts all the text column by column alphabetically.
Sub SortIndividualRows()
' Sorts rows within a list from A-Z
' Run Clean all first to avoid sorting blanks
' Set maximum range to avoid sorting too many rows
Dim rngFirstRow As Range
Dim rng As Range
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = ActiveSheet
Set rngFirstRow = ws.Range("A1:NS1")
For Each rng In rngFirstRow
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=rng, Order:=xlAscending
'assuming there are no blank cells..
.SetRange ws.Range(rng, rng.Range("A87").End(xlUp))
.Header = xlYes
.MatchCase = False
.Apply
End With
Next rng
Application.ScreenUpdating = True
End Sub
I'd like to combine this with a script to then sort each column by color. I recorded a macro when I sorted manually and looked at the code the recording generated. I'm trying to figure out how I could take the generated code and combine it with the above function.
Sub sortColor()
'
' sortColor Macro
' Goes through a range of selected cells and sorts by color, setting green cells (matches) above those with no match (red text)
'
'
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range("F4:F88"), _
xlSortOnCellColor, xlAscending, , xlSortNormal).SortOnValue.Color = RGB(198, _
239, 206)
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("F3:F88")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Just to clarify, you want to run one module then the other straight away afterwards? or do you want the action of the second module to run each time the for loop completes?
To run one directly after the other:
Sub SortIndividualRows()
' Sorts rows within a list from A-Z
' Run Clean all first to avoid sorting blanks
' Set maximum range to avoid sorting too many rows
Dim rngFirstRow As Range
Dim rng As Range
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = ActiveSheet
Set rngFirstRow = ws.Range("A1:NS1")
For Each rng In rngFirstRow
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=rng, Order:=xlAscending
'assuming there are no blank cells..
.SetRange ws.Range(rng, rng.Range("A87").End(xlUp))
.Header = xlYes
.MatchCase = False
.Apply
End With
Next rng
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range("F4:F88"), _
xlSortOnCellColor, xlAscending, , xlSortNormal).SortOnValue.Color = RGB(198, _
239, 206)
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("F3:F88")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Application.ScreenUpdating = True
End Sub
To run the second module each time the for loop completes:
Sub SortIndividualRows()
' Sorts rows within a list from A-Z
' Run Clean all first to avoid sorting blanks
' Set maximum range to avoid sorting too many rows
Dim rngFirstRow As Range
Dim rng As Range
Dim ws As Worksheet
Application.ScreenUpdating = False
Set ws = ActiveSheet
Set rngFirstRow = ws.Range("A1:NS1")
For Each rng In rngFirstRow
With ws.Sort
.SortFields.Clear
.SortFields.Add Key:=rng, Order:=xlAscending
'assuming there are no blank cells..
.SetRange ws.Range(rng, rng.Range("A87").End(xlUp))
.Header = xlYes
.MatchCase = False
.Apply
End With
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range("F4:F88"), _
xlSortOnCellColor, xlAscending, , xlSortNormal).SortOnValue.Color = RGB(198, _
239, 206)
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("F3:F88")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Next rng
Application.ScreenUpdating = True
End Sub

Iteration in Excel VBA

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