Recode in VBA Learn To Automate Excel by P - G BLANCO
Recode in VBA Learn To Automate Excel by P - G BLANCO
BLANCO
RECODE IN VBA
USA
hollerdata.com
ISBN: 978-1-7351146-2-0
DO…LOOP ................................................................................ 19
IF…THEN ................................................................................... 21
HARDCODING ............................................................. 24
You’ll quickly learn how to write an Excel macro in VBA, how to create
variables to interact with your data. You’ll also learn how to write loops to
control your code execution, and how to iterate through your workbook
cells. This minibook will give you the knowledge you need to quickly get
started in serious VBA programming.
The goal of this minibook is to give you a full Excel macro already coded
for you to re-program. The macro calculates invoice due dates depending on
different conditions for a high volume of invoices. It moves around Excel to
perform tasks through controlled executions. Keep in mind this minibook is
not about how to calculate invoice due dates, rather, it’s about giving you
practical knowledge to jump-start you into VBA.
If you have already bought a book about VBA even better; this minibook
will reinforce and show you how to apply that knowledge. It’s packed with
simple and useful statements for automation.
This minibook comes with two companion files, an Excel template and a .txt
file containing all source code. Find the download link to access the
companion files at the very end of this minibook.
If you don’t have the DEVELOPER tab already visible, go to FILE , select
Options , then select Customize Ribbon and under Main Tabs enable
Developer as shown in Figure 1.
Figure 1.
Once the Excel file is opened, to open the Visual Basic Editor , on the ribbon
go to DEVELOPER and click in Visual Basic (located 0n the left side of
the ribbon) as shown in Figure 2.
You should see the Visual Basic Editor opened and its appearance should be
similar to Figure 4.
Figure 2.
pg. 2
In the VBE, go to Project Window and do a right click anywhere below the
tree diagram. Click Insert and select Module as per Figure 4. If the Project
Window is not visible, go to View and click on Project Explorer . The
newly created Module 1 should be visible. We’re all set to start writing VBA
code.
Figure 4.
pg. 3
If you’re new to VBA, read this part so that the later sections of this
minibook can be understood.
Sub test_macro()
Note that End Sub just appeared at the end. See Figure 6 for details.
Figure 6.
pg. 4
Sub stands for sub-procedure, which makes reference to a set of instructions.
Simply stated, Sub MacroName() sets where the macro begins and also
gives the macro a unique identifier (its name). End Sub sets where the
macro ends. All code contained in this macro needs to be written between
these two lines.
Every time you insert text into your macro with a preceding apostrophe ( ‘ ),
you insert a comment. VBA won’t execute the comments, they’ll just be
there to provide information about your macro. See Figure 6 for details.
We can make use of the SELECT method to select a specific cell in our
worksheet. We can also instruct Excel to move in a given direction and
select multiple cells.
1. In
VBE,
under
Sub
test_macro(),
type
Range("G14").Select
and select Run Macro . See Figure 7 and Figure 8 for references.
pg. 5
Figure 7.
Figure 8.
Go to your worksheet and note that cell G14 is selected. See Figure 9. Just
for fun, try selecting other cells in your workbook.
Figure 9.
pg. 6
Let’s try something else besides selecting cell G14 . We’re going to move
down to the last cell that contains data.
Range("G14").End(xlDown).Select
Run the macro and note that this time, our modified code selected the last
cell in the column. See Figures 10 and 11 for reference.
Figure 10.
Figure 11.
Let’s try something else. Let’s select the last cell below G14
that contains data, and extend our selection from G14 to that last cell.
pg. 7
Figure 12.
Figure 13.
pg. 8
In that regard, having G14 in our code by itself wouldn’t mean a thing to
Excel. Assigning an Object attribute to G14 (a Range Object attribute)
through Range() will make G14 become a reference to a cell in our
worksheet. Range is an object in Excel that can be represented by a single
cell or multiple cells.
pg. 9
Figure 14.
We’ve created two variables. Think of variables as boxes; one of them was
created to store strings and the other one to store dates or even date
functions. This is important, because if we needed to perform calculations
involving dates, we would need variables that would allow us to perform
such calculations.
After a variable exists, we can assign a value (or functions) to it. We can
write statements using the equal sign (=) to store strings in string variables.
The following statement assigns the expression Annual to variable Cycle .
Variable Cycle can store the expression Annual since its datatype was
previously declared as a sequence of characters (string). Note that Annual is
enclosed in double quotes (strings always need to be enclosed in double
quotes).
Cycle= "Annual"
pg. 10
Variables provide a way to interact with your data. The word Annual is a
discrete value that you’d find in a column of your worksheet.
The same way we can declare a variable to contain a string or a date, we can
declare a variable to contain a cell range. Later, we’ll assign a cell range to
Target_Range in order to move around Excel and perform different tasks.
These are simple and useful statements for automation. Just think about this,
let’s imagine you’re working with financial data.As new data comes in every
day, you’d want your model to be fully capable of dealing with the growing
volume of data in an automated fashion.
The Date function returns the current system date. Some steps back, we
declared variable Current_Date as Date
datatype to enable the variable to store dates. Now, the second step will be to
assign the Date function to Current_Date in order for Current_Date to
return the current system date.
Like this:
Current_Date = Date
pg. 12
Every time the macro runs, Current_Date will store the current system date.
This is important, because in order for our macro to work, it will need to
know what day is today.
Be careful not to mix the Date function with the Date datatype .
The interval argument: A string representing the time interval you intend to
add or subtract. In the following examples, I only mention two types of
interval arguments : day represented by
d and month represented by m . But ,there are more to choose from, for
example , yyyy represents year and h represents
hour .
Number: This is the number of intervals you intend to add. If you choose
day as the interval argument, Number will represent the number of days you
want the function to add.
pg. 13
DateAdd(“d”, 1, “25-Jan-20”)
pg. 14
We’re going to take the macro shown below and break it apart, piece by
piece, to gain a better understanding of it. This macro iterates through your
worksheet’s cells to perform tasks. The goal of the macro is to calculate an
invoice due date given its Cycle and Term sitting in columns G and I
respectively. Here’s the complete macro we’re going to evaluate:
pg. 15
The first step will be to define the macro by assigning a unique name to it.
Next, we proceed to declare and define our variables.
pg. 16
CurrentDate = Date: The Date function is the current system date assigned
to variable CurrentDate . Previously defined as Date datatype to enable the
variable to store what the Date function returns (a date). Variable
CurrentDate lets the macro know what the date is today which is needed to
calculate the invoice due date.
In this segment, we first select a cell range, then we create a variable out of
the selected cells. This variable ( MyRange ) is one of the elements that will
allow us to move from cell to cell to evaluate the contents of those cells and
take action depending on what’s found, as you will see in the next segments.
Range(Range("H14"),Range("H14").End(xlDown)).Select:
To select cell H14 and every cell below H14 that contains data.
Set MyRange = Selection: To state that MyRange equals (contains) all cells
that were selected in the previous statement.
As already mentioned, every time the macro runs these two statements will
run, meaning that if your data grows, the macro’s selection will expand as
you add more data to your model.
pg. 17
In the previous step, we created a variable called MyRange which is a
selection of a cell range. You can use VBA’s For
Next element
Where the element is an element of the group. In this case the element (
MyCell ) is each cell of the group, and the group is the cell range contained
in variable MyRange .
pg. 18
What this does is tell Excel that for each cell in MyRange you want to
perform one or more actions. Excel will step on the first cell of the group
(cell H14 ), perform one or more actions, and then move to the next cell
(instructed by Next MyCell ) to perform the same set of actions. Next, how
that works in more detail.
For Each MyCell In MyRange : Tell Excel to iterate through the elements
of the collection, that is, step into each cell contained in MyRange and take
the following actions: MyCell.Offset(0, -1).Select: After selecting the first
cell of MyRange ( H14 ), this line of code instructs Excel to move to the left
one cell (instructed by Offset(0,-1)) and select that cell ( G14 ).
pg. 19
End If: Close the If statement previously opened, every single If statement
needs to be closed with an End If statement.
Next MyCell: Make Excel jump to the next cell contained in MyRange , that
is, cell H15, and perform the same exact steps that were performed in cell
H14 . After cell H15 is done, the macro will move to the next cell ( H16 ),
and will keep looping until it reaches the last cell contained in MyRange .
Just so you know, before this macro runs another macro will copy and paste
all dates from column F ( Invoice Date ) into column H ( Due Date ). This
step is convenient, because every time this macro runs it starts calculating
the invoice’s due-date in column H from the invoice’s start date, thus
refreshing all previously calculated due-dates that are (will be) sitting in
column H .
The point is, in this segment the macro moves from cell to cell using the
Do…Loop to add 12 months until a certain condition becomes true. In this
case, the condition is that the date sitting in cell H14 is greater (when
working with dates greater means after) or equal to CurrentDate .
For instance, if you have an invoice from 2018 and we’re in the year 2025,
the macro will add 12 months to 2018 until the year 2025 is reached, which
should be the system date at the time.
The following statements that are part of the next piece of code will take the
resultant date and finish calculating every invoice due-date that is paid
annually with a payment term of 15 days.
pg. 20
You can also control your code execution using If…Then
Keep in mind that the If…Then Statement provides Excel with decision
making capability.
Bottom line, For Each…Next Statement will let you move through all cells
contained in MyRange and If…Then
Statement will let you decide what to do when, for example, the string
Annual is found.
pg. 21
months from whatever date is in cell H14 (as mentioned before, at this point
this is Invoice Date ).
(that resulted from prior steps subtraction and addition) is less (less means
before when we’re dealing with dates) than CurrentDate (current system
date) then do the following: MyCell.Value = DateAdd("m", 12,
MyCell.Value): Add 12
End If: Every time you open an If…Then Statement you need to close the
statement with an End If , always. In this case, we opened three If’s and
therefore we need three End If’s.
pg. 22
Next MyCell: Excel jumps to the next cell contained in MyRange ( H15 )
and performs, once again, the same set of actions. After H15 is done, Excel
will move to the next cell in MyRange , which is H16 . After there are no
more cells to move to, the macro will stop.
End Sub: This is always the last statement to end the macro.
months and added 15 days to find out if we are still running under the last
TERM. If the current date is greater (greater means after when dealing with
dates) than the due-date calculated by the step, that means last payment term
is over and the macro will give you the next due-date.
This makes more sense when you are calculating monthly due-dates. For
example, you have a new monthly invoice that starts in January with a 60
day payment term. That means that after January 31 you still have 60 days to
pay the invoice.
Suppose you are in February. If you are running the model in February you
need to make sure that the tool shows you the remaining days left to pay the
invoice in the month of January instead of calculating the due-date for
February. That’s why we add and then subtract dates to add again. When the
invoice from January is past-due in March, the macro will calculate the next
invoice due-date; that is, the due-date from the month of February.
pg. 23
Hardcoding in programming means fixing some or all of your program’s
parameters using actual data values. Hence, hardcoding may reduce the
flexibility of your code. The only way to modify any hardcoded parameter is
by going into your code and manually changing the parameter itself.
People often argue that hardcoding is bad practice and it should be avoided
when possible. I don’t see it that way, as long as a limited number of
parameters are hardcoded. If you can avoid it, go ahead and do so, but if not,
it doesn’t mean you are compromising your program’s flexibility or that it
can be written in a better way.
For instance, cell H14 is hardcoded into the macro. This is column Due Date
which is the macro’s pointer column/cell. The macro moves from cell to cell
starting from cell H14 . You can use any other cell as a starting point to
iterate through your columns/cells. You do so by simply manually changing
in your source code cell H14 to any other cell.
Something to have in mind, CurrentDate is not hardcoded since it does not
take any specific fixed date; instead its value depends on a function which
supplies the current system date.
Meaning that its value changes without the need to modify the source code.
pg. 24
In this chapter, you’re going to write VBA procedures using the code and
dummy data I provided. You also have the option to copy and paste the
source code into the VBE.
Be careful when coding; any punctuation mark missing or out of place, any
misspelled word, etc. will generate an error and will stop you from running
your macro successfully. Usually, programmers spend hours trying to fix
errors, and that’s because it’s often hard to find them.
Delete all code from MODULE 1 (if any) and write or paste the source code
provided.
Here are some key points to consider when writing macros to calculate
payment due-dates based on monthly cycles:
- Assign string Monthly to variable Payment_cycle . By doing this, the macro
will be able to identify which invoices are marked as monthly in column G
of your spreadsheet. Don’t forget to add quotation marks.
- Set up all your different payment terms. Assign strings of text 15 days, 30
days and 60 days to variables Term_1 , Term_2 and Term_3 respectively.
This way the macro will be able to identify the correct Term from column I
for each invoice. Remember to add quotation marks.
pg. 25
- Create a macro with a unique name. In this script, the macro’s name is
Monthly_calculation_macro . This is hardcoded into the Trigger macro.
(More details about the Trigger macro in the following sections).
In Module 1 , write the block of code below, or copy and paste it from the
source-code file.
pg. 26
‘Second block of instructions: This block calculates due-dates for the
first Term.
pg. 27
pg. 28
In that way, the New Invoice macro that we’re going to write next doesn’t
have to go back to verify whether or not the current term is over, making it
much simpler. Given that, we’re going to take this opportunity to mix things
up a little, and instead of writing one macro per each cycle, we’re going to
consolidate the code and write one macro for all cycles.
In the future, you’ll realize that these series of macros can be consolidated
into one, but for the sake of simplicity, I decided to split the macro into a
series of smaller blocks (monthly, quarterly, and annual macros) so the code
can be better understood and modified more easily.
As a note, every time the macro finds a new invoice (an invoice which starts
on a date ahead of the current date) it will write New_Invoice in column B (
Notes ).
pg. 29
pg. 30
‘Second block of instructions: This block calculates due-dates for
quarterly invoices under all ‘Terms.
pg. 31
‘Third block of instructions: This block calculates due-dates for annual
invoices under all Terms.
pg. 32
Let’s create a Form Control from where we can run all the macros at once.
Go to the DEVELOPER tab and click Insert icon, then under Form
Controls select Button . Figure 15
Figure 15.
Now, click somewhere on cell E7 to start drawing your Button.
While pressing your mouse left button, move to somewhere around cell I8. I
say somewhere around because you can make this button as big or as small
as you like; it’s up to you. Just make sure Design Mode is selected (located
next to the Insert icon). Every time you need to format or adjust one of your
controls, Design Mode needs to be activated. Remembering this will save
you a lot of trouble.
pg. 33
Right after you draw your Button, Excel is going to ask if you would like to
assign a macro. Click Cancel , we’re going to assign a macro later. See
Figure 16 and Figure 17.
Figure 16.
Figure 17.
pg. 34
Position your mouse pointer on top of the Button you just created, do a right
click, and select Edit Text as per Figure 18.
Figure 18.
This procedure gives you the option to rewrite the text that appears on the
Button itself. Delete text Button 1 and rewrite to something similar to
REFRESH. See Figure 19.
Figure 19.
pg. 35
Let’s create a Combo Box control; this type of ActiveX control is generally
known as drop-down.
Figure 20.
Figure 21.
pg. 36
Figure 22.
We’re done here. So far, we’ve created many of the elements your
application needs to run nicely. Also, we’ve given some aesthetic touches to
our model.
We’ve created several macros. It is relatively easy to put all these macros to
work sequentially. We need to write a macro to call all macros. Using the
Call statement to trigger every one of our macros is one way to do the trick.
We’re going to use the Form Control that we just embedded in the main tab
of our spreadsheet to call all procedures with just a click of a button.
Before calling all procedures, this trigger macro also copies and pastes dates
from column F ( Invoice Date ) to column H ( Due Date ). The reason
behind this step, as mentioned before, is to have a starting point from which
to compute due-dates. In other words, every time the macro runs, the starting
date of an invoice is copied and pasted into column Due Date for our macros
to start calculating the invoice due-date based on the invoice’s starting date.
Write the block of code below or copy and paste it from the source-code file
as shown in Figure 23:
pg. 37
‘Step One – Name your macro:
‘First block of instructions: This block copies all dates from column F to
H.
Note: Before running this macro you need to write all macros we are calling
in the second block.
pg. 38
Figure 23.
Step One – Go to your main tab and right click on top of the Button
Form Control:
pg. 39
Figure 24.
Figure 25.
pg. 40
Clicking REFRESH SCHEDULER will activate your trigger macro which
calls all macros we coded. Note, in this case we’re assigning to the Button
Form Control a macro that calls multiple macros but you can simply add any
macro you want to the Button or create more buttons to call macros
individually.
A few steps back, we created an ActiveX Control, and now we’re going to
assign a macro to it. The goal of the control (list dropdown) is to filter one or
more invoices previously grouped by Company ID ( column A ).
To illustrate with an example see Figure 26. Note that all of the invoices
belong to Company ID 0049 . Assigning invoices to parent companies (those
entities which issued the invoice) should be done when they’re entered into
the model. The dummy data was fabricated to group companies using an
identifier such as Company ID but as you can imagine, you can actually set a
name of a specific group or person here (or whatever name or grouping code
works best for you); or you can leave it blank if no grouping is needed.
Figure 26.
pg. 41
Right-click on the new Sheet tab and click Rename to set a name as we did
before. See Figure 27. Note, since we’re going to hardcode the name of this
sheet in our macro, it’s better if we stick to the name for the macro to work.
In other words, if we change the name of this sheet in the future, we need to
modify the macro (that we’re going to write next) to replace the old sheet’s
name with the new one.
Figure 27.
With the List sheet in place, we can proceed to establish a list of names to
place in our drop down’s source list. Every time a new name or entity is
added to column A ( Company ID ), we need to add that same name to our
list and place it in the List sheet for the dropdown to pick it up.
Create the list in the List sheet as per Figure 28. Don’t forget to include All
as shown.
pg. 42
Figure 28.
Finally, click once on your dropdown control to select it. See Figure 29.
Figure 29.
Note from Figure 29 that the name assigned to the control is ComboBox1.
This is important since macros recognize specific controls by their unique
name. If you change the name of the control you also need to change its
name in the macro (since it’s hardcoded).
pg. 43
Next step would be to assign the list we created to the List sheet of this
control. Do a right click on the dropdown (which is selected) and click on
Properties as shown in Figure 30.
Figure 30.
The window shown in Figure 31 will appear. To assign our list to the control
go ahead and type List!A2:A13 in the ListFillRange property as shown in
the figure. Close the property window. Go to the DEVELOPER tab and
deselect Design Mode .
pg. 44
Figure 31.
We’re all set to write the code from which this control will feed.
Below is the macro we need to write. In this Private Sub macro we start by
declaring and defining our variables. In this case, variable x . Note that
variable x is a ComboBox1.value that translates to: x equals the value that is
selected in our ComboBox1 , that is, any value of our list.
pg. 45
After we have completed declaring our variables, we proceed to write
instructions. Here’s the logic: if x <> ( <> means does not equals) “All”
(enclosed in quotes) select whatever criteria of x is selected in the dropdown
(whatever Company ID or value) within range A13:A10000. Else, select
every value within range A13:A10000.
To apply this macro, go to the VBE, double click Sheet1 (Main) and copy
and paste the code from the source code file into the Code Window or type
code above. See Figure 32.
Figure 32.
pg. 46
When you click on the dropdown you should see the list/values shown in
Figure 33.
Figure 33.
At this point, your dropdown should be fully functional and able to filter
invoices by Company ID .
on the basis that you could have 9,987 invoices in your model.
In case you have a higher number of invoices to load into your model, let’s
say 20,000 invoices, you would need to extend your cell range.
pg. 47
Like any other programmer in this world, you’ll encounter issues with your
code. My best advice in this case is to overcome frustration by working until
a solution is found. We learn to code by solving problems.
Here are some quick notes: if you get an error while running your macro (
Error Break Mode ), go to your VBE, identify highlighted code, click Reset (
Stop button ) and fix the code that was highlighted before running the macro
again. If in your Main sheet a column is intended to contain dates, then make
sure to use Date formatting in that specific column.
When you have created something that looks reasonably attractive, that
makes sense, and is functional, you know you’ve created something that
other people can trust. Every Excel model you create should promote trust
and reliability, always.
pg. 48
Please
download
the
companion
files
pg. 49