NUMERIC
/DECIMAL
Zoals Joachim Isaksson zei
, wilt u NUMERIC
gebruiken /DECIMAL
type, als een willekeurig precisietype.
Twee belangrijke punten over NUMERIC
/DECIMAL
:
- Lees de doc zorgvuldig om te leren dat u de schaal moet specificeren om de standaardschaal van 0 te vermijden, wat betekent dat gehele waarden waarbij de decimale breuk wordt weggelaten. Hoewel dit een van de plaatsen is waar Postgres afwijkt van standaard SQL (waardoor u enige schaalvergroting tot aan de implementatielimiet krijgt). Dus het niet specificeren van de schaal is een slechte keuze.
- De SQL-typen
NUMERIC
&DECIMAL
zijn dichtbij maar niet identiek volgens de SQL-standaard. In SQL:92 , uw opgegeven precisie voorNUMERIC
wordt gerespecteerd, terwijl voorDECIMAL
de databaseserver mag extra precisie toevoegen die verder gaat dan wat u hebt opgegeven. Ook hier wijkt Postgres een beetje af van de standaard, met zowelNUMERIC
&DECIMAL
gedocumenteerd als equivalent.
Voorwaarden:
- Precisie is het totale aantal cijfers in een getal.
- Schaal is het aantal cijfers rechts van de komma (de decimale breuk).
- ( Precisie - Schaal ) =Aantal cijfers links van de komma (geheel getal).
Wees duidelijk over de specificaties van uw project voor precisie en schaal:
- Groot
De precisie moet groot genoeg zijn om grotere aantallen aan te kunnen die in de toekomst nodig kunnen zijn. Betekenis... Misschien werkt uw app vandaag de dag in bedragen van duizenden USD, maar moet hij in de toekomst overzichtsrapporten uitvoeren die in de miljoenen lopen. - Klein
Voor sommige boekhoudkundige doeleinden moet u mogelijk een fractie van het kleinste valutabedrag opslaan. Betekenis... Meer dan 3 of 4 decimalen in plaats van de 2 die nodig zijn voor een cent in USD .
Vermijd MONEY
typ
Postgres biedt een MONEY
typ ook. Dat klinkt misschien goed, maar waarschijnlijk niet het beste voor de meeste doeleinden. Een nadeel is dat met MONEY
de schaal wordt ingesteld door een database-brede configuratie-instelling gebaseerd op locale
. Dus die instelling kan gevaarlijk gemakkelijk variëren wanneer u van server wisselt of andere wijzigingen aanbrengt. Bovendien kunt u die instelling niet voor specifieke kolommen bepalen, terwijl u de schaal op elke kolom van NUMERIC
kunt instellen type. Ten slotte, MONEY
is geen standaard SQL zoals weergegeven in deze lijst met standaard SQL-gegevens soorten
. Postgres bevat MONEY
voor het gemak van mensen die gegevens uit andere databasesystemen overzetten.
Verplaats het decimale punt
Een ander alternatief dat door sommigen wordt gebruikt, is het verplaatsen van de komma en gewoon opslaan in een gegevenstype met een groot geheel getal.
Als u bijvoorbeeld USD opslaat dollars tot de cent, vermenigvuldig een gegeven fractioneel getal met 100, giet het in een geheel getal en ga verder. $ 123,45 wordt bijvoorbeeld het gehele getal 12.345.
Het voordeel van deze aanpak is snellere uitvoeringstijden. Bewerkingen zoals sum
zijn erg snel wanneer ze worden uitgevoerd op gehele getallen. Een ander voordeel van gehele getallen is minder geheugengebruik.
Ik vind deze aanpak vervelend, verwarrend en riskant. Vervelend omdat computers voor zouden moeten werken ons, niet tegen ons. Risicovol omdat een programmeur of gebruiker kan nalaten te vermenigvuldigen/delen om terug te zetten naar een fractioneel getal, wat onjuiste resultaten oplevert. Als u in een systeem werkt zonder goede ondersteuning voor nauwkeurige fractionele getallen, kan deze aanpak een acceptabele oplossing zijn.
Ik zie geen enkel voordeel in het verplaatsen van de komma als we DECIMAL
. hebben /NUMERIC
in SQL en BigDecimal
in Java.
Afronding &NaN
In de programmering van uw app, evenals in alle berekeningen die op de Postgres-server zijn gemaakt, wees zeer voorzichtig en let op afronding en truncatie in de decimale breuk. En test op onbedoelde NaN's opduiken.
Aan beide kanten, app en Postgres, vermijd altijd drijvend punt gegevenstypen voor geldwerk. Drijvende punt is ontworpen voor prestatiesnelheid , maar ten koste van nauwkeurigheid . Berekeningen kunnen resulteren in schijnbaar gekke extra cijfers in de decimale breuk. Niet goed voor financiële/geldelijke of andere doeleinden waar nauwkeurigheid belangrijk is.
BigDecimal
Ja, in Java wil je BigDecimal
als uw willekeurige precisietype. BigDecimal
is langzamer en gebruikt meer geheugen, maar zal uw geldbedragen nauwkeurig opslaan. SQL NUMERIC
/DECIMAL
zou moeten verwijzen naar BigDecimal
zoals besproken hier
en op StackOverflow
.
BigDecimal
is een van de beste dingen van Java. Ik ken geen ander platform met een vergelijkbare klasse, vooral een platform dat zo goed geïmplementeerd en verfijnd is met belangrijke verbeteringen en fixes die in de loop der jaren zijn aangebracht.
BigDecimal
gebruiken is zeker langzamer dan het gebruik van Java's floating-point-typen
, float
&double
. Maar in real-world apps betwijfel ik of je geldberekeningen een knelpunt zullen zijn. En bovendien, wat willen u of uw klanten:de snelste geldberekeningen, of nauwkeurige geld berekenen?
Ik heb altijd gedacht aan BigDecimal
als de grootste sleeper-functie in Java, het belangrijkste voordeel van het gebruik van het Java-platform ten opzichte van zoveel andere platforms die zulke geavanceerde ondersteuning voor fractionele getallen missen.
Vergelijkbare vraag:Beste gegevenstype voor valuta