VBA Function For Excel
VBA Function For Excel
In Excel 2007 (and Excel 2010), the Record Marco menu option is under the
View ribbon. Click on the Macros button towards at the right end of the
ribbon and then click Record Macro. A pop-up box will ask you to enter the
details of the macro. If you are just starting to record your own macro, you
can simply click on the ok button. After this you can carry out the steps
that you want like entering numbers, formulas, formatting cells, inserting
charts etc etc. Once you are done you can stop recording the macro by
clicking the Stop Recording option under the Macro button.
Alternatively, you can begin and stop recording a macro in Excel 2010 (and
2007) by clicking on the icon located at the bottom-left of the application
window, right next to where it is labelled Ready.
You can now view the macro that you just recorded by clicking the View
Macros option under the Macros button. Alternatively you can press
Alt+F8 as the shortcut key. You can give a descriptive name to the macro or
assign a shortcut key so that by pressing that key combination, the macro
will begin execution.
You can view the macro you just recorded by clicking on Tools option in the
menubar and then clicking on Macro and then choosing the Macros
option. Alternatively you can press Alt+F8 as the shortcut key. You can record
a complete set of macros and then run them one after another to get a the
steps related to a task accomplished at one go.
How to edit a macro
Congratulations! You have now written your first macro. The logical next step
is to check out the code that was generated by the macro. The code
generated by the application is in a language called VBA (Visual Basic for
Applications). To view the code, we will need to open the VBA Editor (also
referred to as the VBA IDE or VBA Integrated Development Environment). You
can use the shortcut key Alt+F11 to open up the IDE or simply use the
following menu options.
Editing a macro in Excel 2010 and 2007
You can turn on the Developer tab by clicking on the Office button located
at the top left corner of the Excel workbook. Click on the Excel Options
button and then turn on Show developer tab in the Ribbon checkbox the
under the Popular menu option.
Having done that, you can now use the Developer tab to access the VBA
Editor by pressing the Visual Basic button.
You may want to keep just one workbook open to avoid confusion while
opening the VBA editor.
Once youve opened up the VBA IDE, heres how it would look like.
This is the point now where you can begin to edit the code that the macro
generated while you were recording it in Excel. For example, you have to
automate a task where a certain column is populated with numbers starting
from 1 to 10. You recorded the first three steps so that you now have the
code that can enter the numbers 1, 2 and 3 in the first three cells of that
column. You would now like to write the next seven steps.
If you looked at the code given above, you would have guessed that there is
a structure to the code. The application first moves the cursor to the cell by
using an instruction like Range(A1).Select and then editing its contents by
something like ActiveCell.FormulaR1C1 = 1. So for the remaining steps, we
can simply repeat these steps by providing the address of the new cell and
then in the next step providing the value that we would like to enter. For
example if you wanted to enter 4 in cell A4, you would write:
1 Range("A4").Select
2 ActiveCell.FormulaR1C1 = "4"
and then repeat the step for the all the other values that you would like to
enter.
Once you are done editing, save the workbook. You can play back this marco
either by pressing F5 while still within the main body of the macro or going
back to the excel workbook and using the Run button after selecting the
required macro from the Macro list window shown above.
Please take a few minutes to carefully read through the code that the macro
has generated. If you are a beginner, a few minutes invested in reading
through the code and yield tremendous results and will go a long way on
familiarizing you with commonly used objects in VBA. (Please bear in mind
that this example is only for illustration. There are better and faster ways of
achieving the same results, some of which we will cover in the sections
below.)
Improving speed to execution of an Excel Macro
So far so good. Lets move on to learning some tricks that can help you
speed up the performance of your macros VBA code. Lets take the example
of the code snippet shown above. On a high-end computer the above code
will probably run faster than you can click an eyelid but suppose we we had
to run the same code over and over again for 50,000 cells (or iterations).
That would take some time. If the macro that you wrote runs into hundreds
of lines of code, you can improve the speed of execution by cutting down on
all the other processes that are not required when the code is executing.
Using Application.ScreenUpdating command
The first trick is to stop Excel from updating the screen as the code executes.
That helps Excel save all the processing power executing the code and
update the screen with fresh value only after the code has ended executing.
To achieve this, we can write a statement at the beginning of the code to
turn off screen updation and turn it right back on at the end of the code.
1
2
3
4
5
6
7
8
9
10
Sub Macro1()
Application.ScreenUpdating = False
Range("A1").Select
ActiveCell.FormulaR1C1 = "1"
Range("A2").Select
ActiveCell.FormulaR1C1 = "2"
Range("A3").Select
ActiveCell.FormulaR1C1 = "3"
Application.ScreenUpdating = True
End Sub
Sub Macro1()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Range("A1").Select
ActiveCell.FormulaR1C1 = "1"
Range("A2").Select
ActiveCell.FormulaR1C1 = "2"
Range("A3").Select
ActiveCell.FormulaR1C1 = "3"
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Be careful to turn on this option back on at the end otherwise it will remain
turned off even when the code has fully executed. If you let it turned off
withing the code, you can change it to automatic by using the Tools ->
Options -> Calculation tab from the menu as shown below:
Sub Macro1()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Range("A1").Value = 1
Range("A2").Value = 2
Range("A3").Value = 3
Range("A4").Value = 4
Range("A5").Value = 5
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
What weve done here is to simply reference a cell and then provide a value
to it without selecting it at all. This is way faster than the previous one.
4 cel.Value = counter
5 Next cel
6 End Sub
7End Sub
The final value of the a_counter in this loop is 1.
As you can see, we can use the Step n instruction to ensure that the for loop
works either forward or in reverse. By default the Step value is forward 1,
however it can be set to a number more than 1 to skip forward loops or
negative for the for loop to work in reverse.
VBA For Each In Next Loop
The For Each In Next loop has the following syntax:
1 For Each item_in_group In group_of_items
2
Do something here
3 Next item_in_group
The item_in_group here belongs to a group_of_items (smart aint I). What I
mean is that the object used as a group_of_items has to be a collection of
objects. You cant run a for each item loop on individual objects (lest
Microsoft throw the friendly run-time error 438 at you !)
The above loop moves one item at a time starting with the first item in the
collection of objects. You can use this particular for loop syntax to iterate
along sheets in a workbook, shapes in a sheet, pivot tables in a sheet or any
collection of objects in general.
Lets take the example of how you can use the for loop to iterate through all
worksheets in a workbook:
1
2
3
4
5
Sub my_for_loop3()
For Each sht In ActiveWorkbook.Worksheets
MsgBox sht.Name
Next sht
End Sub
Now lets see how we can loop through all the pivot tables in a sheet:
1
2
3
4
5
Sub my_for_loop4()
For Each pvt In ActiveSheet.PivotTables
MsgBox pvt.Name
Next pvt
End Sub
Sub my_for_loop5()
For a_counter = 0 To 5
MsgBox a_counter
If (a_counter = 3) Then Exit For
Next a_counter
End Sub
Sub my_for_loop6()
Dim j As Integer
For i = 0 To 5
b:
If (j = 3) Then GoTo a:
j=i
Next i
a:
j=4
GoTo b:
MsgBox ("Final value of j = " & j)
End Sub
What weve tried to do here is a move out of the for loop in one particular
iteration (when j = 3). What do you think is the final value of j in the above
example. 3 ? 5? Well none of them really. The loop executes endlessly and
would soon lead to overflow.
However it is possible to skip a loop in the For Loop. You can increment the
counter by 1 (or any other number) and that can cause the for loop to skip all
the loops in between. Heres an example.
1
2
3
4
5
6
Sub my_for_loop7()
For i = 0 To 5
i=i+1
MsgBox i
Next i
End Sub
However again, this is not a good coding practice and can lead to headaches
for the folks maintaining the VBA code later. Instead check if the particular
condition is to be skipped in a FOR loop, try using an IF function or even a
SELECT CASE statement.
Using a simple IF function in VBA
Heres an example of the IF function. This piece of VBA code is simply
checking whether the condition specified (i.e. 1 > 4) evaluates to TRUE or
FALSE. In this case, we have only specified the steps to be completed when
the condition evaluates to TRUE. In this case, the result will be a message
box being displayed on the screen. If the function were to evaluate to FALSE,
the VBA code will do nothing.
1
2
3
4
5
Sub IF_FUNCTION()
If 7 > 1 Then
MsgBox "7 is greater than 1"
End If
End Sub
However this form should be used only when there are no ELSE or ELSE IF
statements are needed. Lets look at what they are and how they help
enhance the IF function.
Using a IF function with ELSE in VBA
Sub IF_ELSEIF_FUNCTION()
If 1 > 4 Then
MsgBox "1 is greater than 4"
Else:
MsgBox "1 is less than 4"
End If
End Sub
in the IF and ELSEIF statements turn out to be FALSE, by default the steps
mentioned under the final ELSE: block will get executed. Please remember
that if there are multiple ELSEIF statements, the first one that evaluates to
TRUE will get executed and once completed, the code execution will move to
the END IF statement. Even if there are multiple ELSEIF conditions that
evaluate to TRUE, only the first one that evaluates to TRUE will be executed.
1
2
3
4
5
6
7
8
9
10
11
Sub IF_ELSEIF_ELSE_FUNCTION()
If < <condition_1>> Then
MsgBox "1 is greater than 4"
ElseIf < <condition_2 if condition_1 = FALSE >> Then
MsgBox "2 is greater than 4"
ElseIf < <condition_3 if condition_2 = FALSE >> Then
MsgBox "3 is greater than 4"
Else < <If_Everything_Fails>>:
MsgBox "1, 2 or 3 are lesser than 4"
End If
End Sub
Sub IF_ELSEIF_ELSE_FUNCTION()
If 1 > 4 Then
MsgBox "1 is greater than 4"
ElseIf 2 > 4 Then
MsgBox "2 is greater than 4"
ElseIf 3 > 4 Then
MsgBox "3 is greater than 4"
Else:
MsgBox "1, 2 or 3 are lesser than 4"
End If
End Sub
Sub IF_NEED_FOR_SPEED_1()
t = Timer
For i = 1 To 100000000
If 1 > 4 Then
5
6
7
8
9
10
11
OR
1
2
3
4
5
6
7
8
9
10
11
Sub IF_NEED_FOR_SPEED_2()
t = Timer
For i = 1 To 100000000
If 1 > 4 Then
ElseIf 5 > 4 Then
ElseIf 3 > 4 Then
Else:
End If
Next i
MsgBox Timer - t
End Sub
The answer is that the second one executes much faster than the first. Why?
Because the second one needs to application to go through lesser lines of
code before it finds a condition that evaluates to TRUE. Remember that the
first ELSEIF condition that if found TRUE gets executed and none of the other
conditions are evaluated, even if they were to also evaluate to TRUE. In the
first piece of the VBA code, the ELSEIF function on line 6 evaluates to TRUE
while in the second, line 5 meets the criteria. In essence, the more likely the
condition is to get evaluated to TRUE, the earlier it should be placed in the
VBA code, all else being the same
Heres a bit of VBA code to convert Text to Column which will work across
multiple columns selected together at one go.
Application.DisplayAlerts = False
If Not (TypeName(selected_range) = "Range") Then End
ReDim selected_range_individual_column(selected_range.Columns.Count - 1)
As Range
For col_count = LBound(selected_range_individual_column) To
UBound(selected_range_individual_column)
Set selected_range_individual_column(col_count) =
selected_range.Columns(col_count + 1)
'MsgBox "Value = " &
selected_range_individual_column(col_count).Cells(1, 1).Value
Next col_count
'Begin Text to Column conversion process by starting from Right and
proceeding left
For col_count = UBound(selected_range_individual_column) To
LBound(selected_range_individual_column) Step -1
If
Application.WorksheetFunction.CountIf(selected_range_individual_column(col
_count), "<>") = 0 Then GoTo next_loop:
'------------------------------------------------------------------------------------'DataType = xlDelimited or xlFixedWidth
'------------------------------------------------------------------------------------'If Data Type = xlDelimited then one has to specify the delimiting
characters
'
Change the boolean values for various delimiting characters such
as :
'
ConsecutiveDelimiter, Tab, Semicolon, Comma, Space and Other
tokens as per requirement
'If Data Type = xlFixedWidth then one has to specify the widths of the fields
using the FieldInfo Array.
'
This example specifies three widths for splitting into five columns
with each array
'
bit containing the cumulative sum of chars till the beginning of
each word
'
You will have to edit and modify (add more or delete) these values
as per need
'------------------------------------------------------------------------------------selected_range_individual_column(col_count).TextToColumns _
Destination:=selected_range.Cells(selected_range.Row,
one_to_how_many_columns * col_count + 1), _
DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=True, _
Tab:=False, _
Semicolon:=False, _
Comma:=False, _
Space:=True, _
Other:=False, _
FieldInfo:=Array( _
Array(0, 1), _
Array(3, 1), _
Array(6, 1), _
Array(12, 1), _
Array(17, 1) _
), _
TrailingMinusNumbers:=True
next_loop:
Next col_count
err_occured:
Application.DisplayAlerts = True
End Sub
Microsoft Office Excel can convert only one column at a time. The range can
be many rows tall but no more than one column wide. Tray again by selecting
cells in one column only.
In the code above you can change:
one_to_how_many_columns = Determines how many columns should be
used as a gap to place the (split/converted) data when two consecutive
columns are converted.
DataType = xlDelimited or xlFixedWidth (The text to column feature has two
modes Character Delimited and Fixed Width.)
TextQualifier = xlDoubleQuote or xlSingleQuote or xlNone
Tab = True or False
Semicolon = True or False
Comma = True or False
Space = True or False
TrailingMinusNumbers = True or False
ConsecutiveDelimiter = True or False
You can download a sample worksheet with a example of multiple column
text to column here or click on the button below:
Sub Delete_All_Pivot_Tables_In_Sheet()
For Each pvt In ActiveSheet.PivotTables
pvt.PivotSelect "", xlDataAndLabel, True
Selection.ClearContents
Next pvt
End Sub
5
MsgBox
6
ActiveSheet.PivotTables("PivotTable1").PivotFields("Name").PivotItems("Adri
an")
7
End Sub
8
Remove Old (ghost) Items from a Pivot Table using VBA Macro
Often times you will items show up in the list drop down of a particular field
in pivot table even though those values do not exist in the pivot table. More
likely than not, these are old items left over from the earlier data in the pivot
tables cache and still continue to appear in the table. As a good practice, if
you have large amounts of data in a pivot table and that table gets updated
with fresh data frequently, you may want to call this procedure to clean up
the pivot table.
1 Sub Remove_Old_Items()
2 For Each pvt In ActiveSheet.PivotTables
3 pvt.PivotCache.MissingItemsLimit = xlMissingItemsNone
4 pvt.PivotCache.Refresh
5 Next pvt
6 End Sub
Refresh All Pivot Tables in a Workbook using VBA Macro
The classic case of refreshing all pivot tables in a workbook in one go. A must
when you have more than a handful of pivot tables in the workbook
1
2
3
4
5
Sub Refresh_All_Pivots_1()
For Each pvt In ActiveWorkbook.PivotCaches
pvt.Refresh
Next pvt
End sub
OR
1
2
3
4
5
6
7
Sub Refresh_All_Pivots_2()
For Each sht In ActiveWorkbook.Worksheets
For Each pt In sht.PivotTables
pt.RefreshTable
Next pt
Next sht
End Sub
Sub Refresh_All_Pivots_In_Sheet()
For Each pvt In ActiveSheet.PivotTables
pvt.PivotCache.Refresh
Next pvt
End Sub
This is the simple method of expanding a pivot table so that the underlying
data is revealed. This requires that the pivot table store a copy of the
underlying data set with it for it to work well.
Extract Data (Expand) from a Pivot Table using a VBA Macro
1 Sub Extract_Data_From_Pivot()
2 For Each pvt In ActiveSheet.PivotTables
3 With pvt
4
.ColumnGrand = True
5
.RowGrand = True
6 End With
7 Set rng = pvt.DataBodyRange
8 rng.Cells(rng.Rows.Count, rng.Columns.Count).ShowDetail = True
9 Next pvt
10 End Sub
Remove or Include a Pivot Field in a Pivot Table using a VBA Macro
Often times we need to remove a particular field from the pivot table. The
following code will help you achieve it.
1
2
3
4
5
6
7
Sub Hide_Fields()
For Each pvt In ActiveSheet.PivotTables
For Each pvtfld In pvt.PivotFields
pvtfld.Orientation = xlHidden
Next pvtfld
Next pvt
End Sub
In the above code, we have tried to hide all pivot fields in a pivot table. You
may want to selectively remove fields by referring to them either by their
index values or by their names. Example:
ActiveSheet.PivotTables(PivotTable1).PivotFields(Name).Orientation =
xlHidden
To include the fields again and have them display in the pivot table, use this
code:
1
2
3
4
5
6
7
8
9
10
11
Sub Show_Fields()
For Each pvt In ActiveSheet.PivotTables
For Each pvtfld In pvt.PivotFields
'Use any of the four options listed here
'pvtfld.Orientation = xlRowField
'pvtfld.Orientation = xlColumnField
'pvtfld.Orientation = xlPageField
pvtfld.Orientation = xlDataField
Next pvtfld
Next pvt
End Sub
Hide Pivot Items of Pivot Field located in a Pivot Table using a VBA
Macro
The following code will help you turn off a field from the drop-down of a
particular field in a pivot table
1
2
3
4
5
6
7
8
9
10
Sub Hide_Items()
On Error Resume Next
For Each pvt In ActiveSheet.PivotTables
For Each pf In pvt.PivotFields
For Each pit In pf.PivotItems
pit.Visible = False
Next pit
Next pf
Next pvt
End Sub
By default, atleast one pivot item needs to be left turned if you decide to
hide items in the drop down of a field in a pivot table. Other wise you will
have excel throwing an error which says : Run-time error 1004: Unable to
set the Visible property of the PivotItem class. To ensure that we do not have
the error blocking the code during runtime, we insert the On Error Resume
Next in our code. (You may want to read more about error handling in VBA
here). To make the fields show again, simply turn them on by replacing the
pit.Visible = False statement with pit.Visible = true.
Moving and change orientation of Pivot Fields in a Pivot Table using
VBA Macro
1
2
Sub Move_Fields_Of_Pivot_Table()
For Each pvt In ActiveSheet.PivotTables
3
4
5
6
7
8
9
10
11
12
13
Reduce time taken to update a pivot table when using a VBA macro
Pivot tables can be notoriously slow when you work with large data sets in
VBA. Moving, updating and hiding items can a long time to happen. To
reduce update and response time when working with Pivot Tables in VBA, try
setting the update option to manual. Manual update can reduce the time
taken to update and work with a pivot table by around 10% for very small
tables (say 10 rows in source data) to as much as 75% in large tables (with
more than 50,000 rows in source data).
1Sub Set_Manual_Update_On
2ActiveSheet.PivotTables(1).ManualUpdate = True 'At the beginning of code
3'YOUR CODE HERE
4ActiveSheet.PivotTables(1).ManualUpdate = False 'At the end of code
5End Sub
You can test the improvement in speed by say comparing both the pieces of
VBA code shown below. The first piece of the code will run much slower than
the later.
1
2
3
4
5
6
7
8
9
10
11
12
Sub Manual_Update_Off()
t = Timer
For i = 1 To 20
On Error Resume Next
For Each pf In ActiveSheet.PivotTables(1).PivotFields
For Each pit In pf.PivotItems
pit.Visible = False
Next pit
Next pf
Next i
MsgBox Timer - t
End Sub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Sub Manual_Update_On()
t = Timer
ActiveSheet.PivotTables(1).ManualUpdate = True
For i = 1 To 20
On Error Resume Next
For Each pf In ActiveSheet.PivotTables(1).PivotFields
For Each pit In pf.PivotItems
pit.Visible = False
Next pit
Next pf
Next i
ActiveSheet.PivotTables(1).ManualUpdate = False
MsgBox Timer - t
End Sub
You can download an example of the pivot table and vba macro code
here or click on the button below: