Używam kolumny dziesiętnej do przechowywania wartości pieniężnych w bazie danych, a dziś zastanawiałem się, jakiej dokładności i skali użyć.
Ponieważ podobno kolumny typu char o stałej szerokości są bardziej wydajne, pomyślałem, że to samo może dotyczyć kolumn dziesiętnych. Czy to jest?
A jakiej precyzji i skali powinienem użyć? Myślałem o precyzji 24/8. Czy to przesada, za mało czy w porządku?
Oto, co postanowiłem zrobić:
- Przechowuj kursy wymiany (jeśli dotyczy) w samej tabeli transakcji jako zmiennoprzecinkowe
- Przechowuj walutę w tabeli kont
- Kwota transakcji będzie wynosić
DECIMAL(19,4)
- Wszystkie obliczenia z wykorzystaniem kursu konwersji będą obsługiwane przez moją aplikację, więc mam kontrolę nad kwestiami dotyczącymi zaokrąglania
Nie sądzę, aby liczba zmiennoprzecinkowa dla współczynnika konwersji była problemem, ponieważ jest ona głównie w celach informacyjnych, a mimo to będę rzucać ją na ułamek dziesiętny.
Dziękuję wszystkim za cenny wkład.
DECIMAL(19, 4)
jest popularnym wyborem sprawdź to również sprawdź tutaj Formaty walut świata, aby zdecydować, ile miejsc dziesiętnych użyć, nadzieja pomaga.Odpowiedzi:
Jeśli szukasz jednego rozmiaru dla wszystkich, sugeruję, że
DECIMAL(19, 4)
jest to popularny wybór (szybki Google to znosi). Myślę, że pochodzi to ze starego typu danych VBA / Access / Jet Currency, będąc pierwszym typem dziesiętnym ze stałym przecinkiem w języku;Decimal
pojawił się tylko w stylu „wersji 1.0” (tj. nie w pełni zaimplementowany) w VB6 / VBA6 / Jet 4.0.Praktyczną zasadą przechowywania wartości dziesiętnych ze stałymi punktami jest przechowywanie co najmniej jednego miejsca po przecinku więcej niż jest to wymagane, aby umożliwić zaokrąglanie. Jednym z powodów odwzorowania starego
Currency
typu z przodu naDECIMAL(19, 4)
typ z tyłu było to, żeCurrency
bankowcy wykazywali zaokrąglanie z natury, podczas gdyDECIMAL(p, s)
zaokrąglanie przez obcięcie.Dodatkowe miejsce po przecinku w pamięci
DECIMAL
umożliwia zaimplementowanie niestandardowego algorytmu zaokrąglania zamiast przyjmowania wartości domyślnej dostawcy (a zaokrąglanie przez bankierów jest co najmniej alarmujące dla projektanta oczekującego, że wszystkie wartości kończące się na .5 zaokrągla się od zera) .Tak,
DECIMAL(24, 8)
brzmi to dla mnie przesada. Większość walut jest podawana 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 sytuacja, w której `` normalna '' kwota pieniężna (powiedzmy cztery miejsca po przecinku) została proporcjonalna, co oznacza, że dokładność dziesiętna powinna zostać odpowiednio zmniejszona (również rozważ typ zmiennoprzecinkowy w takich okolicznościach). I nikt nie ma dziś tak dużo pieniędzy, by wymagać dziesiętnej dokładności 24 :)Jednak zamiast podejścia uniwersalnego, niektóre badania mogą być w porządku. Zapytaj swojego projektanta lub eksperta dziedzinowego o zasady księgowania, które mogą mieć zastosowanie: GAAP, EU, itp. Mglisto przypominam sobie niektóre transfery wewnątrzpaństwowe w UE z wyraźnymi zasadami zaokrąglania do pięciu miejsc po przecinku, a zatem używam ich
DECIMAL(p, 6)
do przechowywania. Wydaje się, że księgowi preferują cztery miejsca po przecinku.PS Unikaj
MONEY
typu danych SQL Server, ponieważ wiąże się to z poważnymi problemami z dokładnością podczas zaokrąglania, między innymi kwestiami, takimi jak przenośność itp. Zobacz blog Aarona Bertranda .Microsoft i projektanci języków wybrali zaokrąglanie bankierów, ponieważ projektanci sprzętu wybrali to [cytat?]. Jest na przykład zapisana w normach Instytutu Inżynierów Elektryków i Elektroników (IEEE). A projektanci sprzętu wybrali to, ponieważ wolą to matematycy. Zobacz Wikipedię ; parafrazując: Wydanie Prawdopodobieństwa i teorii błędów z 1906 r. nazywało to „regułą komputera” („komputery” oznaczające ludzi wykonujących obliczenia).
źródło
DECIMAL(19, 4)
bardziej popularne niżDECIMAL(19, 2)
? Większość walut świata ma tylko dwa miejsca po przecinku.Niedawno wdrożyliśmy system, który musi obsługiwać wartości w wielu walutach i przeliczać między nimi, i na własnej skórze odkryliśmy kilka rzeczy.
NIGDY NIE UŻYWAJ PUNKTÓW ZMIENNYCH DO PIENIĘDZY
Arytmetyka zmiennoprzecinkowa wprowadza niedokładności, których można nie zauważyć, dopóki czegoś nie schrzanią. Wszystkie wartości powinny być przechowywane jako liczby całkowite lub typy ze stałymi dziesiętnymi, a jeśli zdecydujesz się użyć typu stałego dziesiętnego, upewnij się, że dokładnie rozumiesz, co ten typ robi pod maską (tj. Czy wewnętrznie używa liczby całkowitej czy zmiennoprzecinkowej rodzaj).
Kiedy musisz wykonać obliczenia lub konwersje:
Podczas konwertowania liczby zmiennoprzecinkowej z powrotem na liczbę całkowitą w kroku 3, nie rzucaj jej po prostu - użyj funkcji matematycznej, aby ją najpierw zaokrąglić. Zwykle tak będzie
round
, chociaż w szczególnych przypadkach może to byćfloor
lubceil
. Poznaj różnicę i rozważnie wybierz.Przechowuj typ liczby obok wartości
Może to nie być tak ważne dla Ciebie, jeśli obsługujesz tylko jedną walutę, ale było to dla nas ważne w przypadku obsługi wielu walut. Użyliśmy 3-znakowego kodu waluty, takiej jak USD, GBP, JPY, EUR itd.
W zależności od sytuacji pomocne może być również przechowywanie:
Poznaj granice dokładności liczb, z którymi masz do czynienia
W przypadku wartości rzeczywistych chcesz być tak dokładny, jak najmniejsza jednostka waluty. Oznacza to, że nie masz wartości mniejszych niż cent, pens, jen, torfowisko itp. Nie przechowuj wartości z większą dokładnością niż ta bez powodu.
Wewnętrznie możesz wybrać mniejsze wartości, w takim przypadku jest to inny typ wartości waluty . Upewnij się, że twój kod wie, który jest który i nie pomieszał ich. Unikaj używania wartości zmiennoprzecinkowych nawet tutaj.
Dodając wszystkie te zasady razem, zdecydowaliśmy się na następujące zasady. W działającym kodzie waluty są przechowywane przy użyciu liczby całkowitej dla najmniejszej jednostki.
W bazie danych wartości są przechowywane jako ciąg w następującym formacie:
To przechowuje wartość 25,00 $. Byliśmy w stanie to zrobić tylko dlatego, że kod zajmujący się walutami nie musi znajdować się w samej warstwie bazy danych, więc wszystkie wartości można najpierw przekonwertować na pamięć. Inne sytuacje bez wątpienia nadają się do innych rozwiązań.
A jeśli nie wyjaśniłem tego wcześniej, nie używaj pływaka!
źródło
bigint
jeśli zamierzasz sortować według kwoty. I nie trać czasu na 32-bitowe PHP w przypadku dużych liczb całkowitych, uaktualnij do wersji 64-bitowej lub Node.JS;)Podczas obsługi pieniędzy w MySQL, użyj DECIMAL (13,2), jeśli znasz dokładność swoich wartości pieniężnych, lub użyj DOUBLE, jeśli chcesz uzyskać szybką, wystarczająco dobrą przybliżoną wartość. Jeśli więc Twoja aplikacja musi obsługiwać wartości pieniężne do biliona dolarów (lub euro lub funtów), powinno to działać:
Lub, jeśli chcesz zachować zgodność z GAAP, użyj:
źródło
Cztery miejsca po przecinku zapewniłyby dokładność przechowywania najmniejszych na świecie podjednostek waluty. Możesz zejść dalej, jeśli potrzebujesz dokładności mikropłatności (nanopłat ?!).
Ja też wolę
DECIMAL
typy pieniędzy specyficzne dla DBMS, bezpieczniej zachowujesz tego rodzaju logikę w aplikacji IMO. Innym podejściem w tych samych wierszach jest po prostu użycie [długiej] liczby całkowitej, z formatowaniem na ¤unit.subunit dla czytelności dla człowieka (¤ = symbol waluty) wykonanym na poziomie aplikacji.źródło
Typ danych Money na serwerze SQL Server ma cztery cyfry po przecinku.
Z SQL Server 2000 Books Online:
Dane pieniężne 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 pieniężne mogą być przechowywane z dokładnością do czterech miejsc po przecinku. Typ danych Money służy do przechowywania wartości z zakresu od -922337203685477,5808 do +922337203685477,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 dziesiętnych, użyj zamiast tego typu danych dziesiętnych.
źródło
Czasami trzeba będzie zapłacić mniej niż centa, a istnieją waluty międzynarodowe, które wykorzystują bardzo duże kwoty demoniczne. Na przykład możesz obciążyć swoich klientów kwotą 0,088 centa za transakcję. W mojej bazie danych Oracle kolumny są zdefiniowane jako NUMBER (20,4)
źródło
Jeśli zamierzasz wykonywać jakiekolwiek operacje arytmetyczne w bazie danych (pomnożenie stawek rozliczeniowych itd.), Prawdopodobnie będziesz potrzebować dużo większej precyzji niż sugerują ludzie, z tych samych powodów, dla których nigdy byś nie chcą używać w kodzie aplikacji wartości mniejszych niż wartość zmiennoprzecinkowa o podwójnej precyzji.
źródło
BigDecimal
), ale przez długi czas była to podwójna precyzja (myśldouble
zamiastfloat
). Ponadto, w niektórych przypadkach arbitralna precyzja ma znaczący wpływ na wydajność. Testowanie to zdecydowanie właściwe podejście.Gdyby używany był serwer IBM Informix Dynamic Server, miałbyś typ MONEY, który jest podrzędnym wariantem typu DECIMAL lub NUMERIC. Jest to zawsze typ stałoprzecinkowy (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 chcesz przechowywać, możesz użyć DECIMAL (16,2) - wciąż wystarczająco dużego, aby utrzymać deficyt federalny USA, z dokładnością do jednego centa - lub możesz użyć mniejszego zakresu lub większej liczby miejsc dziesiętnych.
źródło
Wydaje mi się, że w dużej mierze wymagania twoje lub twojego klienta powinny dyktować, jakiej dokładności i skali użyć. Na przykład w przypadku witryny handlu elektronicznego, nad którą pracuję, która obsługuje pieniądze tylko w GBP, zostałem zobowiązany do zachowania wartości Decimal (6, 2).
źródło
Późna odpowiedź tutaj, ale użyłem
co mam rację, powinno pozwolić do 99 999 999 999,99.
źródło