BlackTor Excel
BlackTor Group · Excel Formulae

Practical formulas, built to be trusted.

Workbooks built to survive real use: a colleague opening them cold, a year of new rows, a renamed tab. This is the formula and modelling side of the practice.

A translucent black cube etched with a moss-green map of the world's continents, glowing softly against black.
BlackTor Group Ltd Dartmoor, UK
A note on what follows

No client names, no client data.

BlackTor's work is covered by client NDAs, so the examples below don't describe a real client, project or dataset. To keep things concrete, they're all set at "Ride Me Cycles": a fictitious multi-branch bike retailer invented for this site. The techniques are real; Ride Me Cycles and everything about it are not.

Latest update

Latest: converted a character-builder workbook's core data ranges (a personal project, not client work) into structured Excel Tables, so every formula built on them extends automatically as rows are added.

A few examples

Two practical examples of formula work.

Illustrative, per the note above: not real client work.

The problem: Ride Me Cycles' branch managers ran their own staff rota in a shared workbook, and the same mechanic ended up booked onto two shifts at once more often than anyone liked.

The approach: Added a COUNTIFS-based overlap check across the shared rota, flagging a double-booking the moment it's entered rather than the moment the shift starts.

=COUNTIFS(staff,B2,start,"<"&E2,end,">"&D2)>1

The result: Clashes get caught at entry, not at the start of the shift.

The problem: Ride Me Cycles' month-end P&L carried eleven different 'branch profit' formulas across its tabs, and they quietly disagreed with each other by a few hundred pounds most months.

The approach: Traced every total back to its source range, then rebuilt them all onto one named-range calculation, so profit only ever gets computed once.

=SUMIFS(sales[Revenue],sales[Branch],B2)-SUMIFS(sales[Costs],sales[Branch],B2)

The result: One number for 'branch profit', quoted the same way in every tab that references it.

Formulas explained

Four formulas worth understanding.

Formulas, tables, pivots and the other pure-Excel problems that do not rely on VBA or SQL. Four patterns below, explained on their own technical terms. For VLOOKUP, HLOOKUP, XLOOKUP and INDEX & MATCH specifically, see the dedicated Lookups page. For Data Validation dropdown lists, including a cascading list, see the dedicated Lists page.

Building a clean list from a messy range

=TRIM(SORT(UNIQUE(FILTER(FT4:FT209,FT4:FT209<>""))))

FILTER first removes every blank cell from the range, leaving only rows with a value. UNIQUE then removes duplicates from what is left, and SORT puts what remains into order. TRIM closes out the formula by stripping any stray leading, trailing or repeated spaces from each result, which matters because a value with an invisible extra space looks identical to its clean counterpart but will not match it in a lookup. The result is a tidy, sorted, deduplicated list built directly from a working range, useful as the source for a dropdown list or a summary table without a separate cleanup step.

The same idea, without deduplication

=SORT(FILTER(HP3:HP59,HP3:HP59<>""))

A simpler variant of the pattern above: FILTER strips blanks from the range, and SORT puts the remaining values in order, but there is no UNIQUE step, so repeated values are kept and appear once for each occurrence. This is the right formula when the count of each item matters (a rota of shifts, for example, where the same name can legitimately appear several times) rather than a distinct list of what is present.

Turning a column into one summary line

=TEXTJOIN(", ",TRUE,UNIQUE(CF3:CF233) & IF(COUNTIF(CF3:CF233,UNIQUE(CF3:CF233))>1,"(" & COUNTIF(CF3:CF233,UNIQUE(CF3:CF233)) & ")",""))

UNIQUE reduces the range to its distinct values, and COUNTIF, run against that same distinct list, counts how many times each one appears in the original range; because both are array formulas, this comparison happens for every distinct value at once rather than one at a time. Where a value appears more than once, the IF appends a count in brackets; where it appears only once, nothing is added. TEXTJOIN then joins the whole array into a single comma-separated string. The result reads as a short summary line such as 'Bracket, Screw (4), Washer (12)', built entirely from a raw column with no helper cells.

Listing the contents of one named container

=IFERROR(TEXTJOIN(", ", TRUE, BYROW(UNIQUE(FILTER($EE$3:$EE$233, ($ED$3:$ED$233<>"Packs & Containers")*($EH$3:$EH$233="Yes")*($EI$3:$EI$233=B58))), LAMBDA(x, x & IF(SUMIFS($EF$3:$EF$233, $EE$3:$EE$233, x, $EH$3:$EH$233, "Yes") > 1, "(" & SUMIFS($EF$3:$EF$233, $EE$3:$EE$233, x, $EH$3:$EH$233, "Yes") & ")", "")))),IF(B58="Money Pouch", SUM(L44:L46)&" coins","Empty"))

This combines several of the patterns above into one formula that answers a single question: what is inside a named container right now? FILTER narrows the source range to rows that belong to the container named in B58, are marked as currently assigned, and are not themselves another container (avoiding a container listing itself as its own content). UNIQUE then reduces that to distinct item names, and BYROW with LAMBDA runs a small calculation, in this case a SUMIFS quantity total, against each one individually, appending a count in brackets wherever the quantity is more than one, the same pattern as the summary-line formula above but generalised to work row by row. TEXTJOIN turns the result into one readable line. The IFERROR at the outer level supplies two fallbacks for the case where FILTER finds nothing to list: a special case for one particular container that instead totals a separate numeric range, and 'Empty' for every other container with nothing assigned to it. Multi-step formulas like this are usually easier to maintain built up gradually, proving each inner function returns what is expected before wrapping the next one around it, rather than writing the whole thing in one pass.

Notes in full

Every note above, in full.

The sidebar carries the short version; this is the longer one, for whoever wants the detail behind it.

AUG 2026

Structured references, not raw ranges

Converting a range into a Table with Ctrl+T does more than apply banded formatting: it turns the range into a defined object with its own name, and every column within it becomes addressable by name rather than by cell coordinates. A formula referring to Sales[Revenue] is describing what it wants, not where it currently happens to sit, so the reference keeps meaning the same thing even after the table has been resized, moved, or had columns reordered around it. A fixed range like C2:C480 carries none of that context; it is only ever correct for as long as the data occupies exactly those cells.

The practical benefit shows up as soon as the underlying data grows. Typing a new row directly beneath a table extends the table boundary automatically, and any formula, chart, or PivotTable built on that table picks up the new row without being edited. A formula built on a raw range simply excludes anything added past its original last row, which is easy to miss because the sheet still calculates without error, it is just quietly working from an incomplete dataset.

Structured references also make formulas considerably easier to audit, since Sales[Revenue] tells a reader what the column contains, where C2:C480 tells them nothing beyond a location. The one habit worth building alongside this is naming tables something more descriptive than the default Table1, Table2 pattern Excel assigns, since a structured reference is only as informative as the table name behind it.

JUL 2026

IFERROR hides problems as well as fixes them

IFERROR is not selective about what it catches. It responds identically to a #N/A from a genuine lookup miss, a #REF! from a deleted column, a #VALUE! from a text string landing in an arithmetic formula, and a #DIV/0! from a blank denominator. Once wrapped, all four collapse into the same fallback value or blank cell, and there is nothing left in the sheet to distinguish an expected, harmless outcome from a formula that has actually broken. The habit of reaching for IFERROR as a first response, before confirming what the formula is supposed to return and why it is currently erroring, converts a visible bug into an invisible one.

A common version of this is a lookup formula wrapped in IFERROR from the outset, on the assumption that some values simply will not be found. If the source range then gets moved, or a sheet it depends on is renamed, the formula starts returning #REF! for every row, and because IFERROR is still in place, every one of those rows quietly returns the fallback value instead of an error. The sheet looks exactly as it did before, calculations still run, and the fault can go unnoticed for a long time precisely because nothing on the surface indicates one exists.

Where the fallback is genuinely needed, IFNA is usually the better choice for lookup formulas specifically, since it only intercepts #N/A and leaves every other error type visible. That preserves the intended behaviour, hiding an expected lookup miss, without also masking the errors that indicate something has actually gone wrong elsewhere in the model.

JUN 2026

SUMPRODUCT for the cases SUMIFS cannot reach

SUMIFS evaluates each criteria range independently and only sums rows where every condition is true at once, which is effectively an AND across all the arguments supplied. That covers the majority of conditional totals, but it has no built-in way to sum rows matching any one of several values in the same field, and no way to weight one column by another as part of the summing step. SUMPRODUCT handles both because it works differently: it multiplies arrays together element by element and sums the result, so the logic is built from ordinary arithmetic rather than fixed criteria arguments.

An OR condition across one field is done by adding boolean arrays together before multiplying by the range to be summed, for instance (Range="A01")+(Range="B02") produces a 1 for a row matching either code and a 0 otherwise, which SUMIFS's AND-only structure cannot express in a single formula. Weighted sums follow the same pattern: multiplying a quantity column by a rate column within SUMPRODUCT, optionally alongside a condition, performs the multiplication and the conditional total in one step, rather than needing a helper column to hold the products first.

The trade-off is that SUMPRODUCT evaluates every array in full for every calculation, so applying it across whole-column references such as A:A rather than a bounded range can noticeably slow a large workbook, in a way that SUMIFS, which is optimised internally for exactly this kind of conditional summing, generally does not.

MAY 2026

Volatile functions and recalculation time

Excel normally recalculates only the cells that depend on whatever has just changed, tracing the dependency chain from the edited cell outward. Volatile functions opt out of that tracking: OFFSET, INDIRECT, TODAY, NOW, and a handful of others are marked to recalculate on every single change made anywhere in the workbook, regardless of whether their own inputs were affected. A volatile cell buried in an otherwise unrelated part of the sheet will still fire every time any other cell is edited, and every formula that depends on it fires in turn.

In a small workbook this is unnoticeable, but the cost scales with how many volatile functions are in use and how much depends on them. A model with OFFSET-based dynamic ranges feeding several charts and summary tables can end up recalculating that entire chain on every keystroke elsewhere in the file, which is the usual explanation for a workbook that becomes sluggish to edit even though the calculations themselves are not individually complex.

INDEX with a calculated position argument, for example INDEX(range, MATCH(...)), achieves the same dynamic lookup that OFFSET is often used for, but INDEX is not volatile, so it only recalculates when its actual inputs change. A helper column that stores an intermediate result once, rather than recomputing it with a volatile function on every recalculation cycle, has the same effect. Neither requires giving up the dynamic behaviour the volatile function was providing, only the constant recalculation that came with it.

APR 2026

Data validation sourced from a table column

A drop-down list built from Data Validation with a fixed source range, such as $B$2:$B$20, only ever offers the options that existed within that range at the point it was set up. Adding a twenty-first option means editing the validation rule itself, and it is easy to add a new row of data further down the sheet, forget the validation source was never extended to cover it, and end up with an option that exists in the data but not in the dropdown that is supposed to control entry.

Setting the source to a Table column instead removes that maintenance step. Typing =Table1[Options] directly into the source field of the Data Validation dialog ties the dropdown to the table's column rather than to a static range, and because a table automatically extends to include new rows added beneath it, the validation list widens on its own as soon as a new option is typed into the table. Nobody needs to remember to update the range separately, and the list cannot silently fall out of sync with the data it is meant to reflect.

One thing worth checking is that the table column used as the source does not include blank cells partway down, since an empty row within the table range will show up as a blank entry in the dropdown. Keeping the options list itself as a clean, gap-free table column avoids that, and also makes it straightforward to add validation, filtering, or lookups against the same list elsewhere in the workbook.

MAR 2026

Custom number formats preserve the underlying value

A formula like ROUND(A1,2) does not just change how a number looks, it replaces the number itself with the rounded result, and every calculation that references that cell afterwards works from the rounded figure rather than the original. Where several rounded figures are then summed, the total can differ slightly from summing the unrounded originals and rounding once at the end, a discrepancy that is confusing to trace because nothing in the sheet looks wrong, the individual figures just do not quite add up to the displayed total.

A custom number format avoids this because it only changes the way a value is rendered on screen, not the value Excel stores or calculates with. Applying a format such as #,##0.00 to a cell displays it to two decimal places while the full, unrounded number remains in place underneath, available in full precision to any formula that references that cell. The same applies to formats that display values in thousands, add units, or hide zeros: what is shown changes, what is stored does not.

This distinction matters most wherever a displayed figure needs to look tidy for a summary or report but the underlying precision still needs to feed further calculations elsewhere, since formatting for display and rounding for calculation are two different requirements that a custom number format keeps properly separate. Where a value genuinely does need to be rounded, for a stored total that must match a rounded figure elsewhere, ROUND is the right tool; the point is not to avoid rounding altogether but to be deliberate about which of the two operations, display or calculation, is actually needed.

FEB 2026

Finding circular references without guessing

A circular reference occurs when a formula, directly or through a chain of other cells, ends up depending on its own result, and Excel flags this with a warning as soon as it happens. The warning itself only names one cell involved in the loop, which is rarely the most useful starting point in a workbook of any size, since the loop might run through several sheets and half a dozen intermediate formulas before returning to where it started.

Formulas, Error Checking, Circular References lists every cell Excel has identified as part of the loop, in one place, rather than leaving the process to manual inspection of each formula in turn to see which one refers back to an earlier point in the chain. Working through that list from one end is far faster than re-reading the sheet line by line trying to hold the whole dependency chain in mind at once, particularly once the loop crosses sheet boundaries and is no longer visible on a single screen.

It is worth checking this menu the moment the warning appears, rather than after other edits have been made, since further changes to the workbook can shift which cells Excel reports and make the original loop harder to reconstruct. The one case where circular references are intentional rather than an error is an iterative model, such as certain interest or goal-seek calculations, where Iterative Calculation is deliberately enabled in Excel's options; in that situation the warning is expected and the Circular References list is not the relevant check, but for everything else, it is the first place to look.

JAN 2026

Trimming a workbook's used range

Pressing Ctrl+End jumps to what Excel considers the last cell containing data or formatting on a sheet, and it is common for that cell to sit far beyond where the actual data ends, sometimes thousands of rows or dozens of columns past it. Excel determines the used range from anything that has ever had content or formatting applied, not from what currently holds data, so a row of formatting applied and later cleared, or a block of data that was deleted rather than having its formatting reset, both leave a trace that keeps the used range artificially inflated.

That inflated range is not just cosmetic. Excel allocates memory and tracks calculation dependencies across the full used range on every sheet, so a used range many times larger than the actual data increases file size, slows saving, and can noticeably slow recalculation, even though the extra rows and columns are empty of any real content.

Fixing it means selecting the rows and columns beyond the genuine data, from just past the last real row or column to the sheet's edge, and deleting them rather than simply clearing their contents, since a plain Delete on the row or column headers removes the formatting trace that Ctrl+End is responding to, where Clear Contents alone does not. Saving the workbook afterwards resets the used range to reflect the trimmed sheet. Conditional formatting rules applied to entire columns are a common hidden cause of the same problem and are worth checking separately, since they extend the used range in the same way even when no cell in that range holds a formatting override on its own.

DEC 2025

Keep a change log inside the workbook

A change log is a plain tab, typically three or four columns wide, recording the date a change was made, who made it, and a short description of what changed and why. It sits alongside the working sheets rather than in any external document, so it travels with the file wherever it is copied, emailed, or saved, and it is visible to anyone who opens the workbook without needing access to a separate system.

The value of this becomes obvious the first time someone other than the original author opens the file and needs to understand a formula that looks unusual, or a figure that does not match what a similar workbook elsewhere would show. Without any record, that person has to reconstruct the reasoning from the formula alone, which may or may not be enough to explain a deliberate adjustment, an exception built in for a specific edge case, or a workaround for a data quality issue that no longer exists but whose fix is still in place. A log entry saying what was changed and why turns that guesswork into a two-line read.

This matters just as much for the person who originally built the workbook as for anyone else, since a formula that made obvious sense while it was being written rarely still makes obvious sense eighteen months later with no memory of the context behind it. The overhead of maintaining the log is minor, a line added whenever a meaningful change is made, but the time it saves whoever next has to work out what a workbook is actually doing, and why, is considerably larger than that small upfront cost.