NUMERIC
/DECIMAL
Jak powiedział Joachim Isaksson
, chcesz użyć NUMERIC
/DECIMAL
typ, jako typ dowolnej precyzji.
Dwie ważne kwestie dotyczące NUMERIC
/DECIMAL
:
- Przeczytaj dokument ostrożnie, aby dowiedzieć się, że należy określić skalę, aby uniknąć domyślnej skali 0, co oznacza wartości całkowite, w których ułamek dziesiętny jest obcinany. Chociaż jest to jedno z miejsc, w których Postgres odchodzi od standardowego SQL (daje dowolną skalę do limitu implementacji). Więc brak określenia skali jest złym wyborem.
- Typy SQL
NUMERIC
&DECIMAL
są bliskie, ale nie identyczne zgodnie ze standardem SQL. W SQL:92 , określona precyzja dlaNUMERIC
jest przestrzegany, podczas gdy dlaDECIMAL
serwer bazy danych może zwiększyć precyzję poza określoną przez użytkownika. Tutaj ponownie Postgres nieco odbiega od standardu, z obiema wartościamiNUMERIC
&DECIMAL
udokumentowane jako odpowiednik.
Warunki:
- Precyzja to całkowita liczba cyfr w liczbie.
- Skala to liczba cyfr na prawo od przecinka dziesiętnego (ułamek dziesiętny).
- ( Dokładność - Skala ) =Liczba cyfr na lewo od przecinka dziesiętnego (część całkowita).
Jasno określ specyfikacje projektu dotyczące precyzji i skali:
- Duży
Precyzja musi być wystarczająco duża, aby obsłużyć większe liczby, które mogą być potrzebne w przyszłości. To znaczy… Być może Twoja aplikacja działa dziś na kwoty tysięcy USD, ale w przyszłości będzie musiała wykonywać raporty zbiorcze, które kończą się milionami. - Mały
W niektórych celach księgowych może być konieczne przechowywanie ułamka najmniejszej kwoty w walucie. To znaczy… Więcej niż 3 lub 4 miejsca po przecinku zamiast 2 potrzebne do grosza w USD .
Unikaj MONEY
wpisz
Postgres oferuje MONEY
wpisz również. To może brzmieć dobrze, ale prawdopodobnie nie jest najlepsze dla większości celów. Jednym minusem jest to, że z MONEY
skala jest ustawiana przez ustawienie konfiguracji obejmujące całą bazę danych na podstawie lokalizacji
. To ustawienie może się niebezpiecznie łatwo zmieniać, gdy zmieniasz serwery lub wprowadzasz inne zmiany. Co więcej, nie możesz kontrolować tego ustawienia dla określonych kolumn, podczas gdy możesz ustawić skalę dla każdej kolumny NUMERIC
rodzaj. Na koniec MONEY
nie jest standardowym SQL, jak pokazano na tej liście standardowych danych SQL typy
. Postgres zawiera MONEY
dla wygody osób przenoszących dane z innych systemów baz danych.
Przesuń punkt dziesiętny
Inną alternatywą stosowaną przez niektórych jest przesuwanie przecinka dziesiętnego i po prostu przechowywanie danych w dużych liczbach całkowitych.
Na przykład, jeśli przechowujesz USD dolarów do grosza, pomnożyć dowolną liczbę ułamkową przez 100, odrzucić na typ liczby całkowitej i kontynuować. Na przykład 123,45 USD staje się liczbą całkowitą 12 345.
Zaletą tego podejścia jest szybszy czas realizacji. Operacje takie jak sum
są bardzo szybkie, gdy są wykonywane na liczbach całkowitych. Kolejną korzyścią dla liczb całkowitych jest mniejsze zużycie pamięci.
Uważam, że takie podejście jest irytujące, mylące i ryzykowne. Irytujące, ponieważ komputery powinny działać dla nam, nie przeciwko nam. Ryzykowne, ponieważ niektórzy programiści lub użytkownicy mogą zaniedbywać mnożenie/dzielenie w celu konwersji z powrotem do liczby ułamkowej, dając nieprawidłowe wyniki. Jeśli pracujesz w systemie bez dobrej obsługi dokładnych liczb ułamkowych, to podejście może być akceptowalnym obejściem.
Nie widzę żadnej korzyści z przesuwania kropki dziesiętnej, gdy mamy DECIMAL
/NUMERIC
w SQL i BigDecimal
w Javie.
Zaokrąglanie i NaN
W programowaniu Twojej aplikacji, a także we wszelkich obliczeniach wykonywanych po stronie serwera Postgres, bądź bardzo ostrożny i pamiętaj o zaokrąglaniu i obcinaniu w ułamku dziesiętnym. I przetestuj pod kątem nieumyślnych NaN wyskakuje.
Po obu stronach, w aplikacji i Postgresie, zawsze unikaj zmiennego punktu typy danych do pracy z pieniędzmi. Liczba zmiennoprzecinkowa została zaprojektowana z myślą o szybkości wydajności , ale kosztem dokładności . Obliczenia mogą skutkować pozornie szalonymi dodatkowymi cyframi w ułamku dziesiętnym. Nie nadaje się do celów finansowych/finansowych lub innych, w których liczy się dokładność.
BigDecimal
Tak, w Javie chcesz BigDecimal
jako arbitralny typ precyzji. BigDecimal
jest wolniejszy i zużywa więcej pamięci, ale dokładnie przechowuje kwoty pieniędzy. SQL NUMERIC
/DECIMAL
powinien mapować na BigDecimal
jak omówiono tutaj
i na StackOverflow
.
BigDecimal
to jedna z najlepszych rzeczy w Javie. Nie znam żadnej innej platformy o podobnej klasie, zwłaszcza tak dobrze zaimplementowanej i dopracowanej z dużymi ulepszeniami i poprawkami wprowadzonymi przez lata.
Korzystanie z BigDecimal
jest zdecydowanie wolniejszy niż używanie typów zmiennoprzecinkowych Java
, float
&double
. Ale w rzeczywistych aplikacjach wątpię, aby twoje obliczenia finansowe były wąskim gardłem. A poza tym, czego Ty lub Twoi klienci chcecie:najszybszy obliczenia pieniężne lub dokładne obliczenia pieniędzy?
Zawsze myślałem o BigDecimal
jako największa funkcja usypiająca w Javie, najważniejsza zaleta korzystania z platformy Java w porównaniu z wieloma innymi platformami, które nie mają tak zaawansowanego wsparcia dla liczb ułamkowych.
Podobne pytanie:Najlepszy typ danych dla waluty