Chapter 10: Advanced Formulas
Learning Objectives
- Write nested logical formulas with IFS, SWITCH and NOT alongside IF, AND and OR.
- Find conditional maximums and minimums with MAXIFS and MINIFS.
- Name values inside a formula with LET.
- Look up data in rows with HLOOKUP.
- Filter data with FILTER and sort it with SORTBY.
- Find the day of the week with WEEKDAY and add working days with WORKDAY.
Introduction to Excel taught you most of the functions on MO-211. Lessons 2–5 covered IF, AND and OR, the conditional aggregate functions (SUMIF, COUNTIFS and the rest), XLOOKUP, VLOOKUP, INDEX and MATCH, NOW and TODAY, and PMT and NPER. This chapter adds the functions those lessons didn't cover, and it focuses on the skill MO-211 cares about most: nesting functions inside each other to answer a question in one formula.
10.1 IFS, SWITCH and nested logic
10.1.1 A quick review of nesting
A nested function is a function used as an argument to another function. You've already written formulas like these:
=IF(AND(B2>=90, C2="Yes"), "Honors", "Standard")
=IF(B2>=90, "A", IF(B2>=80, "B", IF(B2>=70, "C", "F")))
The second formula works, but each extra grade adds another IF and another closing parenthesis. IFS and SWITCH do the same job with flatter formulas.
10.1.2 IFS
IFS(test1, value1, [test2, value2], …) checks each test in order and returns the value paired with the first test that's TRUE.
=IFS(B2>=90, "A", B2>=80, "B", B2>=70, "C", B2>=60, "D", TRUE, "F")
Two things to remember:
- Order matters. IFS stops at the first TRUE test. If you put
B2>=60first, a score of 95 would return "D". - IFS has no "otherwise" argument. If no test is TRUE, it returns
#N/A. To catch everything else, end withTRUEas the last test, as in the formula above.
10.1.3 SWITCH
SWITCH(expression, value1, result1, [value2, result2], …, [default]) compares one expression with a list of exact values and returns the result for the one that matches. A final unpaired argument is the default, returned when nothing matches.
=SWITCH(C2, "N", "North", "S", "South", "E", "East", "W", "West", "Unknown")
=SWITCH(WEEKDAY(A2), 1, "Weekend", 7, "Weekend", "Weekday")
Use SWITCH when you're matching one value against a list of exact options. Use IFS when each test is a different comparison, like ranges of scores. Without a default, SWITCH returns #N/A when nothing matches.
10.1.4 NOT
NOT(logical) reverses TRUE and FALSE. It's most useful inside AND or OR, to say "and this is not the case":
=IF(AND(D2>=3, NOT(E2="Probation")), "Eligible", "Not eligible")
=IF(NOT(ISBLANK(F2)), "Submitted", "Missing")
NOT(E2="Probation") means the same as E2<>"Probation". Either is fine unless a task asks for NOT.
10.1.5 Putting it together
MO-211 tasks often combine several functions. Read the task and break it into parts:
"In G2, enter a formula that returns Bonus if the employee's sales are over 50,000 and they are not in the Training group, Review if their sales are under 20,000, and None otherwise."
- The first condition has two parts joined by and, one of them negative:
AND(E2>50000, NOT(F2="Training")). - There are three outcomes, so use IFS (or nested IFs).
- "Otherwise" means a final
TRUEtest.
=IFS(AND(E2>50000, NOT(F2="Training")), "Bonus", E2<20000, "Review", TRUE, "None")
Build long formulas a piece at a time. Type the inner part, such as the AND, in a spare cell to check that it returns TRUE and FALSE where you expect, then copy it into the full formula and delete the spare cell. The exam grades only the cell the task names.
The Perform data analysis objectives also ask you to "forecast data by using AND, IF and NPER" and to calculate with PMT. Those functions are in Lessons 2 and 3 of Introduction to Excel. On the exam they appear in nested formulas, such as =IF(NPER(B3/12, -B4, B2)<=60, "Within 5 years", "Longer").
10.2 MAXIFS and MINIFS
Lesson 4 of Introduction to Excel covered SUMIFS, COUNTIFS and AVERAGEIFS. MAXIFS and MINIFS work the same way, but they return the largest or smallest value that meets the criteria:
MAXIFS(max_range, criteria_range1, criteria1, [criteria_range2, criteria2], …)
MINIFS(min_range, criteria_range1, criteria1, [criteria_range2, criteria2], …)
Like SUMIFS, the range being measured comes first, followed by pairs of criteria ranges and criteria. For a table Sales with the columns Region, Rep, Product and Amount:
=MAXIFS(Sales[Amount], Sales[Region], "West")
=MINIFS(Sales[Amount], Sales[Region], "West", Sales[Product], "Kayak")
=MAXIFS(Sales[Amount], Sales[Region], H2, Sales[Amount], "<"&H3)
Criteria work the same as in the other -IFS functions:
- Text or numbers to match exactly:
"West",500. - Comparisons in quotation marks:
">=1000","<>Closed". - A comparison with a cell, joined with &:
">"&H3. - Wildcards:
"K*"(starts with K),"*kit*"(contains kit),"?"(any one character).
If no rows match, MAXIFS and MINIFS return 0, not an error.
The order of arguments is the most common mistake. SUMIF and AVERAGEIF put the range being totaled last, but SUMIFS, AVERAGEIFS, MAXIFS and MINIFS put it first. Excel shows each argument's name in a tooltip as you type, so check it.
10.3 LET
LET(name1, value1, [name2, value2], …, calculation) gives names to values or calculations inside a formula, then uses the names in a final calculation. It makes long formulas shorter and easier to read, and it calculates each named part only once.
Without LET, a formula might repeat the same calculation:
=IF(SUM(B2:D2)*1.08>500, SUM(B2:D2)*1.08*0.9, SUM(B2:D2)*1.08)
With LET, you name it once:
=LET(total, SUM(B2:D2)*1.08, IF(total>500, total*0.9, total))
Read it as: "Let total be SUM(B2:D2)×1.08. Then, if total is over 500, return total×0.9; otherwise return total."
You can define several names. Each name can use the ones before it:
=LET(subtotal, B2*C2, tax, subtotal*$H$1, subtotal + tax)
Rules for names:
- They must start with a letter and can't look like a cell reference.
taxRateandtotalare fine, butA1andtax1are not, because TAX is a column. - They work only inside that formula.
- The last argument is always the calculation that gives the result. LET needs an odd number of arguments.
Tasks may say "use a function that assigns a name to the calculation result." That means LET. Make sure your formula uses each name in the final calculation.
10.4 HLOOKUP
HLOOKUP is the horizontal version of VLOOKUP. VLOOKUP searches down the first column of a range and returns a value from another column. HLOOKUP searches across the first row and returns a value from another row.
HLOOKUP(lookup_value, table_array, row_index_num, [range_lookup])
| Argument | Meaning |
|---|---|
| lookup_value | The value to find in the first row. |
| table_array | The range to search. Its first row holds the values to search. |
| row_index_num | Which row of the range to return from: 1 is the first row, 2 the second, and so on. |
| range_lookup | FALSE for an exact match. TRUE (the default) for the closest match below, which needs the first row sorted in ascending order. |
Suppose B1:M1 holds month names (Jan to Dec), row 2 holds sales, row 3 holds costs and row 4 holds staff counts:
=HLOOKUP("Apr", B1:M4, 3, FALSE) April's costs
=HLOOKUP(P2, $B$1:$M$4, 2, FALSE) sales for the month in P2
XLOOKUP (Lesson 4) searches rows or columns, defaults to an exact match and doesn't need a row number. In your own work, prefer XLOOKUP: =XLOOKUP("Apr", B1:M1, B3:M3). MO-211 still lists HLOOKUP, though, so a task may require it. Tasks that require a particular function say so, for example "use a function that searches horizontally."
10.5 FILTER and SORTBY
FILTER and SORTBY are dynamic array functions, like SORT and UNIQUE (chapter 5). They return a whole range of results that spills from one cell.
10.5.1 FILTER
FILTER(array, include, [if_empty]) returns the rows (or columns) of array where include is TRUE.
| Argument | Meaning |
|---|---|
| array | The data to return, such as a whole table or some of its columns. |
| include | A condition that's TRUE or FALSE for each row, the same height as array. |
| if_empty | What to return when no rows match, such as "None". Without it, FILTER returns #CALC! when nothing matches. |
=FILTER(Sales, Sales[Region]="West")
=FILTER(Sales[[Rep]:[Amount]], Sales[Amount]>=1000, "No sales over 1,000")
=FILTER(Sales, Sales[Region]=H1, "None")
To combine conditions, put each one in parentheses:
- Multiply them for and: both must be true.
- Add them for or: either can be true.
=FILTER(Sales, (Sales[Region]="West")*(Sales[Amount]>1000))
=FILTER(Sales, (Sales[Product]="Kayak")+(Sales[Product]="Canoe"))
This works because TRUE counts as 1 and FALSE as 0. A product is 1 only when both conditions are 1, and a sum is 0 only when both conditions are 0.
AND and OR don't work inside FILTER's include argument. They return one TRUE or FALSE for the whole range instead of one for each row. Use * and + instead.
10.5.2 SORTBY
SORTBY(array, by_array1, [sort_order1], [by_array2, sort_order2], …) sorts array by one or more other ranges.
=SORTBY(Staff[Name], Staff[Salary], -1)
=SORTBY(Staff, Staff[Department], 1, Staff[Salary], -1)
The first formula lists names from highest salary to lowest, without showing the salaries. The second sorts the whole table by department, A to Z, and by salary from highest to lowest within each department.
SORT (chapter 5) sorts by a column number inside the array. SORTBY sorts by ranges, which has two advantages:
- You can sort by a column that isn't in the result, as in the first example.
- You can sort by several columns, each with its own order, as in the second.
Each by_array must be the same height as array. Sort order is 1 for ascending (the default) or -1 for descending.
10.5.3 Combining them
Dynamic array functions nest well:
=SORTBY(FILTER(Sales, Sales[Region]="West"), FILTER(Sales[Amount], Sales[Region]="West"), -1)
=SORT(FILTER(Sales[[Rep]:[Amount]], Sales[Amount]>1000), 2, -1)
The second formula is shorter because SORT sorts by a column number of the filtered result. Use SORTBY when you need to sort by something that isn't in the result.
10.6 WEEKDAY and WORKDAY
Lesson 5 of Introduction to Excel covered dates, TODAY and NOW. MO-211 adds two functions for working with days of the week.
10.6.1 WEEKDAY
WEEKDAY(serial_number, [return_type]) returns a number for the day of the week of a date. return_type chooses the numbering:
| return_type | Numbering |
|---|---|
| 1 or omitted | Sunday = 1 through Saturday = 7 |
| 2 | Monday = 1 through Sunday = 7 |
| 3 | Monday = 0 through Sunday = 6 |
With return_type 2, weekends are 6 and 7, which makes weekend checks simple:
=IF(WEEKDAY(A2, 2)>5, "Weekend", "Weekday")
To show the day's name instead of its number, use a number format (dddd, chapter 9) or =TEXT(A2, "dddd").
10.6.2 WORKDAY
WORKDAY(start_date, days, [holidays]) returns the date that is a number of working days before or after a start date. It skips Saturdays, Sundays and any dates you list as holidays.
=WORKDAY(A2, 10) 10 working days after A2
=WORKDAY(A2, 10, Holidays[Date]) the same, also skipping listed holidays
=WORKDAY(A2, -5) 5 working days before A2
The start date itself isn't counted. WORKDAY returns a serial number, so format the cell as a date if it shows a number like 46213.
"Calculate the due date, 15 business days after the order date, excluding the holidays listed on the Holidays worksheet" is a WORKDAY task. Use the holiday range as the third argument, with absolute references (or a table reference) so the range doesn't shift when you copy the formula down.
10.7 Practice
Simmy assessment goes here. Exam-style tasks on IFS, SWITCH, NOT, MAXIFS, MINIFS, LET, HLOOKUP, FILTER, SORTBY, WEEKDAY and WORKDAY, with nesting. When a student misses a task, Simmy builds the AI prompt (the task as worded, what the student did, and the correct result).
Starting data. A workbook named Brightline Staffing with sheets Placements, Rates and Holidays.
Placements: a table named Placements (A1:G16):
| ID | Worker | Client | Type | Start | Hours | Score |
|---|---|---|---|---|---|---|
| P-01 | Ana Morales | Hartwell | Contract | 9/1/2027 | 320 | 92 |
| P-02 | Ravi Singh | Kestrel | Temp | 9/3/2027 | 80 | 67 |
| P-03 | Nora Walsh | Hartwell | Temp | 9/6/2027 | 120 | 85 |
| P-04 | Ken Ito | Orchard | Contract | 9/8/2027 | 400 | 78 |
| P-05 | Lina Haddad | Kestrel | Direct | 9/10/2027 | 0 | 95 |
| P-06 | Luc Moreau | Orchard | Temp | 9/13/2027 | 60 | 54 |
| P-07 | Maya Torres | Hartwell | Contract | 9/15/2027 | 280 | 88 |
| P-08 | Liam Okafor | Orchard | Temp | 9/17/2027 | 140 | 73 |
| P-09 | Ava Chen | Kestrel | Contract | 9/20/2027 | 360 | 81 |
| P-10 | Noah Patel | Hartwell | Direct | 9/22/2027 | 0 | 90 |
| P-11 | Zoe Lindqvist | Orchard | Contract | 9/24/2027 | 300 | 69 |
| P-12 | Eli Brooks | Kestrel | Temp | 9/27/2027 | 100 | 77 |
| P-13 | Isla Romero | Hartwell | Temp | 9/29/2027 | 40 | 58 |
| P-14 | Owen Fitzgerald | Orchard | Direct | 10/1/2027 | 0 | 84 |
| P-15 | Ruby Nakamura | Kestrel | Contract | 10/4/2027 | 380 | 93 |
Rates (A1:E3): row 1 holds the types Contract, Temp, Direct in B1:D1 (A1 "Type"); row 2 "Hourly" 48, 32, 0; row 3 "Fee %" 0.10, 0.15, 0.20.
Holidays: a table named Holidays with one column, Date: 9/6/2027, 10/11/2027, 11/11/2027, 11/25/2027.
Tasks.
- In H2 of the Placements table, add a column named Rating that returns "Excellent" for scores of 90 or more, "Good" for 75 to 89, "Fair" for 60 to 74, and "Poor" otherwise. Use a single function without nesting IF. Expected result: H1 "Rating";
=IFS([@Score]>=90,"Excellent",[@Score]>=75,"Good",[@Score]>=60,"Fair",TRUE,"Poor"). Objective: Perform logical operations by using IFS(). - Add a column named Code that returns "C" for Contract, "T" for Temp and "D" for Direct, using a function that compares the type with a list of values. Expected result: I1 "Code";
=SWITCH([@Type],"Contract","C","Temp","T","Direct","D"). Objective: Perform logical operations by using SWITCH(). - Add a column named Review that returns "Yes" when a placement's score is below 70 and its type is not Direct, and "No" otherwise. Expected result: J1 "Review";
=IF(AND([@Score]<70,NOT([@Type]="Direct")),"Yes","No"). Yes for P-02, P-06, P-11, P-13. Objective: Perform logical operations by using AND(), NOT(), IF(). - In cell Q2, enter a formula that returns the highest score for Hartwell placements. In Q3, return the lowest hours for Contract placements. Expected result: Q2
=MAXIFS(Placements[Score],Placements[Client],"Hartwell")= 92; Q3=MINIFS(Placements[Hours],Placements[Type],"Contract")= 280. Objective: MAXIFS(); MINIFS(). - Add a column named Pay that looks up the hourly rate for the placement's type on the Rates worksheet and multiplies it by the hours. Use a function that searches across the first row of a range. Expected result: K1 "Pay";
=HLOOKUP([@Type],Rates!$B$1:$D$3,2,FALSE)*[@Hours]. Objective: Look up data by using HLOOKUP(). - In cell Q5, enter a formula that multiplies the total hours of Hartwell placements by 32, then returns that amount minus 10 percent if it is more than 20,000. Assign the name amt to the amount within the formula. Expected result: Q5
=LET(amt,SUMIFS(Placements[Hours],Placements[Client],"Hartwell")*32,IF(amt>20000,amt*0.9,amt)); 760 hours × 32 = 24,320, minus 10 percent = 21,888. Objective: Perform logical operations by using LET(). - In cell S1, enter a formula that returns the names of the workers in Contract placements, sorted from highest score to lowest. Do not include the scores in the result. Expected result: S1
=SORTBY(FILTER(Placements[Worker],Placements[Type]="Contract"),FILTER(Placements[Score],Placements[Type]="Contract"),-1), spilling Ruby Nakamura, Ana Morales, Maya Torres, Ava Chen, Ken Ito, Zoe Lindqvist. Objective: Filter data by using FILTER(); Sort data by using SORTBY(). - Add a column named Ready that returns the date 10 working days after the start date, skipping the dates in the Holidays table. Expected result: L1 "Ready";
=WORKDAY([@Start],10,Holidays[Date]), formatted as a date. Objective: Calculate dates by using WORKDAY(). - Add a column named Start Day that returns 1 for a start on Monday through 7 for a start on Sunday. Expected result: M1 "Start Day" …
=WEEKDAY([@Start],2). Objective: Calculate dates by using WEEKDAY().