Найкращий тип даних для зберігання значень грошей у 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те саме.
juergen d

21
Я особисто використовую numeric(19,4)фінансові записи, що дає вам кращу руку, щоб легко грати та приймати нові запити.
YahyaE

10
Я погоджуюся з YahyaE, більше десяткових знаків краще. Є кілька валют, які зазвичай використовують 3 десяткових знаки, такі як Бахрейні, Йорданська або Кувейтські динари, тому вам потрібно принаймні 3. Чотири-п’ять краще.
Едвін Хугербец

1
@EdwinHoogerbeets Не будучи бухгалтером ... але керуючи невеликим бізнесом у Великобританії ... Пам’ятаю, я давно десь читав, що цифри валюти повинні зберігатися до 4 десяткових знаків навіть за £, $ і т. Д., Щоб певні розрахунки могли фактично використовувати останні два десяткових знаки для певних неясних облікових контекстів. Для підтвердження / спростування потрібен бухгалтер.
мійський гризун

88

Ви можете використовувати DECIMALабо NUMERICобидва однакові

Типи DECIMAL і NUMERIC зберігають точні числові значення даних. Ці типи застосовуються, коли важливо зберегти точну точність, наприклад, з грошовими даними. У MySQL NUMERIC реалізований як DECIMAL, тому наступні зауваження щодо DECIMAL застосовуються однаково до NUMERIC. : MySQL

тобто DECIMAL(10,2)

Приклад налаштувань

Добре читати


3
Можливо, заплутаний, але ваш знімок екрана не відповідає вашому тексту відповіді (точність, масштаб).
Патрік Хофман

Я використовую десятковий (10,2) для моєї вартості грошей, однак, коли я вкладаю щось на зразок 867 000,00, це зберігається як 867. Що я роблю неправильно?
codeinprogress

32

Я вважаю за краще використовувати BIGINTта зберігати значення, помноживши на 100 , щоб вони стали цілими.

Наприклад, щоб представити значення валюти 93.49, значення має зберігатися як 9349, відображаючи значення, яке ми можемо розділити на 100 і відобразити. Це займе менше місця для зберігання.

Застереження:
Здебільшого ми не виконуємо currency * currencyмноження, якщо в цьому випадку ділимо результат на 100 і зберігаємо, щоб він повернувся до належної точності.


Я пам’ятаю, як мені розповідав подібний предмет професором на моєму університетському курсі «Комп’ютерні системи». Мене вчили найточніший спосіб - це зберігання в копійках (або центах), помноживши на 100 і зберегти у вигляді Цілого числа та розділити на 100, щоб відобразити його користувачеві. Я думаю, що це має переваги з точки зору точності та продуктивності системи баз даних.
LondonAppDev

11
У чому перевага DECIMAL? Ви створюєте необхідність перекладати копійки в долари, і горе, якщо ви забудете це в якийсь момент.

1
Простір - єдина перевага, але так, нам потрібно бути обережнішими, коли ми використовуємо цю функцію.
Дінеш PR

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.


5
Якщо ви збираєтеся взяти Bitcoin, вам знадобиться 8 знаків після коми, хоча більшість гаманців переходять на mBTC, який становить 3 en.wikipedia.org/wiki/Bitcoin
Крістіан

Не думаю, що ця відповідь правдива. 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 ) .


5
Це не має нічого спільного з "уподобаннями програміста" або з тим, що ви "особисто використовуєте". Це продиктовано проблемною областю, яка вимагає десяткового радіусу. Це не питання, в якому програміст отримує свої особисті переваги.
Маркіз Лорн

3

Спробуйте використовувати

Decimal(19,4)

зазвичай це працює і з усіма іншими БД


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 у біткойнах

Якщо ви спробуєте зробити те саме decimal, вам потрібно decimal(30, 15)14 байт.

Коваджі

Звичайно, використання doubleне обійдеться без застережень.

Однак це не втрата точності, як це схильно зазначають деякі. Незважаючи на те, що doubleсама по собі може не бути внутрішньо точною до базової системи 10 , ми можемо зробити її точною, округливши значення, яке ми витягуємо з бази даних, до її значних десяткових знаків. Якщо потрібно, це є. (наприклад, якщо це буде виведено, і необхідне представлення бази 10).

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

  1. Проведення порівнянь на ньому.
  2. Запис назад у базу даних.

Інший вид застереження - на відміну від того, decimal(m, d)де база даних не дозволить програмам вставляти число з більшою кількістю mцифр, таких перевірок не існує double. Програма може вставити введене користувачем значення 20 цифр, і в кінцевому підсумку воно буде мовчазно записано як неточну кількість.


Перший раз я побачив таку відповідь, цікаву. Питання: Якщо я запишу в базу даних флоат, як 1.41, і мені чомусь потрібно помножити її на якусь величезну кількість у mysql, наприклад, 1.000.000.000.000. Чи точно результат округлення буде: 1.410.000.000.000?
roelleor

@roelleor Щоб результат був рівно 1,410,000,000,000 (кома як роздільник тисяч), вхід вважається рівним ( 1.410000000000дванадцять значущих десяткових знаків), але помноживши це на 1 000 000 000 000 (що на 13 значущих цифр ліворуч від десяткової коми) означає, що ми працюємо з принаймні комбіновані 25 цифр значущості. Це набагато перевершує 15 доступних для подвійного, так що дизайн-розумний я думаю, що це було б дуже зламаним.
антак

2

На той момент це питання ніхто не замислювався про ціну біткойна. Що стосується BTC, його, ймовірно, недостатньо для використання DECIMAL(15,2). Якщо біткойн підніметься до 100 000 доларів або більше, нам знадобиться хоча б DECIMAL(18,9)підтримка криптовалют у наших додатках.

DECIMAL(18,9)займає 12 байт місця в MySQL ( 4 байти на 9 цифр ).


> Біткойн можна розділити на 8 знаків після коми. Тому 0,00000001 BTC - це найменша сума, яку можна обробити за транзакцію. Я думаю, ти маєш на увазі 8 замість 9?
небезпека89

1
Я знаю, але 9 займає таке ж місце на диску, як 8. З MySQL docs: "Значення стовпців DECIMAL зберігаються у двійковому форматі, який пакує дев'ять десяткових цифр у 4 байти"
bizwiz

О, вибачте, зараз я тебе зрозумію. Дякую.
небезпека89

2

Зберігання грошей, BIGINTпомножених на 100 і більше, з тим, щоб використовувати менше місця для зберігання, не має сенсу у всіх "нормальних" ситуаціях.

  • Для того, щоб залишатись узгодженим з GAAP, достатньо зберігати валюти в DECIMAL(13,4)
  • У посібнику MySQL написано, що для зберігання потрібно 4 байти на 9 цифр DECIMAL.
  • DECIMAL(13,4) представляє 9 розрядів + 4 цифри дробу (десяткових знаків) => 4 + 2 байти = 6 байт
  • порівняти з 8 байтами, необхідними для зберігання BIGINT.

1

Якщо потрібна відповідність GAAP або вам потрібні 4 знаки після коми:

ДЕКІМАЛЬНИЙ (13, 4), який підтримує максимальне значення:

$ 999,999,999,9999

В іншому випадку, якщо достатньо 2 знаків після коми: DECIMAL (13,2)

src: https://rietta.com/blog/best-data-types-for-currencymoney-in/


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.