Brantwood Garden Centres reported £63,208.10 of October sales. The shops took £75,773.35. Every branch tab balanced to its own till export, nothing errored, and the group tab came out £12,565.25 light.
That tab is one formula. =VSTACK(Alderwell:Thurlby!A2:F200) stacks nine branch sheets into a single list, and SUMIFS reads the list. It is the tidiest thing in the workbook.
A stack aligns by position, never by heading. Column F of one tab lands under column F of the next, whatever the two headings say, and nothing in Excel compares them.
| Measure | Figure |
|---|---|
| Branch tabs | 9 |
| Sales in those tabs | 1,072 |
| Rows in the stack | 1,592 |
| Reported | £63,208.10 |
| Actually taken | £75,773.35 |
| Short by | £12,565.25 |
Four faults made that gap, and two of them pull in opposite directions, so the total looked like a quiet month. A branch missing, a tab counted twice, two columns swapped, and a range that stops at row 200.
What you need.
VSTACKandHSTACKneed Microsoft 365 or Excel 2024.FILTER,SORT,UNIQUE,LETand spill references such as=H2#need Microsoft 365 or Excel 2021 and later.
SUMIFS,COUNTIFS,SUMPRODUCT,INDEX,COUNTA,MODand 3-D references work in every version this century. Section 11 is for the build that has none of the new ones.Garden centres are only the example. Depots, clinics, sites, funds, subsidiaries: one tab each, one summary tab, and the same silence.
01Nine Tabs, One Stack, £12,565.25 Short
Nine Branch Tabs, One Stack, £12,565.25 Short
The October reconciliation for Brantwood Garden Centres, in A2:I10. It is not the stack itself; it is the check somebody should have run against it. Column C is the sales each branch tab holds, D is the rows the stack took from that tab, F is the amount the stack carries and G is the amount the branch actually took. Six branches agree to the penny. Ferncliffe contributed nothing, because its tab sits outside the `Alderwell:Thurlby` span; Greenhall (2) contributed £9,110.00 that does not exist, because a copied tab landed inside it; Oakmere's £12,742.60 went into the units column and its 486 units into the money column, because the branch changed till systems and a stack aligns by position; and Thurlby lost £1,938.45 off the bottom, because A2:F200 is 199 rows and the branch wrote 214 sales. Net, the group reported £63,208.10 against £75,773.35 taken. Gross, £30,785.25 of October landed somewhere other than where it belongs.
fxCells with formulas are highlighted in green
Hover over formula cells to see the formula and highlight referenced cells
The sheet above is not the stack. It is the reconciliation nobody had run against it: one row per branch tab, what the stack took from that tab, and what the tab itself totals.
Column F is the amount the stack carries. Column G is the amount the branch took. Six branches agree to the penny. Three do not, and one of the three is wrong in the group's favour.
| Branch | In the stack | In the tab | Difference |
|---|---|---|---|
| Ferncliffe | £0.00 | £7,480.20 | −£7,480.20 |
| Greenhall (2) | £9,110.00 | £0.00 | +£9,110.00 |
| Oakmere | £486.00 | £12,742.60 | −£12,256.60 |
| Thurlby | £10,402.15 | £12,340.60 | −£1,938.45 |
Net, the group is £12,565.25 short. Add the four faults without their signs and £30,785.25 of October landed somewhere other than where it belongs.
Scenario: Build this reconciliation for your own summary before you trust it. Put the branch names down a column, =SUMIFS(F:F,A:A,$A2) beside each one against the stack, and subtract each branch tab's own total. Every row should come out at nought.
02VSTACK Stacks by Position, Not by Heading
VSTACK takes arrays and puts each one under the last. Hand it a 3-D reference and it takes the same block from every tab between the two you name, in the order the tabs sit in.
Nothing in it reads a heading. The branch tabs came from one template in 2019, so for six years column F held the money on every one of them. That is a convention, and a convention is not a rule.
One cell says whether two tabs still agree:
=SUMPRODUCT(--(Alderwell!$A$1:$F$1=Oakmere!A1:F1))
It counts the headings that match, position by position. Six means aligned. Anything less is a tab the stack will scramble without a word, and on this workbook it returned 4.
Scenario: Write that SUMPRODUCT once for each tab you stack, pointing the second reference at a different sheet each time, and fill it down. Any row below your column count is a sheet to open before the next report goes out.
03The Branch That Stacked Counts as Money
Oakmere changed till systems in September. The new export writes Amount in column E and Units in column F. Every other branch, and the template they all came from, does it the other way round.
So the stack filed Oakmere's £12,742.60 of sales as a count of units, and its 486 units as £486.00. The group total lost £12,256.60 and gained nothing that looked like an error.
The tell was sitting in a column nobody totals. October's unit count came out at 20,324.60. A count of bags of compost with pence in it is a column that has been swapped, and it is the cheapest check on this page.
=SUMPRODUCT(--(MOD(E2:E1593,1)<>0))
That counts the rows whose unit figure is not a whole number. It came back with 149: the Oakmere rows whose amount carries pence. The other eight of its 157 sales were round pounds.
Scenario: Find the column on your own stack that can only hold whole numbers — units, headcount, tickets, cases — and type =SUMPRODUCT(--(MOD(E2:E1593,1)<>0)) over it. Anything but nought means some tab is feeding a different column into it.
04Every Tab Gives 199 Rows, Sales or Not
A 3-D reference takes the same block from every tab, so A2:F200 is 199 rows whether a branch sold 199 things or 96. The empty rows come through, and they do not come through empty.
A reference to an empty cell returns 0, not a blank. The stack holds 493 rows of zeros, with 00/01/1900 in the date column, and COUNTA counts every one of them as data.
That is why the average basket moved. £63,208.10 over 1,592 rows is £39.70. Over the 1,099 rows that are sales it is £57.51. Both are arithmetic; only one answers the question the report asked.
FILTER strips the padding, and the test is where people lose an afternoon: the blanks are zeros, so <>"" keeps every one of them.
=LET(s, VSTACK(Alderwell:Thurlby!A2:F200),
FILTER(s, INDEX(s,0,1)<>0))
Scenario: Count what your stack is made of before you report an average from it. Put =ROWS(H2#) in one cell and =SUMPRODUCT(--(INDEX(H2#,0,1)<>0)) beside it; if the two disagree, every per-row figure in the report is diluted.
05The Branch That Was Never in the Stack
Ferncliffe opened in September. Its tab went where Excel puts a new sheet when you ask at the end: one place to the right of Thurlby. The formula says Alderwell:Thurlby.
A 3-D reference means the tabs physically between those two, in tab order. Not the branches, not the alphabet, and not whatever the workbook contains today. £7,480.20 sat one tab outside the span in a sheet that balanced perfectly on its own.
Bookend the span with two empty sheets. Name them Start and End, put one at each end of the branch tabs, and write =VSTACK(Start:End!A2:F200). Any tab dragged between them joins the stack.
That is the whole trick, and its price is the one in section 6: a span takes every tab inside it, including the ones you did not mean.
Scenario: Add the two bookend sheets to your own workbook and repoint the stack at them. Then drag an empty tab in between and watch =ROWS(H2#) grow the moment you let go of the mouse.
06The Copy That Was Counted Twice
Greenhall's manager wanted to try a different layout, right-clicked the tab and chose Move or Copy. Excel puts the copy immediately after the original, which is inside the span, so the stack took it.
£9,110.00 counted twice. On its own that would have shown: the group total would have been £9,110.00 too high and somebody would have asked. Against Ferncliffe and Oakmere it closed the gap and made four faults look like a slow October.
Two one-cell checks find it. =ROWS(s)-ROWS(UNIQUE(s)) returns 134, which is the number of rows the stack holds twice over. =COUNTA(UNIQUE(INDEX(s,0,1))) returns 8: seven branch names and the zero the blank rows contribute, for eight tabs stacked.
Scenario: Run =ROWS(H2#)-ROWS(UNIQUE(H2#)) over your own stack today. Anything above nought is a duplicated tab or a genuinely repeated line, and the difference between those two is worth five minutes.
07The Range That Stops at Row 200
Thurlby is the biggest branch: 214 sales in October. A2:F200 takes 199 rows from every tab, so fifteen of them, £1,938.45, are in the workbook and not in the report.
A span cannot grow its rows. It has no idea how long each tab is, and stretching it to A2:F5000 multiplies the blank rows by twenty-five without ever being certain.
Tables grow by themselves, and a 3-D reference cannot hold one. =VSTACK(tAlderwell,tBexmoor,tFerncliffe) over the branch tables follows each one as it fills, and names every tab you meant to include. A tenth branch then has to be added by hand.
Pick which half you want automatic: new tabs for free, or new rows for free. Then write a check against the half you did not pick, because that is the half that will go wrong.
| Approach | New tab joins | New rows join |
|---|---|---|
3-D span Start:End!A2:F200 | Yes | Up to row 200 |
Listed tables tAlderwell,tBexmoor | No | Yes |
| Power Query from a folder | Yes | Yes |
Scenario: For each tab, put =COUNTA(Thurlby!A2:A10000) beside the stack's own =COUNTIF(INDEX(H2#,0,1),"Thurlby") and compare the pair. A branch whose stacked count stops exactly at your range length has lost its tail.
08Different Widths Pad the Stack With #N/A
List the arrays by hand instead of using a span and the widths stop being guaranteed. VSTACK pads the narrow ones with #N/A, so a five-column tab among six-column tabs gets a column of errors rather than a shift.
That is the kind behaviour. The errors are loud, they survive into every total that does not ignore them, and =IFERROR(VSTACK(...),"") turns them into blanks once you have understood why they are there.
HSTACK does the same thing sideways, padding short arrays with #N/A along the bottom. Either way the padding tells you the inputs disagree, which is more than the swapped column in section 3 ever did.
Scenario: Take a copy of one branch tab, delete a column from it, stack it and watch where the #N/A lands. Then put the column back, swap two columns instead, and watch the stack say nothing at all.
Try it in the grid09Five Checks Above the Table
Each of these is one cell, and each one failed on this workbook. Put them above the stack where the report is read, not on a tab called Checks that nobody opens.
| Check | Formula | Here |
|---|---|---|
| Rows in the stack | =ROWS(H2#) | 1,592 |
| Rows that are sales | =SUMPRODUCT(--(INDEX(H2#,0,1)<>0)) | 1,099 |
| Rows held twice | =ROWS(H2#)-ROWS(UNIQUE(H2#)) | 134 |
| Distinct values in column A | =COUNTA(UNIQUE(INDEX(H2#,0,1))) | 8 |
| Unit figures with pence | =SUMPRODUCT(--(MOD(INDEX(H2#,0,5),1)<>0)) | 149 |
The sixth costs a column rather than a cell, and it is the one that would have caught all four faults: the per-branch reconciliation from section 1, stacked total against branch total, every month.
10Reading the Stack: SUMIFS Needs a Range
A stack held inside LET is an array in memory, and SUMIFS and COUNTIFS do not take arrays. They take ranges. Point them at one and the answer is #VALUE!, which at least is an answer.
So let the stack spill onto a sheet. If =VSTACK(...) sits in H2, then H2# is a real range that grows with it, and =SUMIFS(M2:M1593,H2:H1593,$A2) totals a branch the ordinary way.
Inside LET, use SUMPRODUCT instead: =SUMPRODUCT((INDEX(s,0,1)=$A2)*INDEX(s,0,6)) reads arrays happily and gives the same number. XLOOKUP and FILTER take arrays too.
Scenario: Decide which of the two your workbook is. If other formulas point at the stack, spill it once and let them use H2#; if it is one total, keep it in LET and write the total with SUMPRODUCT.
11When Your Build Has None of This
Excel 2019 and earlier have no VSTACK, and Power Query's Append is older than all of it: Data ▸ Get Data ▸ Combine Queries ▸ Append, one query per tab, one output table.
Append matches on column names. Oakmere's swapped columns would have landed under the right headings, and a renamed column would have produced a new column of nulls instead of a silent mix.
It also reads each tab to its real last row, so there is no blank padding and no lost tail. What it does not do is recalculate: somebody has to press Refresh, and a stale refresh hides exactly the kind of gap this article is about.
Which to reach for. A stack is live, reads in one formula and needs Microsoft 365. Power Query is a refresh step, matches on headings and runs on any build since 2016.
If the tabs are really separate files in a folder, neither answer is the right one: point Power Query at the folder instead, and the thirteenth file joins without anybody editing a formula.
12Ten Traps
- A stack aligns by position. Two tabs with the same headings in a different order stack into nonsense with no error.
- A 3-D reference is tab order, not alphabet. Dragging a tab changes what the formula covers.
- A tab added at the end is outside the span. It joins nothing and says nothing.
- Move or Copy lands inside the span. The copy is counted in full.
- Blank cells arrive as 0.
<>""does not remove them;<>0does. - A blank date is 00/01/1900. Sort by it and the padding floats to the top.
- The row bound is fixed. The tab that outgrows it loses its tail quietly.
- Different widths pad with #N/A. Loud, and better than the alternative.
SUMIFSrefuses an array. Spill the stack, or total it withSUMPRODUCT.- The stack is live. Delete a branch tab and the whole report changes while you watch.
13Mini Exercises
- Break it on purpose. Copy a branch tab with Move or Copy, leave it where Excel put it, and watch the group total rise by exactly that branch.
- Count the padding. Write
=ROWS(H2#)and=SUMPRODUCT(--(INDEX(H2#,0,1)<>0))over the example stack, and work out the average basket both ways. - Catch the swap. Point
=SUMPRODUCT(--(Alderwell!$A$1:$F$1=Oakmere!A1:F1))at each tab in turn and find the one that returns 4. - Fit the bookends. Add
StartandEndsheets, repoint the stack atStart:End!A2:F200, and drag Ferncliffe inside. Confirm the total rises by £7,480.20. - Reconcile the lot. Build the column from section 1 and account for all £30,785.25, not just the £12,565.25 the group total admits to.
What to Take Away
Nothing on this workbook was broken. Nine branch tabs balanced, one formula stacked them, SUMIFS added the stack up, and every number in the report was the honest output of the formula above it.
What nobody had written down is that a stack is an assumption: that every tab has the same columns in the same order, that the tabs inside the span are the tabs you mean, and that the rows you read reach the bottom of the longest one.
Those three assumptions are each one cell to test. =SUMPRODUCT(--(Alderwell!$A$1:$F$1=Oakmere!A1:F1)) tests the first, =ROWS(H2#)-ROWS(UNIQUE(H2#)) the second, and =COUNTA(Thurlby!A2:A10000) against the stacked count the third.
Three cells, against £12,565.25 that nobody could explain and £30,785.25 that was never in the right place to begin with.