2013-03-31 2 views
74

Похоже Money типа не рекомендуется, как описано herePostgreSQL: Какой тип данных следует использовать для валюты?

Мое приложение должно хранить валюту, тип данных я буду использовать? Числовые, деньги или FLOAT?

+4

Если вы прочитали всю цепочку, Numeric - это путь. – razpeitia

ответ

58

Numeric с принудительной точностью 2 единицы. Никогда не используйте float или float как тип данных для представления валюты, потому что, если вы это сделаете, люди будут недовольны, если итоговая цифра финансового отчета неверна + или - несколько долларов.

Тип денег как можно дальше указывается по историческим причинам.

+1

Вот почему вы избегаете плавающей запятой. Даже Numeric будет иметь ошибки округления, если вы разделите все, что не делит на десять, независимо от того, какую точность вы используете. (Точность 2 - это плохая идея, так или иначе ... проверьте документы.) – Doradus

39

Ваш выбор:

  1. integer: хранить сумму в центах. Это то, что используют транзакции EFTPOS.
  2. decimal(12,2): хранить сумму с точностью до двух знаков после запятой. Это то, что использует большинство основных книг.
  3. float: ужасная идея - неадекватная точность. Это то, что используют наивные разработчики.

Вариант 2 является наиболее распространенным и простым в использовании. Сделайте точность (12 в моем примере, что означает 12 цифр), как большие, так и маленькие, что лучше всего подходит для вас.

Обратите внимание, что если вы агрегируете несколько транзакций, которые были результатом вычисления (например, с использованием обменного курса), в одно значение, имеющее бизнес-значение, точность должна быть выше, чтобы обеспечить точное значение макроса; подумайте о том, чтобы использовать что-то вроде decimal(18, 8), чтобы сумма была точной, а отдельные значения могут быть округлены до центровой точности для отображения.

+2

Если вы работаете с любым видом обратного налога или иностранной валютой, вам нужно как минимум 4 десятичных знака, или вы потеряете данные. Поэтому 'numeric (15,4)' или 'numeric (15,6)' - хорошая идея. –

+1

Существует 4-й вариант - использование String и использование эквивалентного десятичного типа без потерь в языке хоста. – ioquatix

72

Ваш источник никоим образом не является официальным. Это датируется 2011 годом, и я даже не признаю авторов. Если тип денег был «обескуражен», PostgreSQL скажет так в руководстве - which it doesn't.

Для более официальный источник, читайте this thread in pgsql-general (from just this week!) с заявлениями основных разработчиков, включая Д'Арси JM Cain (оригинальный автор типа денег) и Том Лейн:

В принципе, money имеет свой (ограниченное) использует. Преимущество над numeric составляет производительность.

decimal - всего лишь псевдоним для numeric в Postgres.

Связанный ответ (и комментарии!) О улучшениях в последних версии:

Лично мне нравится хранить валюту в качестве integer представляющих центов. Это более эффективно, чем любой другой из указанных вариантов.

+3

Существует несколько дискуссий по спискам рассылки, которые создают впечатление, что тип денег по крайней мере не рекомендуется, например: здесь: http://postgresql.nabble.com/Money-type-todos-td1964190.html#a1964192 plus чтобы быть справедливым: руководство для версии 8.2 ** ** ** назвало его устаревшим: http://www.postgresql.org/docs/8.2/static/datatype-money.html –

+1

@a_horse_with_no_name: Ваша ссылка для темы из 2007, а также когда 8.2 была текущей версией, а тип 'money' был, по сути, устарел. Проблемы были исправлены, и этот тип был добавлен в более поздние версии. Лично мне нравится хранить валюту как «целое», представляющее Cents. –

+0

Эрвин, вы можете подумать только с точки зрения базы данных. Однако, если вы комбинируете Postgresql + Java, это НЕ совсем хорошо (по моему опыту). Читая ваш комментарий, я использовал MONEY для большинства своих полей валюты, и теперь я получаю это исключение Java: «** SQLException произошло: org.postgresql.util.PSQLException: Плохое значение для типа double: 2,500.00 **». У меня есть googled и не нашел хорошего решения, поэтому я вхожу в скучную задачу поменять все на NUMERIC или DECIMAL сейчас! –

8

Я держу все свои денежные поля, как:

numeric(15,6)

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

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

+0

У этого есть риск неправильных результатов из-за отсутствия усечения. Если ненулевые значения непреднамеренно просачиваются в оставшиеся десятичные разряды, например, поле цены, содержащее 0,3333333 доллара, тогда у вас может быть ситуация, когда система показывает результат того, что кто-то покупает 3 предмета по 0,33 доллара США на общую сумму до 1,00 долларов США вместо 0,99 доллара США. – Peteris

+0

Perteris, так что вы предлагаете вместо этого? Независимо от того, насколько точность, которую вы бросаете на это округление, может быть проблемой. Я просто не нашел лучшего способа, даже если этот не идеален. –

+0

Исправлена ​​и усекалась там, где это уместно. Как только вы достигнете «сохраняемой» денежной стоимости, например. цена, предлагаемая клиенту, должна соответствовать соответствующим показателям, которые в большинстве случаев будут в целом центов в стандартной розничной среде. Если у вас разные потребности в бизнесе (например,цена на объемные товары на единицу) может быть другая установка точности, но вы должны рассматривать * презентацию вместе с памятью * - если вы показываете номер денег с x десятичными знаками (или наоборот, например, целыми тысячами), тогда вы также должны хранить его с * этой * точностью, не менее, но не более. – Peteris