Sorting data using VBA and data in cell - vba

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

Related

Incorporate range within a cell to range formula in Excel VBA

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

excel Vba error 400 when I added sorting to the end of my macro

I Have a relatively long sub that adds data to another sheet in a bunch of columns based on where its coming from. this part of the code works perfectly, however I wanted to sort all the rows in the table up to the last row that was added. the sorting code that I added on to the end works if I hard code what cells to include in the range, but my range will grow each time the sub is run so I tried to make the range include the variable I named for the next empty row (1MaxRows).
When I do this I get an error that says "400", in the past when I have gotten this error it is because i referenced the sheet or workbook wrong, but this time I didn't change any sheet references. The section of my code that gives me this error is as follows:
Columns("A:Q").Select
ActiveWorkbook.Worksheets("Raw Data").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Raw Data").Sort.SortFields.Add Key:=range("A2:A & lMaxRows" _
), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Raw Data").Sort.SortFields.Add Key:=range("B2:B & lMaxRows" _
), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Raw Data").Sort
.SetRange range("A1:Q & lMaxRows")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
I have tried changing the range codes in a handful of ways but I always either get an overflow error or a 400 error.
Thank you for the help.
You should qualify your Range calls with the correct worksheet, and you also have quotes in the wrong place in your addresses. For example:
Dim ws As Worksheet
Set ws = ActiveWorkbook.Worksheets("Raw Data")
With ws.Sort.SortFields
.Clear
.Add Key:=ws.Range("A2:A" & lMaxRows), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.Add Key:=ws.Range("B2:B" & lMaxRows), SortOn:=xlSortOnValues, _
Order:=xlDescending, DataOption:=xlSortNormal
End With
With ws.Sort
.SetRange ws.Range("A1:Q" & lMaxRows)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
I've assumed you have properly declared and assigned a value to lMaxRows (and note that it is LMAXROWS and not 1MAXROWS with a number at the start.

Sort Column by Specific Row

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

automatically sort alphabetically in 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

Last row offset within a filter

So the purpose of my macro is to add a version number to a part number. First a user will input all the data then my macro will create a new entry with that information at the bottom of the table. Then it will filter the table based on part number. Still within the filter I need it to look at the previous entry and add 1 for my current entry. For example if the previous was 01 the next would need to be 02 and so on. I am running into trouble getting my macro to run the add 1 part below is my code. I am thinking that it may not be possible within a filter or I have to write my code differently. Any insight would be awesome thanks!
'Update version number
Sheets("New Version ").Select
part = Range("B4").Value
Sheets("PN_List").Select
ActiveSheet.Range("$A$1:$K$3000").AutoFilter Field:=1, Criteria1:=part
ActiveWorkbook.Worksheets("PN_List").AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.Worksheets("PN_List").AutoFilter.Sort.SortFields.Add Key:= _
Range("B1:B3000"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With ActiveWorkbook.Worksheets("PN_List").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Worksheets("PN_List").Activate
With Range("B" & Rows.Count).End(xlUp).Offset(1)
.Value = "0" & .Offset(-1).Value + 1
End With
Let's re-write your code a bit.
Dim wsNewVersion = Thiwworkbook.Sheets("New Version")
Dim wsPNList = Thiwworkbook.Sheets("PN_List")
part = wsNewVersion.Range("B4").Value
wsPNList.Range("A1:K3000").AutoFilter Field:= 1, Criteria1:=part
wsPNList.AutoFilter.Sort.SortFields.Clear
wsPNList.AutoFilter.Sort.SortFields.Add Key:= _
wsPNList.Range("B1:B3000"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With wsPNList.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'~~> Below code is what you need i guess
Dim myrng As Range, lrow As Long
Dim myadd
'~~> Get the Range Address of the visible cells only
lrow = wsPNList.Range("A" & Rows.Count).End(xlUp).Row
Set myrng = wsPNList.Range("B1", Range("B" & lrow)).Offset(1, 0).Resize(lrow - 1).SpecialCells(xlCellTypeVisible)
'~~> pass addresses in array
myadd = Split(myrng.Address, ",")
'~~> Now you know the address, you can assign the value
With wsPNList
.Range(myadd(UBound(myadd))).Value = Range(myadd(UBound(myadd) - 1)).Value + 1
End With
Hope this is what you need.
I believe it is :) but who knows.
My guess is your cell is formatted as "General"
Right-click the cell, go to Format Cells. Change the Category to "text"
or, if you want it done within VBA, add this:
.Value = "0" & .Offset(-1).Value + 1
.Style = "Text"
Per request:
'Update version number
Sheets("New Version ").Select
part = Range("B4").Value
Sheets("PN_List").Select
ActiveSheet.Range("$A$1:$K$3000").AutoFilter Field:=1, Criteria1:=part
ActiveWorkbook.Worksheets("PN_List").AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.Worksheets("PN_List").AutoFilter.Sort.SortFields.Add Key:= _
Range("B1:B3000"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With ActiveWorkbook.Worksheets("PN_List").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Worksheets("PN_List").Activate
With Range("B" & Rows.Count).End(xlUp).Offset(1)
' following line was added to set text format in the target cell
.NumberFormat = "#"
.Value = "0" & .Offset(-1).Value + 1
End With