Najlepszy typ danych do przechowywania wartości pieniężnych w MySQL

279

Chcę przechowywać wiele rekordów w bazie danych MySQL. Wszystkie zawierają wartości pieniężne. Ale nie wiem, ile cyfr zostanie wstawionych dla każdego.
Jakiego typu danych muszę użyć w tym celu?
VARCHAR lub INT (lub inne typy danych numerycznych)?

Mohammad Saberi
źródło
13
deimal(10,2)to jest to, czego używam ... możesz dostosować wartości w zależności od oczekiwanego rozmiaru
Manse
9
Powiązane pytanie to Najlepszy typ danych dla waluty ;).
shA.t

Odpowiedzi:

370

Ponieważ pieniądze wymagają dokładnej reprezentacji, nie używaj typów danych, które są jedynie przybliżone float. Możesz użyć do tego typu liczbowego typu danych o stałym punkcie

decimal(15,2)
  • 15 to precyzja (całkowita długość wartości, w tym miejsca po przecinku)
  • 2 to liczba cyfr po przecinku

Zobacz typy liczbowe MySQL :

Te typy są używane, gdy ważne jest zachowanie dokładności, na przykład w przypadku danych pieniężnych .

juergen d
źródło
3
jaka może być różnica między dziesiętnym a numerycznym typem danych w tym przypadku?
Emilio Gort,
60
W MySQL decimali numericsą takie same.
juergen d
21
Ja osobiście używam numeric(19,4)do dokumentacji finansowej, która daje lepszą rękę do grania i łatwego przyjmowania nowych żądań.
YahyaE
10
Zgadzam się z YahyaE, więcej miejsc po przecinku jest lepsze. Istnieją waluty, które zwykle używają 3 miejsc po przecinku, takie jak dinary Bahrajnu, Jordanii lub Kuwejtu, więc potrzebujesz co najmniej 3. Cztery lub pięć jest lepszych.
Edwin Hoogerbeets
1
@EdwinHoogerbeets Nie jestem księgowym ... ale prowadzę małą firmę w Wielkiej Brytanii ... Pamiętam, że czytałem gdzieś dawno temu, że liczby walut powinny być przechowywane z dokładnością do 4 miejsc po przecinku nawet za £, $ itp., Aby niektóre obliczenia mogły faktycznie używają 2 ostatnich miejsc po przecinku dla niektórych niejasnych kontekstów księgowych. Wd potrzebuje księgowego do potwierdzenia / odrzucenia.
Mike Gryzonie
88

Możesz użyć DECIMALlub NUMERICoba są takie same

Typy DECIMAL i NUMERIC przechowują dokładne wartości danych liczbowych. Te typy są używane, gdy ważne jest zachowanie dokładności, na przykład w przypadku danych pieniężnych. W MySQL, NUMERIC jest zaimplementowany jako DECIMAL, więc poniższe uwagi o DECIMAL dotyczą w równym stopniu NUMERIC. : MySQL

to znaczy DECIMAL(10,2)

Example settings

Dobra lektura

NullPoiиteя
źródło
3
Może mylące, ale zrzut ekranu nie pasuje do tekstu odpowiedzi (precyzja, skala).
Patrick Hofman
Używam wartości dziesiętnych (10,2) do mojej wartości pieniężnej, jednak gdy wstawię coś w rodzaju 867,000,00, zostanie zapisana jako 867. co robię źle?
codeinprogress
32

Wolę używać BIGINTi przechowywać wartości, mnożąc przez 100 , aby stała się liczbą całkowitą.

Na przykład, aby przedstawić wartość waluty 93.49, wartość należy zapisać jako 9349, wyświetlając wartość, którą możemy podzielić przez 100 i wyświetlić. Zajmie to mniej miejsca do przechowywania.

Uwaga:
przeważnie nie wykonujemy currency * currencymnożenia, w przypadku, gdy to robimy, podziel wynik przez 100 i zapisz, aby powrócił do właściwej precyzji.

Dinesh PR
źródło
Pamiętam, jak profesor na moim uniwersyteckim systemie komputerowym powiedział mi coś podobnego. Nauczono mnie, że najbardziej precyzyjnym sposobem jest przechowywanie w groszach (lub centach) przez pomnożenie przez 100 i zapisanie jako liczba całkowita i podzielenie przez 100, aby wyświetlić to użytkownikowi. Myślę, że ma to zalety pod względem dokładności i wydajności systemu bazy danych.
LondonAppDev,
11
Jaka jest przewaga DECIMAL? Stwarzasz potrzebę przetłumaczenia groszy na dolary i biada, jeśli w pewnym momencie o tym zapomnisz.
1
Przestrzeń jest jedyną zaletą, ale tak, musimy zachować większą ostrożność, gdy korzystamy z tej funkcji.
Dinesh PR
4
W przypadku, gdy nie jest to oczywiste: zachowaj ostrożność przy stosowaniu metody usuwania kamienia, jeśli przechowujesz pieniądze w centach ułamkowych (np. $0.005Lub $0.12345), ponieważ nie zmniejszą się one do liczby całkowitej po pomnożeniu przez 100. Jeśli znasz dokładność wartości, jasne jest, że najlepszą opcją jest użycie DECIMAL. Ale jeśli nie znasz precyzji (jak w moich przykładach), to… byłoby FLOATwłaściwe?
Quinn Comendant
1
Zaletą tej metody jest użycie języka takiego jak JavaScript, który używa IEEE-754 do przechowywania liczb zmiennoprzecinkowych. Ta specyfikacja nie gwarantuje, że 0,1 + 0,2 === 0,3 jest prawdziwe. Przechowywanie waluty jako liczby całkowitej daje pewność, że aplikacja nie popełni tego rodzaju błędu. To może nie być najlepsze rozwiązanie. Dotarłem do tej strony, szukając rozwiązań i jeszcze nie skończyłem.
Gary Ott
27

To zależy od twoich potrzeb.

Używanie DECIMAL(10,2)zwykle wystarcza, ale jeśli potrzebujesz nieco bardziej precyzyjnych wartości, możesz ustawić DECIMAL(10,4).

Jeśli pracujesz z dużymi wartościami zastąpić 10z 19.

Svetoslav
źródło
Używam wartości dziesiętnych (10,2) do mojej wartości pieniężnej, jednak gdy wstawię coś w rodzaju 867,000,00, zostanie zapisana jako 867. co robię źle?
codeinprogress
2
@codeinprogress Używasz niewłaściwych ustawień narodowych / separatora dziesiętnego?
David Balažic
15

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.

david.ee
źródło
5
Jeśli chcesz wziąć Bitcoin, potrzebujesz 8 miejsc po przecinku, chociaż większość portfeli trafia do mBTC, czyli 3 pl.wikipedia.org/wiki/Bitcoin
Christian
Nie myśl, że ta odpowiedź jest prawdziwa. opendata.stackexchange.com/a/10348/13983 @ david.ee masz na to źródło?
Evan Carroll,
@EvanCarroll pozwól mi odpowiedzieć na david.ee. Myślę, że ten artykuł może być źródłem rietta.com/blog/2012/03/03/best-data-types-for-currencymoney-in
naXa
@naXa link nie cytuje niczego z żadnego źródła, które wspiera twierdzenie o zastosowaniu 13,4 dla GAAP. Wszystko, co zrobiłeś, to link do artykułu, który przedstawia to samo bezpodstawne twierdzenie.
iheanyi
6

Rzeczywiście zależy to od preferencji programisty. Ja osobiście używam: w numeric(15,4)celu przestrzegania ogólnie przyjętych zasad rachunkowości ( GAAP ) .

Chagbert
źródło
5
Nie ma to nic wspólnego z „preferencjami programisty” ani z tym, czego „osobiście używasz”. Jest to podyktowane domeną problemową, która wymaga dziesiętnej podstawy. Nie jest to kwestia, w której programista może ćwiczyć swoje osobiste preferencje.
Markiz Lorne
3

Spróbuj użyć

Decimal(19,4)

zwykle działa to również z każdym innym DB

Deepesh
źródło
3

Używamy double.

*łapanie tchu*

Czemu?

Ponieważ może reprezentować dowolną 15-cyfrową liczbę bez ograniczeń co do miejsca po przecinku . Wszystko za marne 8 bajtów!

Może więc reprezentować:

  • 0.123456789012345
  • 123456789012345.0

... i wszystko pomiędzy.

Jest to przydatne, ponieważ mamy do czynienia z globalnymi walutami idouble możemy przechowywać różne liczby miejsc dziesiętnych, które prawdopodobnie napotkamy.

Pojedyncze doublepole może reprezentować 999,999,999,999,999 sekund w jenach japońskich, 9999,999,999,999,99 dolarów w dolarach amerykańskich, a nawet 9 999,999.99999999 sekund w bitcoinach

Jeśli spróbujesz zrobić to samo decimal, potrzebujesz decimal(30, 15)14 bajtów.

Ostrzeżenia

Oczywiście używanie doublenie jest bez zastrzeżeń.

Jednak nie jest to utrata dokładności, jak niektórzy wskazują. Chociaż doublesam może nie być wewnętrznie dokładny w stosunku do systemu podstawowego 10 , możemy to zrobić, zaokrąglając wartość którą pobieramy z bazy danych do jej znaczących miejsc po przecinku. W razie potrzeby to jest. (np. jeśli ma zostać wydrukowany i wymagana jest podstawowa reprezentacja 10).

Zastrzeżenia są następujące: za każdym razem, gdy wykonujemy z nim arytmetykę, musimy znormalizować wynik (zaokrąglając go do jego znaczących miejsc po przecinku) przed:

  1. Przeprowadzanie na nim porównań.
  2. Zapisywanie go z powrotem do bazy danych.

Innym zastrzeżeniem jest to, że w przeciwieństwie do sytuacji, w decimal(m, d)której baza danych uniemożliwia programom wstawianie liczb zawierających więcej niż mcyfry, nie ma takiej weryfikacji double. Program może wstawić wprowadzoną przez użytkownika wartość 20 cyfr, a następnie zostanie po cichu zapisany jako niedokładna kwota.

antak
źródło
Pierwszy raz widziałem taką odpowiedź, interesującą. P: Jeśli napiszę liczbę zmiennoprzecinkową taką jak 1.41 do bazy danych i z jakiegoś powodu muszę ją pomnożyć przez jakąś ogromną liczbę w mysql, na przykład 1.000.000.000.000. Czy zaokrąglony wynik będzie wynosił: 1.410.000.000.000?
roelleor
@roelleor Aby wynik wynosił dokładnie 1 410 1.410000000000000 000 000 (przecinek jako separator tysięcy), przyjmuje się, że dane wejściowe wynoszą (dwanaście znaczących miejsc po przecinku), ale pomnożenie tego przez 1 000 000 000 000 (czyli 13 cyfr znaczących po przecinku) oznacza, że ​​pracujemy z co najmniej 25 cyfr znaczących łącznie. To znacznie przewyższa 15 dostępnych za podwójną, więc myślę, że pod względem projektowym byłby bardzo zepsuty.
antak
2

W chwili, gdy zadano pytanie, nikt nie myślał o cenie Bitcoin. W przypadku BTC korzystanie z niego jest prawdopodobnie niewystarczające DECIMAL(15,2). Jeśli Bitcoin wzrośnie do 100 000 USD lub więcej, będziemy musieli przynajmniej DECIMAL(18,9)wspierać kryptowaluty w naszych aplikacjach.

DECIMAL(18,9)zajmuje 12 bajtów miejsca w MySQL ( 4 bajty na 9 cyfr ).

bizwiz
źródło
> Bitcoin można podzielić na 8 miejsc po przecinku. Dlatego 0,00000001 BTC to najmniejsza kwota, którą można obsłużyć w transakcji. Myślę, że masz na myśli 8 zamiast 9?
danger89
1
Wiem, ale 9 zajmuje tyle samo miejsca na dysku co 8. Z dokumentów MySQL: „Wartości dla kolumn DECIMAL są przechowywane w formacie binarnym, który zawiera dziewięć cyfr dziesiętnych w 4 bajtach”
bizwiz
O, przepraszam, teraz cię rozumiem. Dzięki.
niebezpieczne89
2

Przechowywanie pieniędzy BIGINTpomnożonych przez 100 lub więcej z powodu mniejszej ilości miejsca do przechowywania nie ma sensu we wszystkich „normalnych” sytuacjach.

  • Aby pozostać w zgodzie z GAAP, wystarczy przechowywać waluty DECIMAL(13,4)
  • Podręcznik MySQL czyta, że ​​potrzebuje 4 bajtów na 9 cyfr do przechowywania DECIMAL.
  • DECIMAL(13,4) reprezentuje 9 cyfr + 4 cyfry ułamkowe (miejsca dziesiętne) => 4 + 2 bajty = 6 bajtów
  • porównaj z 8 bajtami wymaganymi do przechowywania BIGINT.
digitalstraw
źródło