Лучший тип данных для хранения денежных значений в MySQL

279

Я хочу хранить много записей в базе данных MySQL. Все они содержат денежные значения. Но я не знаю, сколько цифр будет вставлено для каждого.
Какой тип данных я должен использовать для этой цели?
VARCHAR или INT (или другие числовые типы данных)?

Мухаммед Сабери
источник
13
deimal(10,2)это то, что я использую ... вы можете настроить значения в зависимости от ожидаемого размера
Manse
9
Связанный вопрос - Лучший тип данных для валюты ;).
shA.t

Ответы:

370

Поскольку деньги нуждаются в точном представлении, не используйте типы данных, которые являются приблизительными float. Вы можете использовать числовой тип данных с фиксированной запятой для этого как

decimal(15,2)
  • 15 это точность (общая длина значения, включая десятичные разряды)
  • 2 количество цифр после десятичной точки

Смотрите MySQL Числовые типы :

Эти типы используются, когда важно сохранить точную точность, например, с денежными данными.

Юрген д
источник
3
в чем может быть разница между десятичным и числовым типом данных для этого случая?
Эмилио Горт
60
В MySQL decimalи numericто же самое.
Юрген д
21
Я лично использую numeric(19,4)для финансовых отчетов, что дает вам лучшую руку, чтобы легко играть и принимать новые запросы.
YahyaE
10
Я согласен с YahyaE, чем больше десятичных знаков, тем лучше. Есть некоторые валюты, которые обычно используют 3 знака после запятой, такие как бахрейнский, иорданский или кувейтский динар, поэтому вам нужно как минимум 3. Четыре или пять лучше.
Эдвин Хугербитс
1
@EdwinHoogerbeets Не будучи бухгалтером ... но управляю небольшим бизнесом в Великобритании ... Я помню, как читал где-то давным-давно, что цифры валюты должны храниться до 4 десятичных знаков даже для £, $ и т. Д., Чтобы некоторые вычисления могли фактически использовать последние 2 десятичных знака для определенных скрытых контекстов учета. Wd нужен бухгалтер, чтобы подтвердить / опровергнуть.
Майк Грызун
88

Вы можете использовать DECIMALили NUMERICоба одинаковы

Типы DECIMAL и NUMERIC хранят точные числовые значения данных. Эти типы используются, когда важно сохранить точную точность, например, с денежными данными. В MySQL NUMERIC реализован как DECIMAL, поэтому следующие замечания о DECIMAL в равной степени применимы к NUMERIC. : MySQL

т.е. DECIMAL(10,2)

Пример настроек

Хорошо читать

NullPoiиteя
источник
3
Возможно, это сбивает с толку, но ваш скриншот не соответствует вашему тексту ответа (точность, масштаб).
Патрик Хофман
Я использую десятичную (10,2) для моей денежной стоимости, однако, когда я ставлю что-то вроде 867 000,00, оно сохраняется как 867. Что я делаю не так?
codeinprogress
32

Я предпочитаю использовать BIGINTи хранить значения путем умножения на 100 , чтобы оно стало целым числом.

Например, для представления значения в валюте значение 93.49должно быть сохранено как 9349при отображении значения, которое мы можем разделить на 100, и отобразить. Это займет меньше места для хранения.

Внимание: в
большинстве currency * currencyслучаев мы не выполняем умножение, в случае, если мы делаем это, то делим результат на 100 и сохраняем его, чтобы он вернулся с правильной точностью.

Динеш ПР
источник
Я помню, как профессор рассказывал мне подобное на курсе университета по компьютерным системам. Меня учили, что самый точный способ - хранить в копейках (или центах) умножением на 100 и сохранением в виде целого числа и делением на 100, чтобы отобразить его пользователю. Я предполагаю, что это имеет преимущества с точки зрения точности и производительности системы баз данных.
LondonAppDev
11
В чем преимущество DECIMAL? Вы создаете необходимость переводить копейки в доллары, и горе, если вы забудете об этом в какой-то момент.
1
Пространство является единственным преимуществом, но да, мы должны быть более осторожными, когда мы используем эту функцию.
Динеш пиар
4
В случае, если это не очевидно: будьте осторожны с использованием метода удаления масштаба, если вы храните деньги в дробных центах (например, $0.005или $0.12345), потому что они не будут уменьшаться до целого числа после умножения на 100. Если вы знаете точность значений, это ясно Лучший вариант - использовать DECIMAL. Но если вы не знаете точности (как в моих примерах), тогда ... будет FLOATуместно?
Куинн Комендант
1
Преимущество этого метода возникает при использовании языка, такого как JavaScript, который использует IEEE-754 для хранения чисел с плавающей запятой. Данная спецификация не гарантирует, что 0,1 + 0,2 === 0,3 соответствует действительности. Хранение валюты в виде целого числа дает уверенность в том, что ваше приложение не подвергнется такого рода ошибкам. Это может быть не лучшим решением, хотя. Я пришел на эту страницу, пока искал решения, и пока не закончил.
Гари Отт
27

Это зависит от ваших потребностей.

Использование DECIMAL(10,2)обычно достаточно , но если вам нужно немного более точные значения , которые вы можете установить DECIMAL(10,4).

Если вы работаете с большими значениями, замените 10на 19.

Светослав
источник
Я использую десятичную (10,2) для моей денежной стоимости, однако, когда я ставлю что-то вроде 867 000,00, оно сохраняется как 867. Что я делаю не так?
codeinprogress
2
@codeinprogress Неправильный региональный / десятичный разделитель?
Давид
15

Если ваше приложение должно обрабатывать денежные значения до триллиона, это должно работать: 13,2 Если вам нужно соблюдать GAAP (общепринятые принципы бухгалтерского учета), тогда используйте: 13,4

Обычно вы должны суммировать свои денежные значения в 13,4 до округления результата до 13,2.

david.ee
источник
5
Если вы собираетесь брать биткойны, вам понадобится 8 десятичных знаков, хотя большинство кошельков идут на mBTC, который равен 3 en.wikipedia.org/wiki/Bitcoin
Christian
Не думайте, что этот ответ верный. opendata.stackexchange.com/a/10348/13983 @ david.ee есть источник для этого?
Эван Кэрролл
@EvanCarroll позвольте мне ответить за david.ee. Я думаю, что эта статья может быть источником rietta.com/blog/2012/03/03/best-data-types-for-currencymoney-in
naXa
@naXa ссылка не цитирует ничего из какого-либо источника, подтверждающего заявление об использовании 13,4 для GAAP. Все, что вы сделали, это ссылку на статью, которая делает то же самое необоснованное утверждение.
iheanyi
6

На самом деле это зависит от предпочтений программиста. Я лично использую: numeric(15,4)чтобы соответствовать Общепринятым принципам бухгалтерского учета ( GAAP ) .

Chagbert
источник
5
Он не имеет ничего общего с «предпочтениями программиста» или тем, что вы «лично используете». Это продиктовано проблемной областью, для которой требуется десятичное число. Это не тот вопрос, в котором программист может использовать свои личные предпочтения.
Маркиз Лорн
3

Попробуйте использовать

Decimal(19,4)

это обычно работает с любой другой БД

Deepesh
источник
3

Мы используем double.

* Удушье *

Зачем?

Потому что он может представлять любое 15-значное число без каких-либо ограничений на то, где находится десятичная точка . Все за жалкие 8 байтов!

Так что это может представлять:

  • 0.123456789012345
  • 123456789012345.0

... и все что между

Это полезно, потому что мы имеем дело с глобальными валютами и doubleможем хранить различное количество десятичных разрядов, с которыми мы, вероятно, столкнемся.

Один doubleполе может представлять 999,999,999,999,999s в японских йенах, 9,999,999,999,999.99s в долларах США и даже 9,999,999.99999999s в Bitcoins

Если вы попытаетесь сделать то же самое с decimal, вам нужно, decimal(30, 15)что стоит 14 байтов.

Предостережения

Конечно, использование doubleне без предостережений.

Тем не менее, это не потеря точности, как указывают некоторые. Даже если doubleсам по себе он не может быть внутренне точным для системы base 10 , мы можем сделать его точным, округлив значение, которое мы извлекаем из базы данных, до ее значащих десятичных разрядов. При необходимости это так. (Например, если он будет выведен, и требуется представление базы 10).

Предостережения: всякий раз, когда мы выполняем с ним арифметику, нам нужно нормализовать результат (округляя его до значащих десятичных разрядов) перед:

  1. Выполнение сравнений на нем.
  2. Запись его обратно в базу данных.

Еще один вид предостережения: в отличие от того, decimal(m, d)где база данных будет препятствовать программам вставлять число, состоящее более чем из mцифр, таких проверок не существует double. Программа может вставить введенное пользователем значение из 20 цифр, и в итоге она будет записана в виде неточной суммы.

antak
источник
Впервые я увидел такой ответ, интересный. В: Если я записываю в базу данных число с плавающей точкой, например 1.41, и по какой-то причине мне нужно умножить его на какое-то огромное число в mysql, например 1.000.000.000.000. Будет ли округленный результат точно: 1.410.000.000.000?
roelleor
@roelleor Для результата, равного 1 410 1.410000000000000 000 000 (запятая как разделитель тысяч), предполагается, что входные данные (двенадцать значащих десятичных разрядов), но умножение на 1 000 000 000 000 (что на 13 значащих цифр слева от десятичной точки) означает, что мы работаем с минимум 25 комбинированных значащих цифр. Это намного превосходит 15 доступных для двойного, поэтому по дизайну я думаю, что это будет очень сломано.
Antak
2

В то время, когда этот вопрос задавали, никто не задумывался о цене биткойна. В случае BTC его, вероятно, недостаточно использовать DECIMAL(15,2). Если биткойн вырастет до 100 000 долларов или больше, нам потребуется хотя бы DECIMAL(18,9)поддержка криптовалют в наших приложениях.

DECIMAL(18,9)занимает 12 байтов пространства в MySQL ( 4 байта на 9 цифр ).

bizwiz
источник
> Биткойн можно разделить на 8 десятичных знаков. Поэтому 0,00000001 BTC - это наименьшая сумма, которая может быть обработана в транзакции. Я думаю, что вы имеете в виду 8 вместо 9?
danger89
1
Я знаю, но 9 занимает то же место на диске, что и 8. Из документации MySQL: «Значения для столбцов DECIMAL хранятся в двоичном формате, который упаковывает девять десятичных цифр в 4 байта»
bizwiz
Ой, прости, теперь я тебя понимаю. Спасибо.
danger89
2

Хранение денег, BIGINTумноженное на 100 или более с целью использовать меньше места для хранения, не имеет смысла во всех «нормальных» ситуациях.

  • Чтобы оставаться в соответствии с GAAP, достаточно хранить валюты в DECIMAL(13,4)
  • Руководство MySQL гласит, что для хранения требуется 4 байта на 9 цифр DECIMAL.
  • DECIMAL(13,4) представляет 9 цифр + 4 цифры дроби (десятичные разряды) => 4 + 2 байта = 6 байтов
  • сравните с 8 байтами, необходимыми для хранения BIGINT.
digitalstraw
источник
1

Если требуется соответствие GAAP или вам нужно 4 десятичных знака:

DECIMAL (13, 4), который поддерживает максимальное значение:

$ 999,999,999.9999

В противном случае, если достаточно 2 десятичных разряда: DECIMAL (13,2)

источник: https://rietta.com/blog/best-data-types-for-currencymoney-in/

Stnfordly
источник