Хранение денег в десятичной колонке - какая точность и масштаб?

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

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

И какую точность и масштаб следует использовать? Я думал о точности 24/8. Это слишком много, недостаточно или нормально?


Это то, что я решил сделать:

  • Сохраняйте коэффициенты конверсии (если применимо) в самой таблице транзакций, как float
  • Сохранить валюту в таблице счетов
  • Сумма транзакции будет DECIMAL(19,4)
  • Все вычисления с использованием коэффициента конверсии будут обрабатываться моим приложением, поэтому я буду контролировать проблемы округления.

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

Спасибо всем за ценный вклад.

Ответ 1

Если вы ищете универсальный вариант, я бы предложил DECIMAL(19, 4) популярный выбор (быстрый Google подтверждает это). Я думаю, что это происходит из старого типа данных VBA/Access/Jet Currency, являющегося первым десятичным типом с фиксированной точкой на языке; Decimal только в стиле "версия 1.0" (т.е. не полностью реализован) в VB6/VBA6/Jet 4.0.

Эмпирическое правило для хранения десятичных значений с фиксированной точкой состоит в том, чтобы хранить как минимум еще одно десятичное место, чем вам требуется для округления. Одной из причин сопоставления старого типа Currency в лицевой части с типом DECIMAL(19, 4) на заднем конце было то, что Currency показывал округление банкиров по своей природе, тогда как DECIMAL(p, s) округлялось путем усечения.

Дополнительное десятичное место в хранилище для Decimal позволяет реализовать нестандартный алгоритм округления, а не принимать по умолчанию поставщика (и округление банкиров, по меньшей мере, вызывает тревогу у дизайнера, ожидающего, что все значения заканчиваются на .5 округлить от нуля).

Да, DECIMAL(24, 8) звучит как излишество для меня. Большинство валют котируются до четырех или пяти знаков после запятой. Я знаю ситуации, когда требуется десятичная шкала из 8 (или более), но это означает, что "нормальная" денежная сумма (скажем, четыре десятичных разряда) была пропорциональна, подразумевая, что десятичная точность должна быть соответственно уменьшена (также учитывайте тип с плавающей запятой при таких обстоятельствах). И никто не имеет сегодня столько денег, чтобы требовать десятичную точность 24:)

Однако, скорее, чем одноразовый подход, некоторые исследования могут быть в порядке. Спросите своего дизайнера или специалиста по домену о правилах бухгалтерского учета, которые могут быть применимы: GAAP, ЕС и т.д. Я смутно вспоминаю некоторые внутригосударственные трансферты ЕС с явными правилами округления до пяти знаков после запятой, поэтому используя DECIMAL(p, 6) для хранения. Обычно бухгалтеры предпочитают четыре десятичных знака.


PS Избегайте типа данных SQL Server MONEY, потому что у него есть серьезные проблемы с точностью при округлении, среди других соображений, таких как переносимость и т.д. См. блог Aaron Bertrand.


Microsoft и разработчики языка выбрали округление банкиров, потому что аппаратные дизайнеры выбрали его [цитата?]. Например, он закреплен в стандартах Института инженеров по электротехнике и электронике (IEEE). И разработчики аппаратного обеспечения выбрали его, потому что математики предпочитают его. См. Wikipedia; перефразируя: в 1906 году "Вероятность и теория ошибок" назвали это "компьютерным правилом" ( "компьютеры" означают людей, которые выполняют вычисления).

Ответ 2

Недавно мы реализовали систему, которая должна обрабатывать значения в разных валютах и ​​конвертировать между ними, и придумал несколько трудных вещей.

НИКОГДА НЕ ИСПОЛЬЗУЙТЕ FLOATING ТОЧКИ НОМЕРОВ ДЛЯ ДЕНЕГ

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

Когда вам нужно выполнить вычисления или преобразования:

  • Преобразование значений в плавающую точку
  • Рассчитать новое значение
  • Округлить число и преобразовать его в целое число

При преобразовании числа с плавающей запятой обратно в целое число на шаге 3 не просто бросайте его - сначала используйте математическую функцию для округления. Обычно это будет round, хотя в особых случаях это может быть floor или ceil. Знайте разницу и тщательно выбирайте.

Сохраните тип номера рядом со значением

Это может быть не так важно для вас, если вы обрабатываете только одну валюту, но для нас важно иметь дело с несколькими валютами. Мы использовали 3-символьный код для валюты, такой как USD, GBP, JPY, EUR и т.д.

В зависимости от ситуации также может быть полезно хранить:

  • Достаточно ли оно до или после уплаты налогов (и какая была ставка налога)
  • Является ли число результатом преобразования (и с которого он был преобразован)

Знайте границы точности чисел, с которыми имеете дело

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

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


Объединяя все эти правила вместе, мы приняли следующие правила. При запуске кода валюты сохраняются с использованием целого числа для наименьшей единицы.

class Currency {
   String code;       //  eg "USD"
   int value;         //  eg 2500
   boolean converted;
}

class Price {
   Currency grossValue;
   Currency netValue;
   Tax taxRate;
}

В базе данных значения сохраняются в виде строки в следующем формате:

USD:2500

Это хранит значение в 25,00 $. Мы смогли это сделать только потому, что код, который имеет дело с валютами, не обязательно должен находиться внутри самого уровня базы данных, поэтому все значения могут быть сначала преобразованы в память. Другие ситуации, несомненно, поддаются другим решениям.


И в случае, если раньше я не уточнил, не использовать float!

Ответ 3

4 десятичных разряда предоставят вам точность хранения наименьших валютных единиц мира. Вы можете снять его дальше, если вам нужна точность микроплатежа (наноопция!).

Я тоже предпочитаю DECIMAL для типов денег, специфичных для СУБД, вы более безопасны, сохраняя такую ​​логику в приложении IMO. Другой подход в этом же направлении состоит в том, чтобы использовать целое число [long] с форматированием в ¤unit.subunit для удобочитаемости человека (¤ = символ валюты), выполненного на уровне приложения.

Ответ 4

При работе с деньгами в MySQL используйте DECIMAL (13,2), если вы знаете точность своих денежных значений или используете DOUBLE, если хотите просто получить достаточно хорошее приблизительное значение. Поэтому, если ваше приложение должно обрабатывать денежные значения до триллиона долларов (или евро или фунтов), тогда это должно работать:

DECIMAL(13, 2)

Или, если вам нужно выполнить GAAP, используйте:

DECIMAL(13, 4)

Ответ 5

Тип данных денег на SQL Server имеет четыре цифры после десятичного числа.

Из электронной документации по SQL Server 2000:

Денежные данные представляют собой положительные или отрицательные суммы денег. В Microsoft® SQL Server ™ 2000 денежные данные хранятся с использованием типов данных money и smallmoney. Денежные данные могут храниться с точностью до четырех знаков после запятой. Используйте тип данных денег для хранения значений в диапазоне от -922,337,203,685,477.5808 до +922,337,203,685,477.5807 (для хранения значения требуется 8 байтов). Используйте тип данных smallmoney для хранения значений в диапазоне от -214,748.3648 до 214,748.3647 (для хранения значения требуется 4 байта). Если требуется большее число десятичных знаков, используйте десятичный тип данных.

Ответ 6

Иногда вам нужно идти менее чем на цент, и есть международные валюты, которые используют очень большие демонизации. Например, вы можете взимать с ваших клиентов 0.088 центов за транзакцию. В моей базе данных Oracle столбцы определены как NUMBER (20,4)

Ответ 7

Если вы собираетесь выполнять какие-либо арифметические операции в БД (умножая ставки выставления счетов и т.д.), вы, вероятно, захотите получить гораздо большую точность, чем люди, предлагающие по тем же причинам, что и вы 'd никогда не хотите использовать что-либо меньшее, чем значение с плавающей запятой двойной точности в коде приложения.

Ответ 8

Если вы используете IBM Informix Dynamic Server, у вас будет тип MONEY, который является второстепенным вариантом для типа DECIMAL или NUMERIC. Он всегда является типом с фиксированной точкой (тогда как DECIMAL может быть типом с плавающей точкой). Вы можете указать масштаб от 1 до 32 и точность от 0 до 32 (по умолчанию - шкала 16 и точность 2). Таким образом, в зависимости от того, что вам нужно хранить, вы можете использовать DECIMAL (16,2) - все еще достаточно большой, чтобы удерживать Федеральный дефицит США, до ближайшего цента, или вы можете использовать меньший диапазон или более десятичных знаков.

Ответ 9

Поздний ответ здесь, но я использовал

DECIMAL(13,2)

который я правильно думаю, должен позволить до 99,999,999,999.99.

Ответ 10

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