---
title: DECIMAL(19,4) vs MONEY in SQL Server
date: 2025-08-15
tags: sql, sql-server, database, data-types
summary: Both store four decimal places, but MONEY can round in surprising ways. Which one to pick for financial data.
---

For financial or high-precision values in SQL Server you often have to choose between `DECIMAL(19,4)` and `MONEY`. Both store fixed-precision numbers with four decimal places, but they behave differently.

## The differences

| Feature | DECIMAL(19,4) | MONEY |
|---|---|---|
| Type | ANSI-standard exact numeric | SQL Server-specific fixed-point |
| Storage | 9 bytes | 8 bytes |
| Scale | You choose it (4 here) | Always 4 |
| Portability | High, works in other databases | Low |
| Rounding | Follows precision and scale | Implicit, can surprise in math-heavy queries |

## Rounding example

The classic trap is a ratio: a share, a percentage, a currency conversion. Divide one amount by another, then multiply:

```sql title="a ratio"
DECLARE @m1 MONEY = 100, @m2 MONEY = 339, @m3 MONEY = 10000;
DECLARE @d1 DECIMAL(19,4) = 100, @d2 DECIMAL(19,4) = 339, @d3 DECIMAL(19,4) = 10000;

SELECT
    MoneyResult = @m1 / @m2 * @m3,
    DecResult   = @d1 / @d2 * @d3;
```

| Type | Result | Result type |
|---|---:|---|
| MONEY | 2949.00 | money |
| DECIMAL | 2949.852507 | decimal(38,6) |

`MONEY` keeps only 4 decimals after every step, even inside one expression. `100 / 339` becomes `0.2949`, and multiplying by 10000 turns that small cut into a difference of 0.85. `DECIMAL` widens the scale on division, so the ratio keeps its digits until the end.

## Storing intermediate results

`DECIMAL` only helps while the digits are still there. Store `@d1 / @d2` in a `DECIMAL(19,4)` variable or column first, and it is rounded to `0.2950`, then multiplied. Now `DECIMAL` is off too, just in the other direction (2950).

- Keep intermediate results at a higher scale, for example `DECIMAL(19,8)`, or keep the calculation in one expression.
- Multiply before you divide where you can: `@d1 * @d3 / @d2`.
- Round once, at the end, on purpose: `CAST(... AS DECIMAL(19,4))`.

## Summing

Summing one million rows of `0.0100` gives the same total for both types:

| Type | Result |
|---|---:|
| DECIMAL | 10000.0000 |
| MONEY | 10000.00 |

Both totals are the same value. SSMS just hides the trailing zeros for `MONEY`, while `MONEY` still stores four decimals. Plain addition is not where `MONEY` goes wrong. The surprises come from division and multiplication.

## Performance

`SUM` over 10 million rows, single-threaded, data already in memory, 5 runs:

| Type | Min (ms) | Avg (ms) | Max (ms) |
|---|---:|---:|---:|
| DECIMAL(19,4) | 2970 | 3331 | 3496 |
| MONEY | 2934 | 2996 | 3106 |

`MONEY` is a little faster on average (about 10%), but the best runs are within 1% of each other and the `DECIMAL` runs vary more. The gap is small: about 30 ns per row on average. Performance is not a good reason to pick `MONEY`.

## When to use which

Use `DECIMAL(19,4)` when:

- you need control over precision and scale
- you have compliance or audit requirements
- you want portability to other databases

Use `MONEY` when:

- the currency math is simple
- you maintain legacy code where `MONEY` is the standard
- you understand and accept its rounding behavior

## TL;DR

- `MONEY` is easy but rounds to 4 decimals after every operation.
- `DECIMAL(19,4)` is explicit, portable and safer for financial work.
- `MONEY` was slightly faster in a 10-million-row `SUM`, but not enough to matter. Choose on precision needs.

> For new projects, default to `DECIMAL(19,4)` for financial data.
