# Compare one column across two tables, matched by key

Join two CSVs on a key column and report every row where a single chosen value column disagrees, as clean old → new pairs. Browser-local, no upload.

## Run it

- **CLI:** `gizza tool column-value-diff "id,name,price
1,Apple,10
2,Banana,20
3,Cherry,30" 'right=id,name,price
1,Apple,12
2,Banana,20
3,Cherry,35' 'key=id' 'value=price'`
- **Web:** https://gizza.ai/tools/column-value-diff/
- **Agents:** machine-readable descriptor (parameters JSON Schema) at https://gizza.ai/tools/column-value-diff/tool.json

## Inputs

- `left` — Original CSV (old table) _(field)_
- `right` — Updated CSV (new table) _(field)_
- `key` — Key column(s) to join on _(field)_
- `value` — Value column to compare _(field)_
- `delimiter` — Delimiter _(field)_
- `header` — First row is a header _(field)_
- `ignore_case` — Ignore case _(field)_
- `ignore_whitespace` — Ignore whitespace _(field)_
- `include_unmatched` — Include keys on only one side _(field)_
- `format` — Output format _(field)_

## Output

- Value changes (text)

## Query parameters

Open the tool pre-filled and auto-run via URL:

- `left` — Original CSV (old table)
- `right` — Updated CSV (new table)
- `key` — Key column(s) to join on
- `value` — Value column to compare
- `delimiter` — Delimiter
- `header` — First row is a header
- `ignore_case` — Ignore case
- `ignore_whitespace` — Ignore whitespace
- `include_unmatched` — Include keys on only one side
- `format` — Output format

Example: `https://gizza.ai/tools/column-value-diff/?left=id%2Cname%2Cprice%0A1%2CApple%2C10%0A2%2CBanana%2C20%0A3%2CCherry%2C30&right=id%2Cname%2Cprice%0A1%2CApple%2C12%0A2%2CBanana%2C20%0A3%2CCherry%2C35&key=id&value=price&delimiter=comma&header=true&ignore_case=true&ignore_whitespace=true&include_unmatched=true&format=table`

---

## What this tool does

**Column Value Diff** joins two tables on a **key column** and compares a single
**value column** between the matched rows — reporting every key whose value changed as a
clean `old → new` pair. Every other column is ignored, so two exports with different
surrounding columns still reconcile cleanly on the one metric you care about: a price, a
quantity, a status, a balance.

It's the focused answer to "did the value for this id change between yesterday's file and
today's?" — where a full cell-by-cell diff would drown you in unrelated column noise.

## Worked example

**Original CSV**

```
id,name,price
1,Apple,10
2,Banana,20
3,Cherry,30
```

**Updated CSV**

```
id,name,price
1,Apple,12
2,Banana,20
3,Cherry,35
```

With **key = `id`** and **value = `price`**, the table report is:

```
value column "price" · 3 keys matched · 2 changed · 1 unchanged
~ [1] "10" → "12"
~ [3] "30" → "35"
```

Row `2` (Banana) is unchanged, and the `name` column is never compared. Switch the output
to **CSV change-log** for a flat, pasteable result:

```
key,status,old,new
1,changed,10,12
3,changed,30,35
```

Turn on **Include keys on only one side** to also list keys that appear in just one file
(`left_only` / `right_only`) — useful for spotting added or dropped rows alongside the value
changes.

## How to use it

1. Paste the **original** (old) CSV and the **updated** (new) CSV.
2. Enter the **key column(s)** that identify a row — e.g. `id`, or `first,last` for a
   composite key. Reordered rows still match, because rows are joined by key, not by line.
3. Enter the **value column** to compare — the one metric, e.g. `price`.
4. Pick the delimiter, header, and matching options, then read the `old → new` report.

Everything runs locally in your browser — the CSVs are never uploaded.

## FAQ

<!-- FAQ MUST be <details>/<summary> accordions. Keep the blank line inside each. -->

<details>
<summary>How is this different from a full CSV diff?</summary>

A full cell diff compares **every** column and flags every changed cell, plus whole columns
that were added or removed. That's noisy when the two files have different surrounding
columns. This tool compares **one** value column, matched by key, so you get just the
`key → old/new` changes for the metric you care about — nothing else.

</details>

<details>
<summary>Can I match on more than one column?</summary>

Yes. Enter a **composite key** as a comma-separated list, e.g. `first,last` or
`store,sku`. Rows match only when every key column agrees. Duplicate keys are paired in
their original order.

</details>

<details>
<summary>What if a key exists in only one of the files?</summary>

By default those rows are ignored, so the report shows only value changes for keys present
in **both** tables. Turn on **Include keys on only one side** to also list them as
`left-only` (only in the original) and `right-only` (only in the updated) with their value.

</details>

<details>
<summary>My CSV has no header row — can I still use it?</summary>

Yes. Turn off **First row is a header** and reference the key and value columns by their
**1-based index** instead of a name — e.g. key `1`, value `3`. Columns are labelled
`col1`, `col2`, … internally.

</details>

<details>
<summary>Does it treat "10" and "10.0" (or different case) as equal?</summary>

Values are compared as **text**, so `10` and `10.0` are different, and `Yes` differs from
`yes` unless you enable **Ignore case**. Enable **Ignore whitespace** to fold runs of spaces
(so `in  stock` matches `in stock`). Both options affect matching only — the report always
shows the original text.

</details>

## Limits & edge cases

- Comparison is **textual** — there's no numeric tolerance or rounding; `10` ≠ `10.0`.
- The **key** and **value** columns are required and must exist in **both** tables (by name,
  or by 1-based index when header is off), otherwise you get a clear "not found" error.
- Duplicate keys pair in order (1st-with-1st, 2nd-with-2nd); leftover duplicates on one side
  surface as unmatched when **Include keys on only one side** is on.
- Supported delimiters: comma, tab, semicolon, pipe, or any single character. Quoted fields
  and embedded commas/newlines are parsed correctly.
- Processing is entirely in-browser (wasm); large files are handled in memory with no upload.

## Related tools

- [Adjacency Matrix Converter](https://gizza.ai/tools/adjacency-matrix-converter/): Convert a graph between edge list, adjacency matrix, and incidence matrix — directed or undirected, weighted or not. Free, private, runs in your browser.
- [Amazon Order Analyzer](https://gizza.ai/tools/amazon-order-analyzer/): Paste an Amazon order-history CSV export to summarize total spend by month, top items, and category breakdowns. Browser-only, private, with Markdown or JSON output.
- [Avro to JSON Converter](https://gizza.ai/tools/avro-to-json/): Decode Apache Avro Object Container Files (.avro / OCF) to JSON, NDJSON, or the embedded schema — no .avsc needed, free and private in your browser.
- [Reconcile bank statement and ledger CSVs](https://gizza.ai/tools/bank-statement-reconcile/): Match bank-statement CSV rows to ledger rows by date, signed amount, and fuzzy memo similarity, with unmatched and suggested matches.
- [Base64 ⇄ Base64url Converter](https://gizza.ai/tools/base64url-converter/): Convert standard Base64 to URL-safe Base64url and back in your browser — swaps +/ for -_, handles = padding, auto-detects direction. Free, private, no sign-up.
