Spreadsheet Skills That Prevent Expensive Mistakes

A spreadsheet is not a tiny database, and pretending it is causes most spreadsheet disasters. Use it as a visible calculation tool: keep raw data boring, make transformations explicit, and let summaries sit on top. Here is the working set I trust for budgets, operations, and analysis.

🎙️ Published & recorded:

01References: what moves when you copy

Relative references move; absolute references stay put. That sentence is easy. The expensive part is noticing which input is a rule shared by every row. If tax lives in B1, lock it as $B$1. If price changes row by row in C, leave C2 relative. Press F4 while editing a reference to cycle the dollar signs.

Quantity in B2 · unit price in C2 · tax rate in F1
=B2*C2*(1+$F$1)     ✓ copy down: rows move, tax does not
=B2*C2*(1+F1)       ✗ copy down: F1 becomes F2, F3...

mixed references are for grids
=$A2*B$1            lock column A; lock row 1
Failure seen in a real budget
A finance sheet showed tax falling to zero after its first line. The copied formula had changed F1 to blank F2. Fix: click the first wrong cell, inspect the formula bar, change the rule cell to $F$1, then fill down and reconcile the grand total against quantity × price before tax.

02XLOOKUP: join tables without column counting

Use XLOOKUP instead of VLOOKUP when it exists. You name the key column and the return column directly, it can look left, and exact match is the default. Better still, decide what a missing key means instead of hiding it with a blank.

=XLOOKUP(A2, Products[SKU], Products[Price], "MISSING SKU")

#N/A  when no [if_not_found] argument is supplied
Fix: 1. copy the failing SKU into the Products filter
     2. compare exact characters and data types
     3. add the product or correct the input
     4. use "MISSING SKU", not "", so bad rows stay visible
The silent invoice failure
An order imported SKU 00127 as number 127. The product table stored text, so the formula returned the real error #N/A. Converting both key columns to text and restoring leading zeros fixed it. Wrapping everything in IFERROR(...,0) would have produced a plausible but false zero-dollar line.

03FILTER and SORT: build live views

Stop copying rows into a second tab called “Final v7.” A live view should be a formula, not a monthly ritual. FILTER chooses rows; SORT orders the result. Keep the source as a proper table so new rows join automatically.

=SORT(FILTER(Orders, Orders[Status]="Late", "No late orders"), 5, -1)
returns late orders, newest/highest column 5 first

#VALUE!
FILTER ranges have different heights:
=FILTER(A2:F500, G2:G499="Late")
Fix: make both ranges end on row 500, or use table columns.
A believable wrong report
A team filtered rows 2–500 with a condition from rows 3–501. Some spreadsheet versions raised #VALUE!; another hand-built workaround shifted every status by one customer. Fix the dimensions first, test one known order ID, then count the output against COUNTIF(Orders[Status],"Late").

04Pivot tables: summarize before decorating

A pivot table answers “how much, grouped by what?” Put a category in Rows, a measure in Values, and an optional field in Columns or Filters. My rule: build the pivot before the chart. If the summary is nonsense, a polished chart only makes the nonsense persuasive.

Question: revenue by region and month
Rows:    Region
Columns: Order date → group by Month
Values:  Revenue → Sum       not Count
Filter:  Status ≠ Cancelled

Check: pivot grand total = SUM source Revenue after same filter
Why a revenue pivot suddenly counted orders
The source column contained $1,200 USD as text. The pivot silently chose Count and reported 184 instead of $213,400. Fix: remove currency words, convert the column to numbers, refresh the pivot, change “Summarize values by” to Sum, then reconcile its grand total to the source.

05Dates: numbers wearing a format

A real spreadsheet date is a serial number displayed as a calendar date. Text that looks like a date is just text. That difference explains broken sorting, blank monthly pivots, and arithmetic that refuses to work. Store one date per cell, use an unambiguous import format such as ISO 2026-07-24, and apply display formatting afterward.

=A2+30                    30 calendar days later
=EDATE(A2,1)              same day next month
=EOMONTH(A2,0)            last day of this month
=NETWORKDAYS(A2,B2)       working days inclusive

#VALUE! from ="July 24, 2026"-A2
Fix: convert imported text with DATEVALUE after confirming locale.
The 03/04 disaster
A US colleague read 03/04/2026 as March 4; the UK office read April 3. Delivery metrics shifted by a month without any formula error. Fix: preserve the original import, parse day/month/year explicitly, display 24 Jul 2026, and spot-check dates where both first numbers are 12 or less.

06Text cleanup before matching

Most “lookup bugs” are dirty text. TRIM removes ordinary extra spaces, CLEAN removes many nonprinting characters, and SUBSTITUTE handles known intruders. Preserve the raw column. Create a separate cleaned key so the transformation can be audited.

=UPPER(TRIM(CLEAN(A2)))

non-breaking spaces copied from a web page survive TRIM:
=TRIM(SUBSTITUTE(A2,CHAR(160)," "))

#N/A although "ACME-42" looks identical
Diagnose: =LEN(A2) and =UNICODE(RIGHT(A2,1))
Fix: remove the discovered character in a helper column.
A one-character mismatch
Customer Northwind failed every lookup because the imported value ended with a non-breaking space. Clicking the cell showed nothing unusual. LEN reported 10 instead of 9. Fix: replace character 160, trim, verify the length, then point lookups at the cleaned key.

07Formula errors are messages, not decoration

Do not paint errors white and do not start with IFERROR. Read the message. #N/A means no match. #VALUE! means the wrong kind of input. #REF! means the formula points somewhere that no longer exists. Each has a different repair.

#N/A     → inspect key, type, spaces, and source membership
#VALUE!  → inspect text where a number/date is expected
#REF!    → deleted/moved row, column, sheet, or closed dependency

Real broken formula after deleting column D:
=SUM(B2:C2)+#REF!
Fix: Undo if possible; otherwise identify the intended source
from a prior version, restore the reference, and test known rows.
Failure: deleting “unused” columns
An analyst deleted a hidden exchange-rate column and saw #REF! across the forecast. They replaced errors with zero to meet a deadline, understating costs. Correct recovery: stop editing, restore the previous file version, compare formulas, reinstate the rate column or named range, then add a control total in both currencies.

08Spilled arrays need empty space

Modern formulas return many cells from one formula. That is a spilled array. The top-left cell owns the result; the surrounding cells must stay empty. Do not type into the middle of it. Refer to the whole result with the spill operator, such as J2#.

=UNIQUE(Orders[Region])       one formula, many rows
=SORT(UNIQUE(Orders[Region]))

#SPILL!  "There's already data in E7."
Fix: select the warning → Select Obstructing Cells → move or
clear those cells; unmerge cells; place formula outside a table.
Never clear blindly: inspect the obstruction first.
Failure: the invisible blocker
A dynamic customer list returned #SPILL! because cell E37 contained a single apostrophe left from a manual note. Delete appeared to do nothing from the top. Fix: use “Select Obstructing Cells,” inspect E37, clear its contents, and protect the spill output area from manual entry.

09Do not build a 12-level nested IF

I am firmly against twelve-layer nested IF formulas. They are code with no names, no tests, and brackets as camouflage. If business rules form a mapping, put them in a table and use XLOOKUP. If rules are ranges, store thresholds in ascending order and use an approximate match. Rules belong where another person can read them.

=IF(A2<10,"Tiny",IF(A2<25,"Small",IF(A2<50,"Medium",
 IF(A2<100,"Large",IF(... twelve levels ...)))))

Threshold table:
Minimum | Band
0       | Tiny
10      | Small
25      | Medium
50      | Large

=XLOOKUP(A2, Bands[Minimum], Bands[Band],, -1)
Now changing a rule means editing a row, not surgery.
Failure: order matters
A discount formula checked “revenue above $10,000” before “revenue above $50,000,” so top customers received the smaller discount. Repair: move thresholds to a sorted table, test exact boundaries (9,999; 10,000; 49,999; 50,000), and have the policy owner sign off on the table rather than the formula.

10The workbook handoff checklist

A dependable workbook is boring to inherit. Raw inputs are untouched. Rules live in named cells or tables. Errors remain visible until resolved. A summary reconciles to the source. Before sending, use this checklist.

 one rectangular raw-data table; one field per column
 stable IDs, not names, used as lookup keys
 shared rule cells locked with $ or named
 dates are real dates; amounts are real numbers
 XLOOKUP missing cases say "MISSING", never silent zero
 pivots refreshed and grand totals reconciled
 #N/A, #VALUE!, #REF!, #SPILL! investigated
 boundary cases tested; 12-level IF replaced by a table
 a clean copy opens correctly on another machine