Creating Macro button with multiple functions? - vba

I am trying to sort my excel sheet by first and last name and I was wondering if it was possible for me to assign multiple macros to one button? Let's say I click once, it sorts by first name; click again and it sorts by last name. Is this possible? I asked as I couldn't find similar questions.
Here's my code
First Name
Columns ("D:D").Select
ActiveWorkbook.Worksheets(Sheet1") .Sort.SortFields.clear
ActiveWorkbook.Worksheets(Sheet1") .Sort.SortFields.Add Key:=Range("D1"),
Sorton::x=SortOnValues, Order:=xlDesending, DataOption:=xlSortNormal
with ActiveWorkbook.Worksheets("sheet1") .Sort
.SetRange Range("A1:K505")
Header = X1No
.MatchCase = False
.Orientation = x1TopToBottom
.SortMethod = x1PinYin
.Apply
End With
ActiveWindow.SmallScroll Down:=-495
End Sub
Obviously the other code is similar but with descending instead of ascending.

You can just set a global variable for the state and toggle it to have the macro bound to the button do different stuff. (this is assuming you want the function of the button to toggle after every click)
' global state variable
Dim State As Boolean
Private Sub Workbook_Open()
' initialize state
State = True
End Sub
Sub mymacro()
If State Then
' do stuff 1
Else
' do stuff 2
End If
' toggle state
State = Not State
End Sub

One button can only run one macro. However, you might let the macro do different things depending upon the current selection. For example, if the user selects a cell in the Name column the sort is done on the name, in ascending order, and if the selection is in another column it is done on the first name, in descending order.
The code below sets both the sort key and the sort order relative to the selection. Therefore you don't need two different macros.
Sub SortByColumn()
Dim Ws As Worksheet
Dim Clm As Long
Dim SortOrder As XlSortOrder
With Selection
Set Ws = .Worksheet
Clm = .Column
If Clm = 4 Then ' column #4 = column D
SortOrder = xlDescending
Else
' sort on column 1 by default
Clm = 1 ' column #1 = column A
SortOrder = xlAscending
End If
End With
With Ws.Sort
With .SortFields
.Clear
.Add Key:=Ws.Cells(1, Clm), _
Sorton:=xlSortOnValues, _
Order:=SortOrder, _
DataOption:=xlSortNormal
End With
.SetRange Ws.Range("A1:K505")
.Header = X1No
.MatchCase = False
.Orientation = x1TopToBottom
.SortMethod = x1PinYin
.Apply
End With
ActiveWindow.SmallScroll Down:=-495
End Sub
Note that the sorting action doesn't require anything to be selected.

Related

AutoFilter.Sort.SortFields.Clear is not clearing the sort fields

I have VBA code that uses the columns (values in the Rows section) of a Pivot table on one worksheet to sort another worksheet's data and then summarize that data. Whenever the Pivot table changes the summarized data is recalculated by users pushing a command button. After I run the AutoFilter.Sort.SortFields.Clear I'm still getting 13 sorts exist. These are combinations of the previous sorts. This continues to build up until I get a XLSM file is corrupt message.
Function SortTab(pSheet As String, pCol As String) As Boolean
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Sort entire tab by 1 to 5 columns
'
'Code examples from recording a Macro when sorting
' ActiveWorkbook.Worksheets("Data").AutoFilter.Sort.SortFields.Add Key:=Range("I2:I1019"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
' ActiveWorkbook.Worksheets("Data").AutoFilter.Sort.SortFields.Add Key:=Range("J2:J1019"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
'
'Parameters:
' pSheet Sheet to find range Example: Data
' pCol Last column on sheet Example: BC100
'
'Global Variables:
' gRange UsedRange for current sheet Example: A1:BC100
' gPivotCols Array of column names to Sort Example: gPivotCols(1) = 5 for "Dept", gPivotCols(2) = 4 for "Company"
' gColSort Last column in the sort Example: 4 for the Company column being the 4th column in the data sheet
'gColMax Max # of Sort Columns is 5
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
On Error GoTo Err_SortTab
Dim i As Integer
'Remove all Fiters & Sorts
Worksheets(pSheet).Activate 'Select sheet
Worksheets(pSheet).AutoFilterMode = False 'Turn AutoFilter off
Worksheets(pSheet).UsedRange.AutoFilter 'Turn AutoFilter on
Worksheets(pSheet).AutoFilter.Sort.SortFields.Clear 'Clear any Sorts
'Code inserted to find out how many sort columns exist after a AutoFilter.Sort.SortFields.Clear
'Currently returning a value of 13 sorts
i = ExistingSorts()
If i > 0 Then
MsgBox i & " existing sorts still exist", vbCritical, "Error"
SortTab = False
Exit Function
End If
With ActiveSheet.Sort
.Header = xlYes 'Tab has Headers
.MatchCase = False 'Not case sensitive
.Orientation = xlTopToBottom 'Sort Top to Bottom
.SetRange Range(gRange) 'Complete range on Data tab to sort example: A1:BC100
For i = 1 To gColMax 'Loop throuh column heading in the Pivot table
If gPivotCols(i) = 0 Then 'Check for less than 5 columns
Exit For
End If
gColSort = gPivotCols(i) 'Set the last column in the Sort
.SortFields.Add Key:=Range(gRange).Columns(gColSort), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal 'Add sort column
Next i
.Apply
End With
Exit_SortTab:
SortTab = True
Exit Function
Err_SortTab:
If Application.UserName = "Murf" Then
MsgBox Err.Description, vbOKOnly, "Error #: " & Err.Number
Stop
Resume
End If
End Function
Function ExistingSorts() As Integer
'''''''''''''''''''''''''''''''''''''''''''''''''''
' Copied from internet
' Count existing sorts
'''''''''''''''''''''''''''''''''''''''''''''''''''
On Error Resume Next
Dim S As Sort
Dim SF As SortField
Set S = ActiveSheet.Sort
ExistingSorts = S.SortFields.Count
End Function
I've tried several different variations of
Worksheets(pSheet).AutoFilter.Sort.SortFields.Clear
Activesheet.AutoFilter.Sort.SortFields.Clear
with Activesheet
.AutoFilter.Sort.SortFields.Clear
The manual sorts created on the data tab disappear (arrows go away) but the actual data is sorted by whatever string of columns is already entered.

Table inserted new row still at the top even after sorting (VBA/Excel)

Just interrupting with a small sorting problem I have with a table:
I have a table in which I list some European government bonds:
Only the ISIN is necessary: COUNTRY and MATURITY are retrieved from a Bloomberg API
Say Italy issue a new BOND with Isin code : IT0005402117
I tried a VBA Macro that insert a new line with ISIN = IT0005402117
Then sort the table by 1st: COUNTRY, then 2nd: MATURITY
Here's the code:
Private Sub ButtonAddBondOK_Click()
FormAddBond.Hide
Dim Isin As String
'Declare Table
Dim MyTable As ListObject
Set MyTable = Range("BondBase").ListObject
Isin = FormAddBond.TextBoxIsin.Value
'Test that Isin doesn't exists
Dim r As Range, IsItThere As Range
Set r = MyTable.Range
Set IsItThere = r.Find(What:=Isin, After:=r(1))
If Not IsItThere Is Nothing Then
MsgBox "ISIN already exist, please check."
'Cleaning form
Unload FormAddBond
Exit Sub
End If
'Inserting new row
Dim NewRow As ListRow
Dim IsinCol, FutCol As Long
IsinCol = MyTable.ListColumns("Isin").Range.Column
Set NewRow = MyTable.ListRows.Add(AlwaysInsert:=True)
With NewRow
.Range(IsinCol).Value = Isin
End With
'waiting 3 seconds
Application.Wait (Now + TimeValue("0:00:03"))
'Sorting Table
With MyTable.Sort
.SortFields.Clear
.SortFields.Add Key:=Range("BondBase[[#ALL],[COUNTRY]]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("BondBase[[#ALL],[MATURITY]]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortTextAsNumbers
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'Cleaning form
Unload FormAddBond
End Sub
After running the code, the row is properly insert and table is properly sorted, BUT for the new row that appears at the top. this even though I added a 3 seconds wait for Bloomberg API to retrieve the values...
Result:
Any clue what I have done wrong please?

VBA sort code works for one sheet only but not multiple ones

When I run this code over multiple sheets I get a "Run-Time Error 1004:The sort reference is not valid. Make sure that it's within the data that you want to sort, and the first Sort By box isn't the same or blank":
Dim i As Long
For i = 6 To Worksheets.Count
'more code here
Dim ranged As range
Dim lRow As Long
With ThisWorkbook.Sheets(i)
lRow = .range("AJ" & .Rows.Count).End(xlUp).Row
Set ranged = .range("AJ2:AJ" & lRow)
.Sort.SortFields.Add Key:=ranged, _
SortOn:=xlSortOnValues, _
Order:=xlDescending, _
DataOption:=xlSortNormal
With .Sort
.SetRange ranged
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
'more code here
next i
I'm not sure why this doesn't work, but what is particularly baffling is that when I try to run it on one sheet only by changing With ThisWorkbook.Sheets(i) to With ThisWorkbook.Sheets("Sheetname") it works fine, but when I put it into the above structure to run over multiple ones it doesn't.The idea is to reverse the order of column AJ starting from AJ2 to the last row with data in it and the length of AJ is different in different sheets. Any ideas?
The way you are going about getting your sheetnames is the problem.
You are starting to iterate through i from 6 to Worksheets.count.. With this, assuming you have 10 sheets, you will only iterate through 4 i's before being complete.
The main issue though is that you probably don't have sheetnames that are Sheets(i). i is a variable here and furthermore, it isn't a string. So you need to have a string at the other end of the variable you are placing inside Sheets().
I think what you are trying to accomplish is using a LIST of sheet names that are Strings. Using the variable i as a Long or Integer to iterate through them. "i" being the NUMBER and name(i) being a String.
'This example assumes you have 6 sheets. Declare this at the top with your initial variable declarations.
Dim name(1 to 6) As String
name(1) = "Sheet1"
name(2) = "TotalSales"
name(3) = "MonthlyRevenue"
name(4) = "Sheet 4 Name"
name(5) = "Whatever This sheet is called"
name(6) = "Last Sheet Name"
or whatever your sheets are named. Then when you call Sheets you will use something more like this.
For i = 1 to 6
'YOUR CODE THAT YOU ALREADY ENTERED THAT WORKS WHEN THE SHEET NAME IS CORRECT
With ThisWorkbook.Sheets(name(i))
Next i

EXCEL VBA Sort after Populating Data

I am new to VBA, and excel macros, but not basic programming. I have a few dozen excel files, that I am taking data from, cleaning it, and populating it into one file. After the data is populated, I'd like to sort it according to Column A. After an 2 hours of playing with it, I just recorded a macro and cut and pasted it into my ButtonCall sub. But I'd like to know why its working and why the solutions I found here, and online would not work for me...
Why does this simple code NOT work:
Set q = ThisWorkbook.Worksheets(2)
LastRow = q.UsedRange.rows.Count 'q.UsedRange.Row ' - 1 + q.UsedRange.rows.Count
LastCol = q.UsedRange.Columns.Count
q.Range("A6:AAA" & LastRow).Sort Key:=q.Columns("A"), Order:=xlDescending
While this modified recorded Macro does?
Set q = ThisWorkbook.Worksheets(2)
LastRow = q.UsedRange.rows.Count 'q.UsedRange.Row ' - 1 + q.UsedRange.rows.Count
LastCol = q.UsedRange.Columns.Count
q.Sort.SortFields.Clear
q.Sort.SortFields.Add Key:=Range("A6:A" & LastRow), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With q.Sort
.SetRange Range("A6:AAA" & LastRow)
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Any thoughts? Thanks.
Your code is using the range.sort method, while the original code is employing the sort object - two different things.
This code will sort "A6" to end of data by column A, using the Range.Sort method.
Sub MySort()
Dim q As Worksheet
Dim r As Range
Set q = ThisWorkbook.Worksheets(2)
' specify data range from "A6" to end of data
Set r = q.Range("A6", q.Cells.SpecialCells(xlCellTypeLastCell))
' Header:=xlNo assumes A6 row is included in data to be sorted
r.Sort key1:=r(1, 1), Order1:=xlDescending, Header:=xlNo
End Sub

Sort rows by a specific column containing numbers

How to sort rows by a column containing numbers in ascending or descending order?
I know how to sort using Filters and Using Sort function in VBA. But it sorts in alphabetical order only not by numbers.
This is so far I have done.But still the sorting is coming alphabetically.
Sub sortdata()
Dim LastRow As Integer
NoOfRows = Sheets("RawData").Range("A" & Rows.Count).End(xlUp).Row
Sheets("RawData").Rows("2:" & NoOfRows).NumberFormat = "0"
Sheets("RawData").Sort.SortFields.Add Key:=Range("A1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Sheets("RawData").Sort
.SetRange Range("A1:B" & NoOfRows)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
I prefer the Range.Sort method:
[EDIT 2]:
I have added the .TextToColumns line to programmatically address the numbers stored as text issue
Sub sortdata()
Dim ws As Worksheet
Set ws = Sheets("RawData")
With ws.Range("A1:B" & ws.Cells(Rows.Count, "A").End(xlUp).Row)
Intersect(.Cells, ws.Columns("A")).TextToColumns
.Sort Intersect(.Cells, ws.Columns("A")), xlAscending, Header:=xlGuess
End With
End Sub
[EDIT]:
After reading asker's comment:
I will provide an example . If the column A contains this
values:1,2,55,12,14,5343,22222,9 Then after sorting using filter or
inbuilt sort method. The values are sorted as
follows:1,12,14,2,22222,5343,9. But I need the result as follows:
1,2,9,12,14,5334,22222. Is there any in-built function for this?
The problem is that your numbers are stored as text. You'll need to convert them to numbers.
Select column A -> Data -> Text to Columns -> Finish
Now the numbers should sort correctly.