Two bank statement CSVs can look close enough to compare in Excel, but that is usually why the mismatch gets worse. One file stores debits as negative amounts. The other splits them into separate debit and credit columns. One uses the posting date. The other uses the value date. By the time you start building lookups, the files are already disagreeing about what a single transaction is.

The safest way to compare two bank statement CSV files without formulas is to treat both exports as raw transaction files, map each column by role, match rows by the strongest shared key, and review only the exceptions that remain.

Read the mismatch before you touch the files

Most false mismatches show up before any comparison starts. The two exports are already storing the same transaction differently.

Use this table as the first pass.

What you see on screenHow File A stores itHow File B stores itResult when matched
05/01/2026 and -125.40Date is text 05/01/2026; amount is one signed valueDate is a real date serial; amount is 125.40 in a Debit columnMatch fails on both date type and sign convention
1,250.00 in both filesAmount is text with a comma and hidden leading apostropheAmount is a real numberValues look identical but a spreadsheet lookup treats them differently
TRANSFER TO SAVINGS appears twice for 250.00Two separate rows share the same date and amountOne row includes a bank reference, the other does notDate-and-amount matching creates duplicate candidates
AMAZON vs AMAZON MKTPLACE PMTSDescription is truncated by one bank exportDescription keeps the longer merchant textDescription-only matching fails even though the payment is the same
31/03/2026 in one file and 01/04/2026 in the otherFile uses transaction or swipe dateFile uses posting or settlement dateSame movement is reported as a timing difference, not a missing row
Opening Balance exists only in one fileFile includes statement control rows in the CSVFile contains transactions onlyThat line should not be matched as a transaction at all

If two cells still look suspiciously identical after this first pass, use =TYPE(A2) as a spot check. 1 means Excel stored a number. 2 means it stored text. If Excel keeps returning #N/A on values that appear to match, why VLOOKUP returns #N/A on mismatched CSV formats is usually the underlying failure.

Pick the column that deserves to be the match key

The whole comparison gets easier once you stop asking every column to do the same job. Some fields are safe for matching. Some are only supporting evidence.

Candidate keyUse it whenWhat it does wellWhere it breaks
Bank reference or transaction IDBoth exports preserve a bank-generated referenceBest primary key for true one-to-one matchingMany CSV exports omit it or rename it
Posted date + signed amountBoth files use the same date basis and same sign ruleWorks for clean same-account comparisonsBreaks on one-day shifts and repeated same-amount rows
Amount + reference fragmentOne file truncates descriptions but preserves part of the referenceUseful when bank reference is partial but consistentWeak for card traffic and recurring merchant payments
Description + amountReference is missing and merchant text is stableGood as a fallback review keyBreaks on abbreviations, truncation, and duplicate same-day purchases
Running balanceYou need supporting evidence after a likely matchHelps confirm row order around a disputed transactionNever use it as the primary key because one inserted row shifts everything after it

Amount alone is weak. Two card purchases for 19.99 are common. Description alone is weak because one bank might export UBER BV while another writes UBER *TRIP. Running balance is useful for context, but it is not stable enough to drive the whole match.

A clean comparison usually uses a hierarchy:

  1. Match by bank reference when both files have it.
  2. Fall back to signed amount plus date when reference is missing.
  3. Use description only to review leftovers, not to drive the first pass.

Map the columns by role, not by header name

Two bank CSVs often describe the same field with different headers. The fix is not to rename every column manually. The fix is to decide what job each column plays in the comparison.

Here is a typical mapping:

Comparison roleFile A headerFile B headerRule
Transaction datePosted DateValue DateTreat as comparable only after you know whether the banks use the same date basis
AmountAmountDebit and CreditConvert to one signed amount rule, or compare debits and credits in separate passes
ReferenceReferenceBank RefUse as primary key if both sides preserve it
DescriptionDescriptionNarrationUse to support review, not as the first key
BalanceBalanceRunning BalanceKeep for diagnostics only
Transaction typeTypeDetailsUseful for excluding fees, reversals, or control rows

If one CSV uses separate debit and credit columns, do not force that file into a bad single-column comparison by eyeballing signs. Either use a comparison tool that lets you map debit as negative and credit as positive, or run two passes: debits against debits, then credits against credits. That is still cleaner than burying the sign logic inside lookup columns that no one wants to audit later.

Build the comparison in passes, not in one giant match

Pass 1: lock the raw files

Keep the original exports untouched. Do not overwrite them, sort them in place, or delete rows before you know what those rows mean. If one file later turns out to contain opening balance lines or pending card transactions, you need the untouched version to prove it.

Pass 2: exclude rows that are not real transaction matches

Before matching anything, identify rows such as:

  • Opening balance
  • Closing balance
  • Statement summary rows
  • Blank separator rows
  • Export footer text

Those lines belong in period control, not transaction matching. If one file includes them and the other does not, you are manufacturing discrepancies before the work starts.

Pass 3: run the strongest key first

Start with the highest-confidence rule available.

First-pass ruleBest use caseExpected outcome
Reference + amountSame account exported from two systemsMost rows match cleanly with low review effort
Signed amount + posted dateReference missing but date basis is alignedGood coverage on simple bank exports
Debit-only or credit-only passOne file splits amounts across two columnsPrevents false sign mismatches

Do not bring description into this first pass unless you have to. Merchant text creates noise early and rarely solves it.

Pass 4: review the leftovers by exception type

After the first pass, every remaining row should go into one of a few clear buckets:

Exception bucketWhat it usually meansWhat to do next
Missing from File ATransaction exists only in File BCheck date filter, statement period, or whether File A dropped that transaction type
Missing from File BTransaction exists only in File ACheck export completeness, pending items, or duplicates
Same amount, different datePosting delay or value-date differenceMark as timing unless another field disagrees
Same date, same amount, multiple candidatesDuplicate-value problemBring in reference, balance context, or nearby sequence
Same row, different signDebit/credit convention mismatchRework amount rule before investigating further
Same text, different stored value typeText-vs-number issueNormalize the field type, then rerun the comparison

Pass 5: use description only to settle ambiguous leftovers

Once the exceptions are down to a small set, description becomes helpful. At that stage you are no longer scanning thousands of lines. You are deciding whether ATM WDL 004281 is the same cash withdrawal as ATM CASH 4281.

Description is a review tool. It is not the backbone of the comparison.

Handle the bank-statement edge cases that generic CSV guides skip

Generic CSV comparison pages usually stop at "upload two files and compare." Bank statements need more than that.

Posted date versus value date

Banks do not always agree on which date belongs in the export. A card payment made late in the evening can show one day earlier in one file and one day later in another. That is not a missing transaction. It is a timing difference. Treat it as its own bucket.

Split debit and credit columns

One file may store withdrawals in Debit and deposits in Credit, while the other uses one signed Amount column. If you do not normalize that rule first, every outgoing payment becomes a false mismatch.

Repeated same-amount transactions

Coffee shops, subscription charges, cash withdrawals, and transfer sweeps produce duplicates constantly. If you match only on date and amount, the wrong row can appear to reconcile while the real mismatch stays hidden.

Balance lines and summary rows

Some exports include opening balance, closing balance, or daily total lines inside the CSV. Those rows are useful for control, but they are not individual transactions and should never compete for a match key.

Filtered date ranges

One CSV may cover statement dates while the other covers download dates. That is how you end up comparing March 1 to March 31 on one side against March 2 to April 1 on the other. The files are not wrong. The extraction window is different.

Truncated descriptions

One bank export may cut merchant text after 18 characters. Another may keep the full string. Treat description as supporting evidence only, especially on card traffic.

A file comparison process can classify these cases cleanly. A large spreadsheet full of VLOOKUPs usually hides them inside helper columns and manual filters.

The comparison is finished when the output can answer a real finance question

Your final output should be able to show:

Output sectionWhat it should tell you
Matched transactionsWhich rows are confirmed across both files
Missing rowsWhich transactions exist on only one side
Timing differencesWhich rows agree in amount but sit on different dates
Duplicate candidatesWhich same-value rows need a stronger key
Control totalsWhether unmatched amounts are explained or still open

If the comparison feeds month-end work, the next question is usually not about the CSV anymore. It is about why the bank side and the books still disagree after the statement match is done. That is where what to do when books do not match your bank at month end becomes the next diagnostic step.

When the monthly rerun is the real waste

The manual pain is rarely the first comparison. It is the fifth one. Then the tenth. Then the version where one bank changes the headers, another adds a balance column, and the statement deadline does not move.

At that point, the work is no longer analytical. It is repeated file matching, repeated exception review, and repeated report cleanup.