Najlepszy typ danych do przechowywania wartości walut w bazie danych MySQL

Odpowiedzi:

227

Coś takiego Decimal(19,4)zwykle działa całkiem dobrze w większości przypadków. Możesz dostosować skalę i precyzję do potrzeb liczb, które chcesz przechowywać. Nawet w SQL Server nie używam „ money”, ponieważ jest niestandardowy.

Kibee
źródło
52
Punkt o rozmiarze: według MSDN ( msdn.microsoft.com/en-us/library/ms187746.aspx ), dziesiętne (10,4) i dziesiętne (19,4) oba używają 9 bajtów pamięci, więc może dobrze wiosna dla tych dodatkowych 9 cyfr skali.
Adam Nofsinger
1
Artykuł MSDN dotyczy SQL Server, ale pytanie dotyczy MySQL. (Spotkałem programistów, którzy uważają, że oba są takie same, więc najlepiej to wyjaśnić.)
cja
5
Jaka jest korzyść z używania (19,4)zamiast (19,2)?
ryvantage
1
Moją zaletą było to, że potrzebowałem wszystkich wierszy tabeli, aby wyrównać określoną kwotę pieniędzy. Powiedzmy, że ta kwota wynosi 10,00 $. W miarę dodawania nowych wierszy zmienia się ilość wierszy. Jeśli w tabeli są 3 wiersze. 10/3 = 3,3333333333 ... ale tylko z 2 miejscami po przecinku są przechowywane jako 3,33. Po zsumowaniu tych wartości 3,33 + 3,33 + 3,33 = 9,99. Straciliśmy grosz! Gorzej nawet w przypadku większego zestawu danych. Przechowuj w 19,4 i zsumuj swoje sumy, a następnie zaokrąglij wynik do 19,2 ..
Rick
49

Jedyną rzeczą, na którą musisz uważać, to migracja z jednej bazy danych do innej może okazać się, że DECIMAL (19,4) i DECIMAL (19,4) oznaczają różne rzeczy

( http://dev.mysql.com/doc/refman/5.1/en/precision-math-decimal-changes.html )

    DBASE: 10,5 (10 liczb całkowitych, 5 miejsc po przecinku)
    MYSQL: 15,5 (15 cyfr, 10 liczb całkowitych (15-5), 5 miejsc po przecinku)
SeanJA
źródło
Link nie działa, niestety.
Marco Aurélio Deleu,
1
@ MarcoAurélioDeleu - Zmieniłem link, aby wskazywał stronę na Wayback Machine, dzięki czemu można zobaczyć, jak wyglądał w 2009 roku.
Tony
17

Ważne jest również ustalenie, ile miejsc dziesiętnych może być wymaganych do obliczeń.

Pracowałem nad aplikacją cen akcji, która wymagała obliczenia ceny miliona akcji. Podana cena akcji musiała być zapisana z dokładnością do 7 cyfr.

Lea
źródło
7
To dobra uwaga - szczególnie w aplikacjach finansowych „cena” z pewnością nie oznacza „pieniędzy”
Mike Woodhouse
17

Odpowiedź Assafa na

Zależy, ile masz pieniędzy ...

brzmi to głupio, ale tak naprawdę to jest trafne.

Dopiero dzisiaj mieliśmy problem polegający na tym, że nie udało się wstawić rekordu do naszej tabeli stawek, ponieważ jedna z kolumn (GrossRate) ma wartość dziesiętną (11,4), a nasz dział produktów właśnie dostał kontrakt na pokoje w jakimś niesamowitym kurorcie w Bora Bora, które sprzedają za kilka milionów franków pacyficznych za noc ... coś, czego nigdy nie oczekiwano, kiedy schemat bazy danych został zaprojektowany 10 lat temu.

Scott Ferguson
źródło
2
Dlatego zalecałem przecinek dziesiętny (19,4). Może to brzmieć jak przesada, ale nigdy nie wiadomo, kiedy będziesz musiał przechowywać naprawdę dużą ilość w tym polu.
Kibbee,
2
@Kibbee: Do dzisiaj nie zgodziłbym się z tobą na nasze wymagania. (Przez 6 lat (11,4) wszystko było w porządku ...)
Scott Ferguson
@Kibbee Brzmi jak mem o 640 Kb :)
Nikita Bosik
13

W przypadku aplikacji księgowych bardzo często przechowywane są wartości jako liczby całkowite (niektóre nawet posunęły się do stwierdzenia, że ​​to jedyny sposób). Aby uzyskać pomysł, weź kwotę transakcji (załóżmy 100,23 USD) i pomnóż przez 100, 1000, 10000 itd., Aby uzyskać wymaganą dokładność. Więc jeśli potrzebujesz tylko przechowywać centy i możesz bezpiecznie zaokrąglić w górę lub w dół, po prostu pomnóż przez 100. W moim przykładzie dałoby to 10023 jako liczbę całkowitą do przechowywania. Zaoszczędzisz miejsce w bazie danych, a porównywanie dwóch liczb całkowitych jest znacznie łatwiejsze niż porównywanie dwóch liczb zmiennoprzecinkowych. Moje 0,02 $.

Dane Bendixen
źródło
Jak przechowywać 6.125 (6 1/8)?
PeterToTheThird
Myślę, że
zapisałby
2
Jak by to było lepsze niż DECIMAL? Trzeba bardzo uważać, aby zawsze w odpowiednim czasie tłumaczyć grosz, młyny lub młyny na dolary.
Czytałem, że wydajność jest zwykle szybsza z INT niż DECIMAL, nawet w najnowszych wersjach MySQL. Jest to również łatwiejsze, gdy musisz przenieść te wartości do PHP lub coś takiego i porównać wartości.
Dane Bendixen
9

bardzo późne wejście, ale GAAP to dobra zasada.

Jeśli Twoja aplikacja musi obsługiwać wartości pieniężne do biliona, powinno to działać: 13,2 Jeśli musisz przestrzegać GAAP (ogólnie przyjętych zasad rachunkowości), użyj: 13,4

Zwykle powinieneś sumować swoje wartości pieniężne na 13,4 przed zaokrągleniem wyniku do 13,2.

Źródło: Najlepszy typ danych do przechowywania wartości pieniężnej w MySQL

Damian
źródło
5

Możesz użyć czegoś takiego jak DECIMAL(19,2)domyślnie dla wszystkich swoich wartości pieniężnych, ale jeśli kiedykolwiek będziesz przechowywać wartości niższe niż 1000 USD, będzie to po prostu marnowanie cennej przestrzeni w bazie danych.

W przypadku większości implementacji DECIMAL(N,2)wystarczy, gdy wartość Njest co najmniej liczbą cyfr przed .największą sumą, jakiej można się spodziewać w tym polu + 5. Jeśli więc nie spodziewasz się przechowywać wartości większych niż 999999.99, DECIMAL(11,2)powinno być więcej niż wystarczające (dopóki nie zmienią się oczekiwania).

Jeśli chcesz być zgodny z GAAP , możesz przejść DECIMAL(N,4), gdzie wartość Nto co najmniej liczba cyfr przed .największą sumą, jakiej kiedykolwiek spodziewałeś się przechowywać w tym polu + 7.

John Slegers
źródło
3

To zależy od charakteru danych. Musisz to przemyśleć wcześniej.

Mój przypadek

  • dziesiętny (13,4) niepodpisany do rejestrowania transakcji pieniężnych
    • efektywne przechowywanie (w każdym razie 4 bajty z każdej strony miejsca dziesiętnego) 1
    • Zgodny z GAAP
  • dziesiętny (19,4) bez znaku dla agregatów
    • potrzebujemy więcej miejsca na sumy wielu wielomiliardowych transakcji
    • częściowa zgodność z typem danych MS Currency nie zaszkodzi 2
    • zajmie więcej miejsca na rekord (11 bajtów - 7 po lewej i 4 po prawej), ale to dobrze, ponieważ jest mniej rekordów dla agregatów 1
  • po przecinku (10,5) dla kursów wymiany
    • są zwykle cytowane łącznie 5 cyframi, więc można znaleźć wartości takie jak 1.2345 i 12.345, ale nie 12345.67890
    • jest to powszechna konwencja, ale nie skodyfikowany standard (przynajmniej według mojej wiedzy o szybkim wyszukiwaniu)
    • możesz ustawić wartość dziesiętną (18,9) przy tej samej pamięci, ale ograniczenia typów danych są cennym, wbudowanym mechanizmem sprawdzania poprawności

Dlaczego (M, 4)?

  • istnieją waluty podzielone na tysiąc groszy
  • istnieją ekwiwalenty pieniężne, takie jak „Unidad de Fermento”, „CLF” wyrażone z 4 znaczącymi miejscami po przecinku 3 , 4
  • jest zgodny z GAAP

Kompromis

  • niższa precyzja:
    • niższe koszty przechowywania
    • szybsze obliczenia
    • niższe ryzyko błędu obliczeniowego
    • szybsze tworzenie kopii zapasowych i przywracanie
  • wyższa precyzja:
    • przyszła kompatybilność (liczby zwykle rosną)
    • oszczędność czasu programowania (nie będziesz musiał odbudowywać połowy systemu, gdy limity zostaną osiągnięte)
    • mniejsze ryzyko niepowodzenia produkcji z powodu niewystarczającej precyzji przechowywania

Kompatybilny Extreme

Chociaż MySQL pozwala używać dziesiętnych (65, 30), 31 dla skali i 30 dla precyzji wydają się być naszymi ograniczeniami, jeśli chcemy pozostawić opcję transferu otwartą.

Maksymalna skala i precyzja w większości popularnych RDBMS:

            Skala precyzji
Oracle 31 31
T-SQL 38 38
MySQL 65 30
PostgreSQL 131072 16383

6 , 7 , 8 , 9

Rozsądny Extreme

  1. Dlaczego (27,4)?
    • nigdy nie wiadomo, kiedy system musi przechowywać dolary Zimbabwe

Wrzesień 2015 r. Rząd Zimbabwe oświadczył, że będzie wymieniał dolary Zimbabwe na dolary amerykańskie według stawki od 1 USD do 35 biliardów dolarów Zimbabwe 5

Zwykle mówimy „tak, jasne ... Nie będę potrzebował tych szalonych postaci”. Cóż, Zimbabwe też to mówili. Nie tak dawno temu.

Wyobraźmy sobie, że musisz zarejestrować transakcję 1 mln USD w dolarach Zimbabwe (być może dziś mało prawdopodobne, ale kto wie, jak to będzie wyglądać za 10 lat?).

  1. (1 mln USD) * (35 Quadrylion ZWL) = (10 ^ 6) * (35 * 10 ^ 15) = 35 * 10 ^ 21
  2. potrzebujemy:
    • 2 cyfry do zapisania „35”
    • 21 cyfr do przechowywania zer
    • 4 cyfry po prawej stronie przecinka dziesiętnego
  3. to czyni dziesiętne (27,4), co kosztuje nas 15 bajtów na każdy wpis
  4. możemy dodać jeszcze jedną cyfrę po lewej bez żadnych kosztów - mamy dziesiętne (28,4) na 15 bajtów
  5. Teraz możemy przechowywać transakcję o wartości 10 mln USD wyrażoną w dolarach Zimbabwe lub zabezpieczyć się przed kolejnym atakiem hiperinflacji, co, mam nadzieję, nie nastąpi
ksiszkin
źródło
0

Chociaż może to być późno, ale będzie pomocne dla kogoś innego. Z mojego doświadczenia i badań poznałem i akceptuję dziesiętne (19, 6). Tak jest podczas pracy z php i mysql. podczas pracy z dużą ilością pieniędzy i kursem wymiany

cenny
źródło