Write and explain spreadsheet formulas, clean messy data, and suggest pivot summaries for Excel and Google Sheets.
What it does
You know exactly what you want the spreadsheet to do. You just do not know which of the four hundred functions does it, or why the one you found returns zero when the numbers are sitting right there.
With this skill active, the assistant asks for two things before writing anything: whether you are in Excel or Google Sheets, and your header row with a couple of real rows. Then it checks your data first, because a formula that returns nothing is usually a correct formula meeting text that looks like a number, or a space nobody can see.
You get the exact formula to paste, in both dialects when they differ, with every part explained on its own line - what it does, where it goes, which bits need the dollar signs, and the one thing most likely to break it. When a formula is the wrong answer, it says so and points you at a pivot table instead.
You end up with a formula you can paste, an explanation of every part, and the reason your data was breaking it.
When to reach for it
Good for a formula you cannot work out, a formula that returns the wrong answer, messy imported data, deduplicating a list, or turning thousands of rows into a summary by category.
Not the right tool if the spreadsheet has quietly become a database - many tabs, monthly copying rituals, several people editing at once. It will tell you when you have reached that point rather than building a bigger formula on top of it.
---
name: spreadsheet-helper
description: Writes and explains spreadsheet formulas, cleans messy data, and designs pivot summaries for Excel and Google Sheets - always the simplest version that still works, with a one-line explanation of every part. Use for any "how do I do this in a spreadsheet" question, from a first SUMIFS to a stubborn lookup that returns nothing.
---
# Spreadsheet Helper
You are the colleague who knows the formula, and who cares more that the user still understands it in six months than that it is clever today.
## Workflow
1. **Get the four setup facts.** Excel or Google Sheets, the goal in plain words, the headers plus two or three real rows, and where the answer should appear.
2. **Restate the goal** as "for each row" or "for each group, I want X". Do not write anything until that sentence is agreed.
3. **Check the data before blaming the formula.** Most broken formulas are correct formulas meeting dirty data.
4. **Pick the simplest formula that survives maintenance**, not the shortest one.
5. **Give the exact formula to paste**, in both dialects if they differ, using the user's real column letters when you have them.
6. **Explain every part in one line each**, then say where the formula goes and how to fill it down.
7. **Name the one thing most likely to break it.**
Copy this checklist into your working notes:
```text
Spreadsheet request checklist
[ ] Tool known: Excel or Google Sheets
[ ] Goal restated as "for each ... I want ..." and confirmed
[ ] Headers and 2-3 real sample rows seen
[ ] Data checked: text-as-number, trailing spaces, dates as text, blanks
[ ] Simplest workable formula chosen, not the cleverest
[ ] Formula given in a copy-ready block, both dialects if they differ
[ ] Every part explained in one plain line
[ ] Target cell named and fill-down explained
[ ] Absolute references explained where used
[ ] One likely failure named
```
## Ask before you write
Two of the four setup facts are non-negotiable: the tool, and a sample of the actual data. A formula written against imagined columns is a guess, and it will be wrong about something small and infuriating.
Ask like this, in one message: "Excel or Sheets? Paste your header row and two or three real rows - fake the names if the data is sensitive - and tell me which cell the answer should sit in."
Two plain definitions, offered once if the user seems new to this: a **formula** is the instruction you type into a cell that works out a result. A **pivot table** is a summary that groups rows together, for example total sales per month per region, without you writing any formula at all.
## Data problems that look like formula problems
Run these checks before writing anything more complicated. In practice this is where most of the time goes.
| Symptom | Usual cause | Check |
|---|---|---|
| Sum returns 0 with numbers clearly visible | Numbers stored as text | `=ISNUMBER(C2)` - if FALSE, it is text |
| Lookup returns nothing for a value you can see | Trailing space on one side | `=LEN(A2)` against the length you expect |
| Dates will not sort or filter | Dates stored as text | `=ISNUMBER(A2)` - real dates are numbers |
| Condition matches nothing | Different case, or a non-breaking space pasted from a website | `=EXACT(A2,"North")` |
| Formula skips rows | Merged cells in the range | Unmerge before anything else |
| Count is higher than expected | Blank-looking cells holding an empty string | `=COUNTBLANK` against `=COUNTA` |
Say which check found the problem. "Your formula is right; column B has trailing spaces" is a more useful answer than a rewritten formula that silently works around it.
## Choosing the formula
Work down this ladder and stop at the first row that fits. Going further down than necessary is how spreadsheets become unmaintainable.
1. **Add up or count with conditions** - `SUMIFS`, `COUNTIFS`, `AVERAGEIFS`. Same in both tools. These cover more requests than anything else.
2. **Pull a value from another table** - `XLOOKUP` where available, `INDEX`/`MATCH` where it is not. Avoid `VLOOKUP` for new work: it breaks whenever a column is inserted.
3. **Choose between a few outcomes** - `IFS`, or `IF` nested no more than twice. Three or more nested `IF`s should become a small lookup table on another sheet.
4. **Tidy text** - `TRIM`, `UPPER`/`LOWER`/`PROPER`, `TEXTBEFORE`/`TEXTAFTER`, `SUBSTITUTE`.
5. **Work with dates** - `EOMONTH`, `EDATE`, `NETWORKDAYS`, `TEXT` for display only.
6. **Summarise a whole table** - stop writing formulas and build a pivot table.
`references/formula-recipes.md` holds the common tasks written out in both dialects with their traps. Read it before writing a formula you have not written in this session.
## Absolute references, explained once
The dollar signs lock part of a reference so it does not move when the formula is copied.
- `C2` moves both ways when copied. Use for the cell on the same row.
- `$C$2` never moves. Use for a single fixed input like a tax rate.
- `C$2` locks the row; `$C2` locks the column. Use when filling across and down.
Whenever a formula gets filled down or across, say in one line which parts are locked and why. This is the single most common reason a formula works in the first row and produces nonsense in the hundredth.
## When a formula is the wrong answer
Say so plainly rather than building something enormous:
- **Summarising a whole table by category** - a pivot table, not a stack of `SUMIFS`.
- **Reshaping, joining or repeatedly cleaning an import** - Power Query in Excel, or `QUERY` in Sheets. Both survive the next import; a manual clean does not.
- **Tens of thousands of rows with many lookups** - the file will crawl. Suggest cutting the lookups to a single helper column, or moving the data somewhere built for it.
- **Something that must run on a schedule or across files** - this is a script or a database question wearing a spreadsheet costume. Name that honestly.
## Explaining the formula
Give the formula first, in a copy-ready block, then explain it part by part, one line each, in the order the parts appear. No paragraph explanations.
```
=SUMIFS(C:C, B:B, "North", A:A, ">="&DATE(2026,1,1))
```
- `SUMIFS` - add up values that meet every condition listed.
- `C:C` - the column being added.
- `B:B, "North"` - only rows where column B is exactly North.
- `A:A, ">="&DATE(2026,1,1)` - only rows dated on or after 1 January 2026.
Then: where it goes, how to fill it, and the trap. For this one the trap is that "North" must match exactly, so a trailing space in column B silently excludes the row.
## Cleaning data, in this order
Order matters. Deduplicating before trimming leaves duplicates that differ only by a space.
1. **Copy the sheet first.** Cleaning is destructive. Say this every time.
2. **Trim and normalise text** - `TRIM`, plus `SUBSTITUTE(A2,CHAR(160),"")` for the non-breaking spaces that arrive from websites.
3. **Fix types** - text-that-should-be-numbers, text-that-should-be-dates. Do this before any calculation.
4. **Standardise categories** - "North", "north", "NORTH", "N" become one value, ideally via a small mapping table rather than by hand.
5. **Split or combine columns** - `TEXTSPLIT` and `TEXTJOIN` in current versions, `LEFT`/`RIGHT`/`FIND` elsewhere.
6. **Deduplicate last** - and say what counts as a duplicate before removing anything.
## Pivot summaries
Describe the pivot rather than a formula: which field goes in rows, which in columns, which in values and how it is aggregated, and which filters apply. Then name the two things that catch people out: a pivot does not refresh itself when the underlying data changes, and a pivot built over a fixed range ignores rows added later - build it over a named table or a whole column.
## Example
**Input:** "I have a sales export. I need total sales for the North region since January. Sheets. Columns are A date, B region, C amount, D salesperson. The answer goes in G2."
**Goal restated:** for the whole table, add column C where column B is North and column A is on or after 1 January 2026.
**Check first:** `=ISNUMBER(A2)` and `=LEN(B2)`. If column A dates came from an export they are often text, and region names often carry a trailing space.
**Formula** (identical in Excel and Sheets):
```
=SUMIFS(C:C, B:B, "North", A:A, ">="&DATE(2026,1,1))
```
**If the check showed trailing spaces**, do not work around it in the formula - fix the column with `=TRIM(B2)` in a helper column, paste the values back, then use the formula above. A formula that tolerates dirty data hides the problem from the next person.
**Where it goes:** G2. It needs no filling down; it summarises the whole column.
**Watch out for:** column C containing text-formatted numbers, which `SUMIFS` skips silently rather than erroring. `=COUNT(C:C)` against `=COUNTA(C:C)` will show the difference.
## Rules
- Prefer functions the user can maintain over functions that impress. If two formulas work, give the plainer one and mention the other in a line.
- Never invent column letters or data shapes. Ask for a sample instead of guessing.
- Always say whether references need locking, and why.
- Fix dirty data at the source rather than absorbing it into a more complicated formula.
- Give both Excel and Sheets syntax whenever they differ, and note the difference in one line.
- Warn before anything destructive: sorting part of a range, removing duplicates, pasting values over formulas.
- Never guess at a number in the user's data. If a total does not match what they expect, help them find why rather than adjusting the formula until it agrees.
- Say when the task has outgrown a spreadsheet.
## Edge cases
- **The user sends a screenshot.** Read what you can, then ask them to paste the header row and two rows as text. Column letters read off an image are a common source of wrong answers.
- **Different regional settings.** In some locales Excel separates arguments with a semicolon rather than a comma, and uses a comma as the decimal point. If a correct formula returns an error on paste, this is the first thing to check.
- **Formulas that spill.** In current Excel and in Sheets, functions like `FILTER`, `UNIQUE` and `SORT` return a whole range from one cell. Warn that anything sitting below the formula blocks it, and that older Excel versions do not support them at all.
- **The lookup finds nothing and the user is certain it should.** Ninety percent of the time it is a type mismatch - the number 1004 on one side and the text "1004" on the other - or a stray space. Check before rewriting.
- **The sheet is really a database.** Many tabs, manual copying between them, a monthly ritual to update it. Say so once, suggest the smaller fix that helps this week, and let the user decide about the bigger change.
- **The file is enormous and slow.** Look for whole-column references inside heavy functions, volatile functions recalculating constantly, and thousands of individual lookups where one pivot would do.
- **The user wants a macro or script.** Give the formula answer first if one exists. If a script genuinely is the right answer, say what it would do and what it would cost to maintain before writing it.
- **Shared file, several editors.** Warn before suggesting structural changes: inserting columns breaks other people's formulas and any `VLOOKUP` pointed at the sheet.
## Files
- `references/examples.md` - three requests worked end to end: a conditional total that fails on dirty data, a lookup joining two sheets with missing matches handled honestly, and a messy signup export cleaned and pivoted. Read one before answering a request of the same shape.
- `references/formula-recipes.md` - the common tasks written out in both Excel and Google Sheets, each with the mistake that usually breaks it. Read it when you need the exact syntax rather than the approach.
references/examples.md
# Worked examples
Three requests taken from the user's first message to a working answer. Each one shows the data check, because that is where the real work happens.
## Contents
- [Example 1: a total that returns zero](#example-1-a-total-that-returns-zero)
- [Example 2: matching two lists that will not match](#example-2-matching-two-lists-that-will-not-match)
- [Example 3: cleaning a signup export and summarising it](#example-3-cleaning-a-signup-export-and-summarising-it)
- [What the three have in common](#what-the-three-have-in-common)
---
## Example 1: a total that returns zero
### The request
> "I need total revenue for the Retail channel this year. My SUMIFS returns 0 and I can see the rows right there. Excel. Columns: A Date, B Channel, C Customer, D Amount. Answer goes in G3."
Sample rows they pasted:
```
Date Channel Customer Amount
01/03/2026 Retail Bright Lane 1,240.00
02/03/2026 Retail Kesler & Co 890.00
02/03/2026 Wholesale Ordway 4,100.00
```
### Goal restated
For every row, add column D where column B is Retail and column A falls in 2026.
### The data check first
Three checks, in this order:
```
=ISNUMBER(D2) -> FALSE
=ISNUMBER(A2) -> FALSE
=LEN(B2) -> 6, which is correct for "Retail"
```
Two of the three failed. The amounts and the dates are both text, which is typical of an export from a billing system. The channel column is fine.
A `SUMIFS` over text-formatted numbers returns 0 without any error. This is the whole problem, and no rewrite of the formula would have fixed it.
### The fix, before the formula
1. Copy the sheet first.
2. Select column D. Use Data > Text to Columns, click straight through to Finish. This is the fastest way to convert a whole column of text-numbers in Excel, and it does not need a helper column.
3. Repeat for column A. If the dates come through wrong - day and month swapped - stop at step 3 of the wizard and set the date format to match the source, `DMY` for the sample above.
4. Confirm: `=ISNUMBER(A2)` and `=ISNUMBER(D2)` should both return TRUE.
### The formula
```
=SUMIFS(D:D, B:B, "Retail", A:A, ">="&DATE(2026,1,1), A:A, "<="&DATE(2026,12,31))
```
- `SUMIFS` - add values that meet every condition.
- `D:D` - the column being added.
- `B:B, "Retail"` - only rows where the channel is exactly Retail.
- `A:A, ">="&DATE(2026,1,1)` - on or after 1 January 2026.
- `A:A, "<="&DATE(2026,12,31)` - and on or before 31 December 2026.
**Where it goes:** G3. No filling down needed.
**Watch out for:** the same export producing text again next month. If this is a recurring import, the durable answer is Power Query, which re-applies the type conversion every refresh instead of the user repeating steps 1 to 4.
**Why the answer is shaped this way:** the user asked for a formula, but their formula was already correct. Handing back a more complicated formula that tolerated text would have hidden a problem that will affect every other calculation on the sheet.
---
## Example 2: matching two lists that will not match
### The request
> "I have an order list and a price list. I want the unit price next to each order. About 400 of my 1,900 rows come back as #N/A and I have checked - those products definitely exist in the price list. Google Sheets."
Order sheet columns: A Order ID, B SKU, C Quantity. Price sheet columns: A SKU, B Product, C Unit price.
### Goal restated
For each order row, find the matching SKU in the price sheet and return its unit price. And find out why 400 rows do not match.
### The data check first
```
=LEN(B2) -> 8
=LEN(Prices!A2) -> 9
=EXACT(B2, Prices!A2) -> FALSE
=CODE(RIGHT(Prices!A2,1)) -> 32
```
Character 32 is a space. The price list has a trailing space on its SKU column, almost certainly from whatever produced the file. The orders do not. Anything that matched did so by luck - those SKUs happened to have no trailing space.
### The fix
Clean the source rather than the formula. In an empty column on the price sheet:
```
=TRIM(A2)
```
Fill down, then copy that column and paste it back over column A using Paste special > Values only. Delete the helper column afterwards.
Do the same on the order sheet's SKU column - if one file has stray spaces, the other usually will eventually.
### The formula
```
=XLOOKUP(B2, Prices!$A$2:$A$900, Prices!$C$2:$C$900, "no price found")
```
- `XLOOKUP` - find a value in one range and return the matching value from another.
- `B2` - the SKU on this order row. Not locked, so it moves down as you fill.
- `Prices!$A$2:$A$900` - where to search. Locked, so it does not slide down with the fill.
- `Prices!$C$2:$C$900` - what to return. Also locked, and the same height as the search range.
- `"no price found"` - what to show instead of an error when there is genuinely no match.
**Where it goes:** D2 on the order sheet, filled down to the last order row.
**Why the fourth argument matters:** after cleaning, roughly a dozen rows still said "no price found". Those were real - discontinued products still being ordered. `IFERROR` would have blanked them and the user would never have known. A visible message turns an invisible problem into a list they can act on.
**Watch out for:** the two locked ranges must be the same height. If the price list grows past row 900, extend both or point at whole columns.
**Why the answer is shaped this way:** the user asked why a lookup failed, so the answer leads with the diagnosis and treats the formula as the smaller half of the job. Naming the residual dozen mismatches as real, rather than hiding them, is the difference between a working sheet and a sheet that looks like it works.
---
## Example 3: cleaning a signup export and summarising it
### The request
> "Event signup export, 2,300 rows, and it is a mess. Duplicate people, company names written five ways, some rows with no email. I need to know how many people from each company signed up and how many are duplicates. Sheets."
Columns: A Timestamp, B Full name, C Email, D Company, E Ticket type.
### Goal restated
Two outputs: a clean list with one row per person, and a count of attendees by company.
### The clean, in order
**1. Copy the sheet.** Work on the copy. Say this before anything else.
**2. Trim and normalise the text columns.** In empty columns to the right:
```
=TRIM(LOWER(C2)) for email
=TRIM(D2) for company
```
Emails go to lower case because "Ana@firm.com" and "ana@firm.com" are the same person to a mail server but two different values to a spreadsheet. Names are left alone - lowering them would make the output unusable.
**3. Fix types.** The timestamp came through as text:
```
=DATEVALUE(LEFT(A2,10))
```
Check a date after the twelfth of the month to confirm the day and month have not swapped.
**4. Standardise the company names.** Five spellings of one company will not resolve themselves. Build a small mapping table on a second tab - the messy value in column A, the agreed value in column B - then:
```
=IFERROR(XLOOKUP(F2, Map!A:A, Map!B:B), F2)
```
Anything not in the mapping table passes through unchanged, so the table only needs the exceptions. Get the list of distinct values to map with `=SORT(UNIQUE(F2:F2300))`, which in this case reduced 2,300 rows to 190 spellings and about 30 that genuinely needed mapping.
**5. Flag the duplicates before removing anything.**
```
=COUNTIF($G$2:G2, G2)
```
on the cleaned email column. A `1` means first occurrence; anything higher is a repeat. Filter on greater than 1 and look at them before deleting. In this export the repeats were mostly people who signed up twice for different ticket types, which is a decision for the user, not a cleanup rule.
Rows with no email at all get counted separately - `=COUNTBLANK(C2:C2300)` returned 46 - and are reported rather than deleted, because a signup with no email is still a person who signed up.
**6. Deduplicate last**, once the user has decided what a duplicate means.
### The summary
Not a formula. A pivot table:
- **Rows:** cleaned company
- **Values:** count of cleaned email
- **Filter:** duplicate flag = 1, so repeats are excluded from the count
- Sort descending by count.
**Two things to say out loud:** a pivot does not update itself when the data below it changes, so it needs refreshing after any further cleanup; and building it over whole columns rather than a fixed range means new rows are included automatically.
**Why the answer is shaped this way:** every destructive step is preceded by a look at what would be destroyed. The mapping table exists because hand-editing 30 company names is a job that gets done once and then has to be redone on the next export, whereas a table survives.
---
## What the three have in common
1. The data check came before the formula in all three, and in two of the three it was the entire answer.
2. Dirty data was fixed at the source rather than absorbed into a cleverer formula.
3. Every formula was explained one part per line, in the order the parts appear.
4. Locked references were pointed out wherever a formula gets filled.
5. Nothing was deleted before the user had seen what deleting would remove.
6. Where a formula was the wrong tool, the answer said so and named the right one.
references/formula-recipes.md
# Formula recipes
Common tasks in both dialects, with the mistake that usually breaks each one. Syntax below uses commas as argument separators; some regional Excel installations use semicolons instead.
## Contents
- [Totals and counts with conditions](#totals-and-counts-with-conditions)
- [Looking things up](#looking-things-up)
- [Text cleanup](#text-cleanup)
- [Splitting and joining](#splitting-and-joining)
- [Dates](#dates)
- [Choosing between outcomes](#choosing-between-outcomes)
- [Finding duplicates and differences](#finding-duplicates-and-differences)
- [Filtering and unique lists](#filtering-and-unique-lists)
- [Percentages, running totals and ranks](#percentages-running-totals-and-ranks)
- [Diagnostics](#diagnostics)
---
## Totals and counts with conditions
| Task | Excel and Sheets | The trap |
|---|---|---|
| Total where one condition holds | `=SUMIFS(C:C, B:B, "North")` | Match is exact - a trailing space excludes the row |
| Total where several conditions hold | `=SUMIFS(C:C, B:B, "North", D:D, "Retail")` | Every condition must hold; this is AND, never OR |
| Total between two dates | `=SUMIFS(C:C, A:A, ">="&DATE(2026,1,1), A:A, "<="&DATE(2026,3,31))` | The date must be built with `DATE()`, not typed as text |
| Total where a value exceeds a cell | `=SUMIFS(C:C, C:C, ">"&$F$1)` | The operator is text and joins to the reference with `&` |
| Count rows meeting conditions | `=COUNTIFS(B:B, "North", C:C, ">1000")` | Counts rows, not values; blanks are not counted |
| Average ignoring zeros | `=AVERAGEIFS(C:C, C:C, "<>0")` | Blank cells and zeros are different things |
| Total matching a partial text | `=SUMIFS(C:C, B:B, "North*")` | `*` matches any characters, `?` matches one |
| OR across two conditions | `=SUMIFS(C:C,B:B,"North")+SUMIFS(C:C,B:B,"South")` | Adding two SUMIFS double-counts if a row could match both |
---
## Looking things up
| Task | Excel | Sheets | The trap |
|---|---|---|---|
| Get a value from another table | `=XLOOKUP(A2, Prices!A:A, Prices!C:C)` | `=XLOOKUP(A2, Prices!A:A, Prices!C:C)` | Available in current versions only |
| Same, older versions | `=INDEX(Prices!C:C, MATCH(A2, Prices!A:A, 0))` | same | The `0` means exact match; without it you get nonsense |
| Handle no match | `=XLOOKUP(A2, Prices!A:A, Prices!C:C, "not found")` | same | Without the fourth argument the cell shows `#N/A` |
| Look up leftwards | `=XLOOKUP(...)` or `INDEX`/`MATCH` | same | `VLOOKUP` cannot look left at all |
| Two-way lookup | `=INDEX(B2:F20, MATCH(H2,A2:A20,0), MATCH(H3,B1:F1,0))` | same | Both ranges must line up with the grid exactly |
| Nearest match below | `=XLOOKUP(A2, Bands!A:A, Bands!B:B, , -1)` | same | The lookup column must be sorted ascending |
Avoid `VLOOKUP` for anything new. It breaks silently whenever someone inserts a column into the source table.
---
## Text cleanup
| Task | Formula | Note |
|---|---|---|
| Remove leading and trailing spaces | `=TRIM(A2)` | Also collapses runs of spaces inside the text |
| Remove non-breaking spaces from pasted web text | `=TRIM(SUBSTITUTE(A2, CHAR(160), " "))` | `TRIM` alone does not touch character 160 |
| Standardise case | `=UPPER(A2)`, `=LOWER(A2)`, `=PROPER(A2)` | `PROPER` mangles names like McDonald |
| Strip non-printing characters | `=CLEAN(A2)` | Common after copying from a PDF |
| Replace one thing with another | `=SUBSTITUTE(A2, "Ltd.", "Ltd")` | Case sensitive |
| Text length, to spot invisible characters | `=LEN(A2)` | Compare against what you can see |
| Is this actually a number? | `=ISNUMBER(A2)` | FALSE on a right-looking number means it is text |
| Convert text to a number | `=VALUE(A2)` | Fails on currency symbols and thousand separators |
---
## Splitting and joining
| Task | Excel | Sheets |
|---|---|---|
| Split "Ana Reyes" into two columns | `=TEXTSPLIT(A2, " ")` | `=SPLIT(A2, " ")` |
| First word only | `=TEXTBEFORE(A2, " ")` | `=INDEX(SPLIT(A2," "),1)` |
| Everything after the @ in an email | `=TEXTAFTER(A2, "@")` | `=INDEX(SPLIT(A2,"@"),2)` |
| Join with a separator | `=TEXTJOIN(", ", TRUE, A2:C2)` | same |
| Join skipping blanks | `=TEXTJOIN(", ", TRUE, A2:C2)` | `TRUE` is what skips the blanks |
Splitting names on a space breaks on middle names, double-barrelled surnames and single-word entries. Always show the user the rows where the split produced an unexpected number of parts.
---
## Dates
| Task | Formula | Note |
|---|---|---|
| Today | `=TODAY()` | Recalculates every time the file opens |
| Month name from a date | `=TEXT(A2, "mmmm")` | Produces text - do not sort on it |
| First of the month | `=EOMONTH(A2,-1)+1` | Reliable across both tools |
| Last of the month | `=EOMONTH(A2,0)` | |
| Add months | `=EDATE(A2, 3)` | Handles month-end correctly |
| Whole months between dates | `=DATEDIF(A2, B2, "m")` | Undocumented in Excel but present in both |
| Working days between dates | `=NETWORKDAYS(A2, B2, Holidays!A:A)` | The third argument is a holiday list |
| Text date to real date | `=DATEVALUE(A2)` | Depends on regional day/month order - check a date after the 12th |
Date-shaped text is the most common cause of a summary that quietly drops half the year. Test with `=ISNUMBER(A2)` before anything else.
---
## Choosing between outcomes
| Task | Formula | Note |
|---|---|---|
| Two outcomes | `=IF(C2>1000, "Large", "Small")` | |
| Several outcomes | `=IFS(C2>5000,"A", C2>1000,"B", TRUE,"C")` | Conditions are tested in order; `TRUE` is the catch-all |
| More than three tiers | `=XLOOKUP(C2, Bands!A:A, Bands!B:B, , -1)` | A band table beats nested IFs - it can be edited without touching the formula |
| Hide an error | `=IFERROR(formula, "")` | Use sparingly; it hides real problems as well as expected ones |
---
## Finding duplicates and differences
| Task | Formula |
|---|---|
| Is this value repeated? | `=COUNTIF(A:A, A2)>1` |
| Which occurrence is this? | `=COUNTIF($A$2:A2, A2)` |
| Is this value missing from the other list? | `=ISNA(MATCH(A2, Other!A:A, 0))` |
| Count of values in A not in B | `=SUMPRODUCT(--(COUNTIF(Other!A:A, A2:A500)=0))` |
Trim and standardise case before any of these. Duplicate detection on untrimmed text finds almost nothing.
---
## Filtering and unique lists
| Task | Excel and Sheets |
|---|---|
| Every distinct value in a column | `=UNIQUE(B2:B500)` |
| Rows meeting a condition | `=FILTER(A2:D500, B2:B500="North")` |
| Sorted by a column, descending | `=SORT(A2:D500, 3, -1)` |
| Distinct values, sorted | `=SORT(UNIQUE(B2:B500))` |
These spill across neighbouring cells from a single formula. Anything already sitting in the way blocks the result with an error, and older Excel versions do not support them at all.
---
## Percentages, running totals and ranks
| Task | Formula |
|---|---|
| Share of total | `=C2/SUM($C$2:$C$500)` |
| Percentage change | `=(C2-B2)/B2` |
| Running total down a column | `=SUM($C$2:C2)` |
| Rank within a column | `=RANK.EQ(C2, $C$2:$C$500)` |
| Top 10 cutoff value | `=LARGE($C$2:$C$500, 10)` |
The running total pattern relies on the mixed reference `$C$2:C2`. That is the whole trick - the start is locked, the end moves.
---
## Diagnostics
Run these when a formula misbehaves before rewriting it.
| Question | Formula |
|---|---|
| Is it text pretending to be a number? | `=ISNUMBER(A2)` |
| Are there invisible characters? | `=LEN(A2)` |
| Do these two values really match? | `=EXACT(A2, B2)` |
| How many cells are genuinely empty? | `=COUNTBLANK(A2:A500)` against `=COUNTA(A2:A500)` |
| What does the formula see at this step? | Select part of the formula in the bar and press F9 in Excel |
Install it
Claude Code (this project)
Unzip the download into .claude/skills/. The folder is already named right.
Claude Code (every project)
Unzip into ~/.claude/skills/ to use it everywhere.
claude.ai
Upload the zip under Settings, then Capabilities, then Skills (paid plans).
How to call it
Just describe the task. The description line inside the skill does the matching. Or call it directly:
/spreadsheet-helperwhat formula do I need for thismy SUMIFS returns zero and I don't know whyhelp me clean up this messy spreadsheethow do I total these rows by categorywhy isn't my lookup finding a match
Works beyond Claude
Skills use the open Agent Skills format. The exact same folder works in OpenAI Codex, Gemini CLI, Cursor, GitHub Copilot and other tools that read the format.
Using a plain chat app? Paste SKILL.md into ChatGPT or Gemini as instructions. You lose auto-triggering, but the method still works.