NUMERIC
/DECIMAL
Както каза Йоахим Исаксон
, искате да използвате NUMERIC
/DECIMAL
тип, като тип с произволна точност.
Две важни точки относно NUMERIC
/DECIMAL
:
- Прочетете документ внимателно, за да научите, че трябва да посочите мащаба, за да избегнете мащаба по подразбиране от 0, което означава цели числа, при които десетичната дроб се отрязва. Въпреки че това е едно от местата, където Postgres се отклонява от стандартния SQL (давайки ви всякакъв мащаб до лимита за внедряване). Така че липсата на уточняване на мащаба е лош избор.
- SQL типовете
NUMERIC
&DECIMAL
са близки, но не идентични според стандарта SQL. В SQL:92 , зададената от вас точност заNUMERIC
се зачита, докато заDECIMAL
на сървъра на базата данни е позволено да добави допълнителна точност извън това, което сте посочили. Тук отново Postgres се отклонява малко от стандарта, както сNUMERIC
&DECIMAL
документирано като еквивалент.
Условия:
- Точността е общият брой цифри в едно число.
- Мащабът е броят на цифрите вдясно от десетичната запетая (десетичната дроб).
- ( Прецизност - Мащаб ) =Брой цифри вляво от десетичната запетая (цяла част).
Бъдете ясни по отношение на спецификациите на вашия проект за прецизност и мащаб:
- Голям
Прецизността трябва да е достатъчно голяма, за да се справи с по-големи числа, които може да са необходими в бъдеще. Което означава… Може би вашето приложение днес работи със суми от хиляди щатски долари, но в бъдеще трябва да извършва сборни отчети, които в крайна сметка достигат до милиони. - Малък
За някои счетоводни цели може да се наложи да съхранявате част от най-малката валутна сума. Което означава… Повече от 3 или 4 знака след десетичната запетая вместо 2, необходими за едно пени в USD .
Избягвайте MONEY
тип
Postgres предлага MONEY
тип също. Това може да звучи правилно, но вероятно не е най-доброто за повечето цели. Един недостатък е този с MONEY
мащабът се задава от конфигурационна настройка за цялата база данни въз основа на локал
. Така че тази настройка може да варира опасно лесно, когато превключвате сървъри или правите други промени. Освен това не можете да контролирате тази настройка за конкретни колони, докато можете да зададете мащаба на всяка колона на NUMERIC
Тип. И накрая, MONEY
не е стандартен SQL, както е показано в този списък със стандартни SQL данни типове
. Postgres включва MONEY
за удобство на хората, пренасящи данни от други системи за бази данни.
Преместване на десетичната точка
Друга алтернатива, използвана от някои, е преместването на десетичната запетая и просто съхраняването в големи цели числа.
Например, ако съхранявате USD долара до стотинка, умножете всяко дадено дробно число по 100, преобразувайте в целочислен тип и продължете. Например $123,45 се превръща в цяло число 12 345.
Предимството на този подход е по-бързото време за изпълнение. Операции като sum
са много бързи, когато се изпълняват върху цели числа. Друго предимство на целите числа е по-малкото използване на паметта.
Намирам този подход за досаден, объркващ и рискован. Досадно, защото компютрите трябва да работят за нас, а не срещу нас. Рисковано, защото някои програмист или потребител може да пропусне да умножи/дели, за да преобразува обратно в дробно число, давайки неправилни резултати. Ако работите в система без добра поддръжка за точни дробни числа, този подход може да бъде приемливо решение.
Не виждам никакво предимство в преместването на десетичната точка, когато имаме DECIMAL
/NUMERIC
в SQL и BigDecimal
в Java.
Закръгляване и NaN
При програмирането на вашето приложение, както и при всички изчисления, направени от страна на сървъра на Postgres, бъдете много внимателни и имайте предвид закръгляването и отрязването в десетичната дроб. И тествайте за непреднамерени NaN изскача.
И в двете страни, приложението и Postgres, винаги избягвайте плаваща запетая типове данни за работа с пари. Плаващата запетая е предназначена за бързина на изпълнение , но на цената на точността . Изчисленията могат да доведат до привидно луди допълнителни цифри в десетичната дроб. Не е подходящ за финансови/парични или други цели, където точността има значение.
BigDecimal
Да, в Java искате BigDecimal
като произволен тип точност. BigDecimal
е по-бавен и използва повече памет, но ще съхранява точно вашите парични суми. SQL NUMERIC
/DECIMAL
трябва да съответства на BigDecimal
както се обсъжда тук
и на StackOverflow
.
BigDecimal
е едно от най-добрите неща в Java. Не знам за друга платформа с подобен клас, особено такава, която е толкова добре внедрена и усъвършенствана с големи подобрения и поправки, направени през годините.
Използване на BigDecimal
определено е по-бавно от използването на типовете с плаваща запетая на Java
, float
&double
. Но в приложенията от реалния свят се съмнявам, че вашите парични изчисления ще бъдат някакво тясно място. И освен това, какво искате вие или вашите клиенти:най-бързият парични изчисления или точни парични изчисления? 😉
Винаги съм мислил за BigDecimal
като най-голямата спяща функция в Java, най-важното предимство за използването на платформата Java пред толкова много други платформи, на които им липсва такава усъвършенствана поддръжка за дробни числа.
Подобен въпрос:Най-добрият тип данни за валута