PostgreSQL: Який тип даних слід використовувати для валюти?


128

Схоже, що Moneyтип не рекомендується, як описано тут

У моїй програмі потрібно зберігати валюту, який тип даних я буду використовувати? Числові, гроші чи ПЛАТИ?


7
Якщо ви прочитали цілу нитку, числовий шлях - це шлях.
razpeitia

Для всіх, хто працює з декількома валютами та піклується про збереження кодів валют на додаток до сум, ви можете побачити моделювання валют у базі даних (SO) та ISO 4217 (Wikipedia). Коротка відповідь - вам знадобляться два стовпчики.
Fabien Snauwaert

Відповіді:


90

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

Наскільки я можу сказати, тип грошей залишається лише з історичних причин.


9
Ось чому ви не уникаєте плаваючої точки. Навіть Numeric матиме помилки округлення, якщо розділити їх на все, що не ділиться на потужність десять, незалежно від того, яку точність ви використовуєте. (Точність 2 - це все одно погана ідея ... перевірити документи.)
Дорадус

6
Якщо ви хочете підтримувати довільні валюти, ніколи не складайте шкалу, рівну 2 (в постгрес-терміні, точність - це число всіх цифр, наприклад, у 121.121 вона дорівнює 6). Є валюти, такі як Бахрейнський динар, де 1000 підрозділів дорівнює одній одиниці, а є валюти, які взагалі не мають підрозділів.
Микола Архипов

@NikolayArhipov гарний момент, тому макс насправдіscale - precision
Конрад

1
numeric(3,2)зможе зберігати макс.9.99 3-2 = 1
Конрад

5
Не роби цього! Якщо ви не плануєте помножити на 100, перш ніж завантажувати будь-які значення на інші мови, а потім робити математику з цілими числами - у вас виявиться помилковий результат. Зберігайте речі в центах (найменша валютна одиниця, з якою ви маєте справу) та заощадите собі клопоту. Дуже погана відповідь у багатьох випадках.
Avamander

111

Ваше джерело жодним чином не є офіційним. Він датується 2011 роком, і я навіть не визнаю авторів. Якби форма грошей була офіційно "відсторонена", PostgreSQL сказав би це в посібнику - чого вона не робить .

Для отримання більш офіційного джерела прочитайте цю тему в pgsql-генералі (з цього тижня!) , Із заявами основних розробників, включаючи D'Arcy JM Cain (оригінальний автор грошового типу) та Тома Лейн:

Відповідна відповідь (та коментарі!) Про покращення в останніх випусках:

В основному, moneyмає свої (дуже обмежені) використання. Postgres Wiki пропонує у чому уникнути, за винятком тих вузько визначених випадків. Перевага по порівнянні numericє продуктивність .

decimalце лише псевдонім для numericPostgres і широко використовується для грошових даних, оскільки він є "довільною точністю". Посібник :

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

Особисто я люблю зберігати валюту як integerпредставницьку центів, якщо дробові центи ніколи не виникають (в основному там, де гроші мають сенс). Це більш ефективно, ніж будь-який інший із згаданих варіантів.


4
У списках розсилки є декілька дискусій, які створюють враження, що тип грошей принаймні не рекомендується, наприклад: тут: postgresql.nabble.com/Money-type-todos-td1964190.html#a1964192 плюс бути справедливим: керівництво для версії 8.2 було назвати його застарілим: postgresql.org/docs/8.2/static/datatype-money.html
a_horse_with_no_name

11
@a_horse_with_no_name: Ваше посилання є на потік з 2007 року, який також коли 8.2 був поточною версією, а moneyтип, фактично, застарів. Проблеми виправлені, а тип було додано ще в пізніших версіях. Особисто я люблю зберігати валюту як integerпредставницьку центів.
Ервін Брандстеттер

1
Ервіне, ти можеш правильно думати лише з точки зору бази даних. Однак, якщо ви комбінуєте Postgresql + Java, це зовсім НЕ добре (з мого досвіду). Читаючи ваш коментар, я використовував MONEY для більшості моїх валютних полів, і тепер я отримую цей виняток на Java: " Виникла SQLException: org.postgresql.util.PSQLException: Неправильне значення для типу подвійне: 2500,00 ". Я переглянув Google і не знайшов хорошого рішення, тому я переймаюся нудною задачею змінити їх на НУМЕРИЧНІ або ДЕКІМАЛЬНІ !!!
М.Д.

1
@MD: Вибачте, що це чую, але я, очевидно, не говорив за Java (що не можу). Повідомлення про помилку непарне. "подвійний"? І подільник тисяч може бути також проблемою. Ви можете почати нове запитання з цього приводу.
Ервін Брандстеттер

2
@PirateApp: Так, мій особистий фаворит. Можливо, ви пропустили останнє речення моєї відповіді, сказавши саме це.
Ервін Брандстетер

68

Ваш вибір:

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

Варіант 2 - найпоширеніший і найпростіший в роботі. Зробіть точність (12 у моєму прикладі, тобто 12 цифр у всьому) такою великою чи маленькою, як найкраще підходить для вас.

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


10
Якщо ви працюєте з будь-яким видом зворотного обчислення податку чи валюти, вам потрібно принаймні 4 десяткових знаки, інакше ви втратите дані. Так numeric(15,4)чи numeric(15,6)це гарна ідея.
Петрус Терон

3
Існує 4-й варіант - це використовувати String і використовувати еквівалентний десятковий тип без втрат у мові хоста.
ioquatix

2
що з масштабним цілим числом, безумовно, що зберігати 10000.045 не зашкодило б, якщо воно зберігалося як 10000045 з коефіцієнтом масштабування 1000x?
PirateApp

26

Я зберігаю всі мої грошові поля як:

numeric(15,6)

Має бути надмірним число знаків після коми, але якщо є навіть найменший шанс, вам доведеться мати справу з кількома валютами, вам знадобиться стільки точності для конвертації. Незалежно від того, що я представляю користувачеві, я завжди зберігаю долар США. Таким чином я можу легко конвертувати в будь-яку іншу валюту, враховуючи коефіцієнт конверсії за відповідний день.

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


6
Це загрожує помилковими результатами через відсутність усікання. Якщо ненульові значення ненавмисно просочуються до решти десяткових знаків, наприклад, у ціновому полі, що містить 0,333333 доларів, то у вас може виникнути ситуація, коли система показує результат того, що хтось купує 3 позиції по 0,33 долара кожен, загальною вартістю до 1,00 доларів замість $ 0,99.
Петерсіс

1
Perteris, так що ви пропонуєте замість цього? Незалежно від того, яка точність ви кинете на цьому округленні, може бути проблемою. Я просто не знайшов кращого способу, навіть якщо цей не ідеальний.
Майкл Коллетт

3
Фіксована точка і обрізання, де це доречно. Як тільки ви досягнете "зберігається" вартості грошей, наприклад, ціни, запропонованої клієнтові, вона повинна відповідати показникам, які в більшості випадків становлять цілі копійки в стандартному роздрібному середовищі. Якщо у вас є різні потреби в бізнесі (наприклад, велика кількість товарів на одиницю), може бути різний параметр точності, але ви повинні ставитись до презентації разом із сховищем - якщо ви показуєте номер грошових знаків x десятковою комою (або навпаки, наприклад, цілими тисячами), тоді ви також повинні зберігати його з такою точністю, не менше, але і не більше.
Петріс

Для багатьох сайтів, що стосуються роздрібної торгівлі, які можуть працювати. Основний проект, з яким я працюю, може мати одну сторону, яка потребує перегляду однакової вартості в одній валюті, з клієнтом в іншій валюті, для постачальника ще в третьому.
Майкл Коллетт

19

Використовуйте 64-бітове ціле число, збережене як bigint

Я рекомендую використовувати мікродолари (або подібну основну валюту). Мікро означає 1 мільйон, тому 1 мікродолар = 0,000001 дол.

  • Проста у використанні та сумісна з усіма мовами.
  • Досить точності, щоб обробити частки цента.
  • Працює за дуже невеликі ціни за одиницю (наприклад, покази оголошень або плата за API).
  • Менший розмір даних для зберігання, ніж рядки чи числові дані.
  • Легко підтримувати точність за допомогою обчислень і застосовувати округлення на кінцевому виході.

1
Це найправильніша відповідь, і будь-яке розумне програмне забезпечення стосується найменшої валютної одиниці. Виконання всієї математики на цілі числа означає, що вам не доведеться мати справу з будь-яким специфічним для мови плаваючим керуванням.
Avamander

1
Буде використовувати і це. Дякую

Чому це над numeric(15,6)запропоновано в іншій відповіді?
Юліуш Гонера

@JuliuszGonera З причин, зазначених у відповіді. Цілі лічильники є меншими і підтримуються скрізь, і уникають усіх проблем з математичним скороченням. Це в основному використання числових, але зміщення десяткових знаків, щоб у вас було ціле число, яке набагато сумісніше.
Мані Гандам

1
Ага, правда, я пропустив частину про зберігання. Дякую! Щодо "Простий у використанні та сумісний з усіма мовами", на жаль, JavaScript підтримує цілі числа до 9007199254740991, що в 1000 разів менше максимального значення bigint. Існує developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…, але він надається з обмеженою підтримкою (на даний момент) та застереженнями (наприклад, ви не можете легко помножити його на поплавок при здійсненні конвертації валюти) . Зважаючи на те, що максимум, який ви можете зберігати в цілому JS, використовуючи мікродолари, становить 9 мільярдів доларів, що, мабуть, все ще добре для більшості випадків.
Юліуш Гонера

3

Використовуйте BigIntдля зберігання валюти як додатне ціле число, що представляє грошову вартість в найменшій валютній одиниці (наприклад, 100 центів для зберігання 1,00 долара або 100 для зберігання 100 (японська ієна, валюта з нульовою десятковою). Це те, що робить Stripe - один найважливіші компанії з фінансових послуг для глобальної електронної комерції.

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