Przechowywanie pieniędzy w kolumnie dziesiętnej - jaka precyzja i skala?

Używam kolumny dziesiętnej do przechowywania wartości pieniędzy w bazie danych, a dzisiaj zastanawiałem się, jakiej precyzji i skali użyć.

Ponieważ podobno kolumny znaków o stałej szerokości są bardziej wydajne, myślałem, że to samo może być prawdą dla kolumn dziesiętnych. Naprawdę?

A jakiej precyzji i skali powinienem użyć? Myślałem o precyzji 24/8. Czy to przesada, za mało czy ok?


To jest to, co postanowiłem zrobić:

  • przechowywać współczynniki konwersji (gdy dotyczy) w samej tabeli transakcji, jako float
  • Zapisz walutę w tabeli kont
  • Kwota transakcji będzie DECIMAL(19,4)
  • wszystkie obliczenia przy użyciu przelicznika będą obsługiwane przez moją aplikację, więc mam kontrolę nad kwestiami zaokrąglania

Nie sądzę, że float dla współczynnika konwersji jest problemem, ponieważ jest to głównie w celach informacyjnych, i i tak będę rzucać go do dziesiętnego.

Dziękuję wszystkim za cenny wkład.

Author: Nick Chammas, 2008-10-22

10 answers

Jeśli szukasz uniwersalnego rozmiaru, sugeruję, że {[0] } jest popularnym wyborem(szybkie Google to znosi). Wydaje mi się, że wywodzi się to ze starego typu danych waluty VBA/Access/Jet, będącego pierwszym typem dziesiętnym o stałym punkcie w języku; Decimal pojawił się tylko w stylu 'version 1.0' (tzn. nie w pełni zaimplementowanym) w VB6/VBA6/Jet 4.0.

Regułą dla przechowywania wartości dziesiętnych stałych punktów jest przechowywanie co najmniej jednego miejsca dziesiętnego więcej niż w rzeczywistości wymaga aby umożliwić zaokrąglenie. Jednym z powodów odwzorowania starego typu Currency z przodu na typ DECIMAL(19, 4) z tyłu było to, że Currency z natury jest zaokrąglane, podczas gdy DECIMAL(p, s) zaokrąglane przez obcinanie.

Dodatkowe miejsce po przecinku w pamięci dla DECIMAL pozwala zaimplementować niestandardowy algorytm zaokrąglania, zamiast przyjmować domyślne wartości dostawcy (a zaokrąglanie bankierów jest alarmujące, mówiąc co najmniej, dla projektanta oczekującego, że wszystkie wartości zakończą się .5 do rundy od zero).

Tak, brzmi jak przesada. Większość walut notowanych jest z dokładnością do czterech lub pięciu miejsc po przecinku. Znam sytuacje, w których wymagana jest skala dziesiętna wynosząca 8 (lub więcej) , ale jest to miejsce, w którym 'normalna' kwota pieniężna (powiedzmy cztery miejsca po przecinku) została proporcjonalnie zmniejszona, co oznacza, że dokładność dziesiętna powinna zostać odpowiednio zmniejszona (rozważ również Typ zmiennoprzecinkowy w takich okolicznościach). I nikt nie ma tyle pieniędzy w dzisiejszych czasach, aby wymagać dokładności dziesiętnej 24 :)

Jednak, zamiast podejścia uniwersalnego, niektóre badania mogą być w porządku. Zapytaj swojego projektanta lub specjalistę ds. domen o zasady rachunkowości, które mogą mieć zastosowanie: GAAP, UE itp. Niejasno przypominam sobie niektóre transfery WEWNĄTRZPAŃSTWOWE UE z wyraźnymi zasadami zaokrąglania do pięciu miejsc po przecinku, dlatego używam DECIMAL(p, 6) do przechowywania. Księgowi generalnie wydają się faworyzować cztery miejsca po przecinku.


PS unikaj typu danych SQL Server MONEY, ponieważ ma poważne problemy z dokładnością podczas zaokrąglania, między innymi względy takie jak przenośność itp. Zobacz Blog Aarona Bertranda.


Microsoft i projektanci języka wybrali zaokrąglenie, ponieważ projektanci sprzętu wybrali to [cytat?]. Jest on zapisany w standardach Institute of Electrical and Electronics Engineers (IEEE), na przykład. A projektanci sprzętu wybrali go, ponieważ matematycy wolą go. Zobacz Wikipedia ; parafrazując: wydanie prawdopodobieństwa i teorii błędów z 1906 roku nazywa to "regułą komputera" ("komputery", co oznacza ludzi, którzy wykonują obliczenia).

 145
Author: onedaywhen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-09 09:39:56

Niedawno wdrożyliśmy system, który musi obsługiwać wartości w wielu walutach i konwertować je między sobą, i wymyśliliśmy kilka rzeczy w trudny sposób.

NIGDY NIE UŻYWAJ LICZB ZMIENNOPRZECINKOWYCH DLA PIENIĘDZY

Arytmetyka zmiennoprzecinkowa wprowadza nieścisłości, których nie można zauważyć, dopóki czegoś nie spieprzą. Wszystkie wartości powinny być przechowywane jako liczby całkowite lub typy o stałej dziesiętnej, a jeśli zdecydujesz się użyć typu O STAŁEJ dziesiętnej, upewnij się, że rozumiesz dokładnie to, co ten typ robi pod maską (tzn. czy wewnętrznie używa typu integer lub zmiennoprzecinkowego).

Kiedy trzeba wykonać obliczenia lub konwersje:

  1. Konwertuj wartości na zmiennoprzecinkowe
  2. Oblicz nową wartość
  3. zaokrąglić liczbę i przekształcić ją z powrotem na liczbę całkowitą

Podczas konwersji liczby zmiennoprzecinkowej z powrotem na liczbę całkowitą w kroku 3, nie rzucaj jej po prostu - użyj funkcji matematycznej, aby zaokrąglić ją jako pierwszą. Zazwyczaj będzie to round, chociaż w szczególnych przypadkach może to być floor lub ceil. Poznaj różnicę i wybierz ostrożnie.

Zapisz Typ liczby wraz z wartością

Może to nie być tak ważne dla Ciebie, jeśli obsługujesz tylko jedną walutę, ale było ważne dla nas w obsłudze wielu walut. Użyliśmy 3-znakowego kodu dla waluty, takiej jak USD, GBP, JPY, EUR itp.

W zależności od sytuacji pomocne może być również przechowywanie:

  • Czy liczba jest przed lub po podatku (i jaka była stawka podatku)
  • Czy liczba jest wynikiem konwersji (i z czego została przekonwertowana)

Poznaj granice dokładności liczb, z którymi masz do czynienia

Dla wartości rzeczywistych, chcesz być tak precyzyjny, jak najmniejsza jednostka waluty. Oznacza to, że nie masz wartości mniejszych niż cent, grosz, Jen, fen itp. Nie przechowuj wartości z większą dokładnością bez powodu.

Wewnętrznie, ty może zdecydować się na obsługę mniejszych wartości, w którym to przypadku jest to inny rodzaj wartości waluty. Upewnij się, że Twój kod wie, który jest Który i nie powoduje ich pomieszania. Unikaj używania wartości zmiennoprzecinkowych nawet tutaj.


Dodając wszystkie te zasady razem, zdecydowaliśmy się na następujące zasady. W kodzie uruchomionym waluty są przechowywane za pomocą liczby całkowitej dla najmniejszej jednostki.

class Currency {
   String code;       //  eg "USD"
   int value;         //  eg 2500
   boolean converted;
}

class Price {
   Currency grossValue;
   Currency netValue;
   Tax taxRate;
}

W bazie danych wartości są przechowywane jako ciąg znaków w następujący sposób format:

USD:2500

, który przechowuje wartość $25.00. Udało nam się to tylko dlatego, że kod, który dotyczy walut, nie musi znajdować się w samej warstwie bazy danych, więc wszystkie wartości mogą być najpierw konwertowane do pamięci. Inne sytuacje bez wątpienia przydadzą się innym rozwiązaniom.


I na wypadek, gdybym nie wyraził się jasno wcześniej, nie używaj float!

 86
Author: Marcus Downing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 12:47:39

Podczas obsługi pieniędzy w MySQL, użyj DECIMAL(13,2), jeśli znasz dokładność wartości pieniędzy lub użyj DOUBLE, jeśli chcesz tylko szybki dobry-wystarczająco przybliżona wartość. Więc jeśli Twoja aplikacja musi obsługiwać wartości pieniędzy do biliona dolarów( lub euro lub Funtów), to powinno działać: {]}

DECIMAL(13, 2)

Lub, jeśli musisz przestrzegać GAAP, Użyj:

DECIMAL(13, 4)
 3
Author: pollux1er,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-20 14:15:28

4 miejsca po przecinku dałoby ci dokładność przechowywania najmniejszych jednostek waluty świata. Możesz to zrobić dalej, jeśli potrzebujesz mikropłatności (nanopłat?!).

Ja też wolę DECIMAL od specyficznych dla DBMS typów pieniędzy, bezpieczniej trzymać taką logikę w aplikacji IMO. Innym podejściem w tych samych liniach jest po prostu użycie liczby całkowitej [long] z formatowaniem do ¤jednostki.podjednostka dla czytelności człowieka (¤=symbol waluty) wykonana na poziomie aplikacji.

 2
Author: bobince,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 00:09:13

Typ danych pieniędzy na serwerze SQL ma cztery cyfry po przecinku.

From SQL Server 2000 Books Online:

Dane monetarne przedstawiają dodatnie lub ujemne kwoty pieniędzy. W Microsoft® SQL Server™ 2000 dane pieniężne są przechowywane przy użyciu typów danych money I smallmoney. Dane monetarne mogą być przechowywane z dokładnością do czterech miejsc po przecinku. Użyj typu danych money do przechowywania wartości w zakresie od -922,337,203,685,477.5808 do +922,337,203,685,477. 5807 (wymaga 8 bajtów do przechowywania wartości). Typ danych smallmoney służy do przechowywania wartości z zakresu od -214,748.3648 do 214,748.3647 (do przechowywania wartości wymagane są 4 bajty). Jeśli wymagana jest większa liczba miejsc po przecinku, należy zamiast tego użyć typu danych decimal.

 1
Author: Austin Salonen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 04:10:49

Czasami trzeba będzie przejść do mniej niż centa i są waluty międzynarodowe, które używają bardzo dużych demoniacji. Na przykład możesz obciążyć swoich klientów 0,088 centów za transakcję. W mojej bazie danych Oracle kolumny są zdefiniowane jako liczba (20,4)

 1
Author: WW.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 06:11:10

Jeśli masz zamiar wykonywać jakiekolwiek operacje arytmetyczne w DB (mnożenie stawek rozliczeniowych itp.), prawdopodobnie będziesz potrzebował o wiele większej precyzji, niż ludzie tutaj sugerują, z tych samych powodów, z których nigdy nie chciałbyś używać niczego mniej niż podwójnej precyzji zmiennoprzecinkowej w kodzie aplikacji.

 1
Author: Hank Gay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 11:34:07

Jeśli używasz IBM Informix Dynamic Server, masz typ MONEY, który jest pomniejszym wariantem dziesiętnym lub liczbowym. Jest to zawsze Typ stałopunktowy (podczas gdy DECIMAL może być typem zmiennoprzecinkowym). Możesz określić skalę od 1 do 32 i dokładność od 0 do 32(domyślnie Skala 16 i dokładność 2). Tak więc, w zależności od tego, co musisz przechowywać, możesz użyć dziesiętnego(16,2) - wciąż wystarczająco dużego, aby utrzymać deficyt federalny USA, do najbliższego centa-lub możesz użyj mniejszego zakresu lub więcej miejsc po przecinku.

 0
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 06:05:43

Myślę, że w dużej części wymagania Twoje lub Twojego klienta powinny dyktować, jakiej precyzji i skali użyć. Na przykład, w przypadku strony e-commerce, nad którą pracuję, która zajmuje się pieniędzmi tylko w GBP, musiałem zachować je do dziesiętnego (6, 2).

 0
Author: ayaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 06:16:16

Późna odpowiedź tutaj, ale użyłem

DECIMAL(13,2)
Co moim zdaniem powinno pozwolić na 99,999,999,999.99.
 0
Author: Mike Upjohn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-24 12:54:16