Czy należy wybrać typy danych PIENIĄDZE lub DECIMAL (x, y) w SQL Server?

442

Jestem ciekawy, czy istnieje prawdziwa różnica między moneytypem danych a czymś podobnym decimal(19,4)( jak sądzę, z czego pieniądze korzystają wewnętrznie).

Wiem, że moneyjest to specyficzne dla SQL Server. Chcę wiedzieć, czy istnieje ważny powód, aby wybierać między sobą; większość próbek SQL Server (np. baza danych AdventureWorks) używa, moneya nie decimaltakich informacji jak cena.

Czy powinienem po prostu nadal używać typu danych pieniędzy, czy zamiast tego jest korzyść z używania dziesiętnego? Pieniądze to mniej znaków do wpisania, ale to nie jest prawidłowy powód :)

Wayne Molina
źródło
12
DECIMAL(19, 4) jest popularnym wyborem sprawdź to również sprawdź tutaj Formaty walut światowych, aby zdecydować, ile miejsc po przecinku użyć, w czym nadzieja pomaga.
shaijut
Zastanawiałem się, dlaczego typ danych pieniędzy ma 4 miejsca po przecinku .. a nie 2. tj. 100 centów za dolara, więc wymagane są tylko 2 miejsca po przecinku? Do przechowywania rekordu kwot pieniężnych mniejszych niż 999,99 USD zamierzałem użyć typu danych dziesiętnych (6,2). Nie przejmuję się obliczeniami dzielenia lub mnożenia, tylko przechowywanie i sumowanie.
Allan F

Odpowiedzi:

326

Nigdy nie powinieneś używać pieniędzy. Nie jest precyzyjne i jest czystym śmieciem; zawsze używaj liczb dziesiętnych / numerycznych.

Uruchom to, aby zobaczyć, co mam na myśli:

DECLARE
    @mon1 MONEY,
    @mon2 MONEY,
    @mon3 MONEY,
    @mon4 MONEY,
    @num1 DECIMAL(19,4),
    @num2 DECIMAL(19,4),
    @num3 DECIMAL(19,4),
    @num4 DECIMAL(19,4)

    SELECT
    @mon1 = 100, @mon2 = 339, @mon3 = 10000,
    @num1 = 100, @num2 = 339, @num3 = 10000

    SET @mon4 = @mon1/@mon2*@mon3
    SET @num4 = @num1/@num2*@num3

    SELECT @mon4 AS moneyresult,
    @num4 AS numericresult

Wyjście: 2949.0000 2949.8525

Do niektórych osób, które powiedziały, że nie dzielisz pieniędzy przez pieniądze:

Oto jedno z moich zapytań do obliczenia korelacji, a zamiana tego na pieniądze daje złe wyniki.

select t1.index_id,t2.index_id,(avg(t1.monret*t2.monret)
    -(avg(t1.monret) * avg(t2.monret)))
            /((sqrt(avg(square(t1.monret)) - square(avg(t1.monret))))
            *(sqrt(avg(square(t2.monret)) - square(avg(t2.monret))))),
current_timestamp,@MaxDate
            from Table1 t1  join Table1 t2  on t1.Date = traDate
            group by t1.index_id,t2.index_id
SQLMenace
źródło
61
„Nigdy” to mocne słowo. „Pieniądze” są przydatne do przesyłania wyników tego typu do wyświetlania użytkownikowi w sposób wrażliwy na kulturę, ale masz rację, że bardzo źle jest używać go do samych obliczeń.
Joel Coehoorn
36
Twój przykład nie ma sensu, ponieważ nikt nigdy nie pomnoży dwóch obiektów typu pieniądze. Jeśli chcesz udowodnić swoją rację, musisz porównać pomnożenie pieniędzy przez dziesiętne, do pomnożenia dziesiętnych przez dziesiętne.
Brian
27
.. ale wciąż zastanawiające jest, dlaczego pieniądze * nie miałyby precyzji pieniędzy.
Nauka
4
@Learning: ma precyzję pieniędzy. Nadal jednak występują błędy zaokrąglania, które mogą się kumulować w miarę upływu czasu. Typ dziesiętny nie używa arytmetyki binarnej: gwarantuje, że otrzyma takie same wyniki 10, jak w przypadku pracy na papierze.
Joel Coehoorn
55
Mnożenie i dzielenie moneyna moneybok tej „ilustracji” jest manipulacyjne. Jest to udokumentowany fakt, który moneyma stałą i bardzo ograniczoną precyzję. W takich przypadkach należy najpierw pomnożyć, a następnie podzielić. Zmień kolejność operatorów w tym przykładzie, a otrzymasz identyczne wyniki. moneyZasadniczo jest 64-bitowy int, a jeśli były do czynienia z wskazówki, byś pomnożyć przed podziałem.
Andriy M,
272

SQLMenace powiedział, że pieniądze są niedokładne. Ale nie mnożysz / nie dzielisz pieniędzy przez pieniądze! Ile wynoszą 3 dolary razy 50 centów? 150 centów? Mnożysz / dzielisz pieniądze przez skalary, które powinny być dziesiętne.

DECLARE
@mon1 MONEY,
@mon4 MONEY,
@num1 DECIMAL(19,4),
@num2 DECIMAL(19,4),
@num3 DECIMAL(19,4),
@num4 DECIMAL(19,4)

SELECT
@mon1 = 100,
@num1 = 100, @num2 = 339, @num3 = 10000

SET @mon4 = @mon1/@num2*@num3
SET @num4 = @num1/@num2*@num3

SELECT @mon4 AS moneyresult,
@num4 AS numericresult

Rezultaty prawidłowego wyniku:

moneyresult numericresult
--------------------- ----------------------------- ----------
2949.8525 2949.8525

moneyjest dobry, o ile nie potrzebujesz więcej niż 4 cyfr dziesiętnych i upewniasz się, że twoje skalary - które nie reprezentują pieniędzy - są decimals.

konfigurator
źródło
57
ile monet 1 cent może ci dać dolar? odpowiedź na to wymaga pieniędzy / pieniędzy.
Nauka
48
@Learning w takim przypadku wynikiem nie są pieniądze, ale liczba zmienna. (Podstawowa analiza wymiarowa.)
Richard
11
@Learning: Czy pytasz bazę danych, ile centów za dolara dużo? W każdym razie to zwróci właściwy wynik. Jego problem polegał na tym, że pieniądze / pieniądze były precyzyjne tylko do czterech cyfr (było to 0,2949), a następnie pomnożone przez 10000 stały się 2949.0000.
konfigurator
26
@ mson Ma rację i nie krytykuj, tak jak zrobiłeś to w oparciu o uwagę w jednym wierszu, to nie jest pomocne. Jeśli nie podzieli przez 0,01 USD, a zamiast 0,01, wynik to 100 USD zamiast 100. Za dolara jest 100 centów, a nie 100 centów. Jednostki są ważne! Jest zdecydowanie duże miejsce do nurkowania, a być może pomnażania pieniędzy przez pieniądze.
andrewb
19
Czy jeśli chcę wydać 1000 USD na zakup akcji o wartości 36 USD, czy nie jest to zgodne z prawem money / money? Odpowiedź to całe jednostki bez dołączonego znaku dolara, co jest poprawne! Jest to całkowicie rozsądny scenariusz, sugerujący, że ze względu na takie dziwne przypadki brzegowe, takie jak ten, moneynie jest dobrym typem danych do użycia, ponieważ wynik jest zawsze przycinany z powrotem w celu dopasowania, moneyzamiast przestrzegać normalnych reguł dotyczących precyzji i skalowania. Co jeśli chcesz obliczyć odchylenie standardowe zestawu moneywartości? Tak, Sqrt(Sum(money * money))(uproszczony) faktycznie ma sens.
ErikE
59

Wszystko jest niebezpieczne, jeśli nie wiesz, co robisz

Nawet precyzyjne typy dziesiętne nie mogą uratować dnia:

declare @num1 numeric(38,22)
declare @num2 numeric(38,22)
set @num1 = .0000006
set @num2 = 1.0
select @num1 * @num2 * 1000000

1,000000 <- Powinien wynosić 0,6000000


Te moneytypy są liczbami całkowitymi

Tekstowe reprezentacje smallmoneyi decimal(10,4)mogą wyglądać podobnie, ale to nie czyni ich wymiennymi. Czy kulisz się, gdy widzisz daty zapisane jako varchar(10)? To jest to samo.

Za kulisami money/ smallmoneysą po prostu bigint/ int Punktem dziesiętnym w reprezentacji tekstowej moneyjest puch wizualny, podobnie jak myślniki z datą rrrr-mm-dd. SQL tak naprawdę nie przechowuje ich wewnętrznie.

Jeśli chodzi o decimalvs money, wybierz to, co jest odpowiednie do twoich potrzeb. Te moneytypy istnieją, ponieważ przechowywanie wartości księgowych jako wielokrotności całkowitych 1/10000 jednostki jest bardzo powszechne. Ponadto, jeśli masz do czynienia z rzeczywistymi pieniędzmi i obliczeniami wykraczającymi poza zwykłe dodawanie i odejmowanie, nie powinieneś robić tego na poziomie bazy danych! Zrób to na poziomie aplikacji, korzystając z biblioteki obsługującej zaokrąglanie przez bankiera (IEEE 754)

Zaraz
źródło
1
Czy możesz wyjaśnić, co się stało w tym przykładzie?
Siergiej Popow
4
Przepełnienie skali. W małych skalach numeryczna (a, b) * numeryczna (c, d) daje wartość liczbową (a-b + c-d + 1, max (b, d)). Jeśli jednak (a + b + c + d)> 38, SQL ogranicza skalę, obrabowując precyzję od strony ułamkowej, aby wypełnić stronę całkowitą, powodując błąd zaokrąglenia.
Anon
Wszystkie obliczenia numeryczne są podatne na utratę precyzji z powodu skalowania: zamiast tego oblicz wybierz 1000000 * @ num1 * @ num2
Mitch Wheat
Przykład Anona dotyczy wersji i bazy danych. ale ważna jest uwaga. w wersji 1.1 sqlanywhere przykład podaje poprawnie 0,00000. (Wiem, że mówimy tutaj o ms sql). Kolejna kwestia związana z brakiem typu pieniędzy w innej bazie danych, istnieją różne sposoby nazywania liczb dziesiętnych lub liczbowych jako pieniędzy, na przykład tworzenie domeny.
gg89
3
Myślę, że jest to najbardziej pouczająca odpowiedź, ponieważ wyjaśniłeś nie tylko popełniane błędy, ale także to, co naprawdę dzieje się za kulisami i dlaczego PIENIĄDZE istnieją. Nie jestem pewien, dlaczego otrzymanie tej odpowiedzi zajęło 4 lata, ale być może dlatego, że zbyt duży nacisk położono na „problem” obliczeniowy, a nie tyle na ile i ile pieniędzy i dziesiętnych.
Steve Sether
44

Zdaję sobie sprawę, że WayneM stwierdził, że wie, że pieniądze są specyficzne dla SQL Server. Jednak pyta, czy istnieją jakieś powody, aby używać pieniędzy w systemie dziesiętnym lub odwrotnie, i myślę, że należy podać jeden oczywisty powód, a mianowicie w systemie dziesiętnym, o jedną rzecz mniej martw się, jeśli kiedykolwiek będziesz musiał zmienić DBMS - co może się zdarzyć.

Uczyń swoje systemy tak elastycznymi, jak to możliwe!

Dziekan
źródło
1
Być może, ale teoretycznie można zadeklarować domenę o nazwie Money w innym DBMS (który obsługuje deklarację domen).
debatuje
Ponieważ ktoś obecnie konwertuje bazę danych SQL Server na Amazon Redshift, mogę ręczyć, że jest to prawdziwy problem. Staraj się unikać typów danych, które są dostosowane do konkretnej platformy bazy danych, chyba że istnieją uzasadnione powody biznesowe, aby z nich korzystać.
Nathan Griffiths
@Nathn, biorąc pod uwagę słaby system Redshift w porównaniu do PostgreSQL lub SQL Server, np. Bez datetypu, powiedziałbym, że zawsze będziesz mieć takie problemy. Powinieneś powiedzieć „Nie używaj przestarzałych typów, gdy baza danych już zapewnia lepsze, bardziej zgodne ze standardami typy i ostrzega przed przestarzałymi typami ”.
Panagiotis Kanavos
@PanagiotisKanavos - pieniądze nie są przestarzałe
Martin Smith
@MartinSmith zszokowało to, ponieważ nie jest w stanie obsłużyć wartości pieniężnych, takich jak BTC w 2017 r. Lub rozróżnić kwoty w GBP i EUR - nawet jeśli zbliżają się do parytetu: P. W każdym razie przejście do Redshift wprowadza wiele bólu
Panagiotis Kanavos
32

Cóż, lubię MONEY! Jest to bajt tańszy niż DECIMAL, a obliczenia wykonują się szybciej, ponieważ (pod przykryciem) operacje dodawania i odejmowania są zasadniczo liczbami całkowitymi. @ Przykład SQLMenace - który jest doskonałym ostrzeżeniem dla nieświadomych - może być również zastosowany do INTeger, gdzie wynik byłby zerowy. Ale to nie jest powód, aby nie używać liczb całkowitych - w stosownych przypadkach .

Jest więc całkowicie „bezpieczny” i odpowiedni do użycia, MONEYgdy masz do czynienia z tym, z czym masz do czynienia MONEYi stosuj go zgodnie z matematycznymi zasadami, które on przestrzega (tak samo jak np INT.

Czy byłoby lepiej, gdyby SQL Server promował dzielenie i mnożenie MONEYna DECIMALs (lub FLOATs?) - być może, ale nie zdecydowali się tego zrobić; nie zdecydowali się też promować INTegerów FLOATpodczas dzielenia ich.

MONEYnie ma problemu z precyzją; to, że DECIMALpodczas obliczeń może zostać użyty większy typ pośredni, jest po prostu „cechą” używania tego typu (i nie jestem pewien, jak daleko sięga ta „cecha”).

Aby odpowiedzieć na konkretne pytanie, „ważny powód”? Cóż, jeśli chcesz bezwzględną wydajność maksymalnie w SUM(x)którym xmogłyby być DECIMALlub MONEY, wtedy MONEYbędzie miał przewagę.

Nie zapomnij też, że jest mniejszym kuzynem SMALLMONEY- tylko 4 bajty, ale osiąga maksimum przy 214,748.3647- co jest dość małe jak na pieniądze - i dlatego często nie jest dobrze dopasowane.

Aby dowieść sensu przy użyciu większych typów pośrednich, jeśli przypisujesz pośrednio jawnie do zmiennej, DECIMALwystępuje ten sam problem:

declare @a decimal(19,4)
declare @b decimal(19,4)
declare @c decimal(19,4)
declare @d decimal(19,4)

select @a = 100, @b = 339, @c = 10000

set @d = @a/@b

set @d = @d*@c

select @d

Daje 2950.0000(okej, więc przynajmniej DECIMALzaokrąglaj, a nie MONEYobcinaj - tak samo jak liczba całkowita).

dsz
źródło
21
MONEYjest o jeden bajt mniejszy niż duży DECIMAL , z dokładnością do 19 cyfr. Jednak większość rzeczywistych obliczeń pieniężnych (do 9,99 mln USD) mieści się w DECIMAL(9, 2), co wymaga zaledwie pięciu bajtów. Możesz zaoszczędzić rozmiar, mniej przejmować się błędami zaokrąglania i uczynić kod bardziej przenośnym.
Podczas gdy @JonofAllTrades jest poprawny, możesz również odzyskać wydajność liczb całkowitych, po prostu używając liczby całkowitej zawierającej pensy lub centy, i zaoszczędzić dodatkowy bajt, który koduje pozycję przecinka dziesiętnego i który należy sprawdzić podczas dodawania miejsc po przecinku.
dsz
„Tak więc korzystanie z PIENIĘDZY jest całkowicie„ bezpieczne ”i właściwe, gdy masz do czynienia z PIENIĄDAMI i stosujesz je zgodnie z matematycznymi zasadami, którymi się kieruje” -> patrz jednak odpowiedź Anona: „Wszystko jest niebezpieczne, jeśli nie wiedzieć, co robisz ". Nigdy nie możesz przewidzieć, w jaki sposób ludzie będą pytać o system, który tworzysz, najlepiej, aby uniknąć możliwości niewłaściwego użycia, gdy możesz. Niewielki przyrost w magazynie nie jest tego wart IMHO.
Nathan Griffiths
1
Spróbuj zapisać wartość Bitcoin. Ma 8 miejsc po przecinku
Panagiotis Kanavos
13

Właśnie natrafiliśmy na bardzo podobny problem i jestem teraz bardzo +1 za to, że nigdy nie używam pieniędzy, z wyjątkiem prezentacji na najwyższym poziomie. Mamy wiele tabel (w rzeczywistości kupon sprzedaży i fakturę sprzedaży), z których każda zawiera jedno lub więcej pól pieniędzy z powodów historycznych, i musimy wykonać proporcjonalne obliczenia, aby obliczyć, ile całkowitej faktury podatku dotyczy każdego wiersz na kuponie sprzedaży. Nasze obliczenia to

vat proportion = total invoice vat x (voucher line value / total invoice value)

Powoduje to obliczanie pieniędzy / pieniędzy w świecie rzeczywistym, co powoduje błędy skali w części podziału, która następnie mnoży się do nieprawidłowej proporcji kadzi. Po późniejszym dodaniu tych wartości otrzymujemy sumę proporcji kadzi, które nie sumują się do całkowitej wartości faktury. Gdyby jedna z wartości w nawiasach była dziesiętna (mam zamiar rzucić jedną z nich jako taką), proporcja kadzi byłaby poprawna.

Kiedy nawiasy klamrowe nie były tam pierwotnie działały, myślę, że ze względu na większe wartości, efektywnie symulował większą skalę. Dodaliśmy nawiasy, ponieważ najpierw wykonywał mnożenie, co w niektórych rzadkich przypadkach podważyło dokładność dostępną do obliczeń, ale teraz spowodowało to znacznie częstszy błąd.

Kaideejee
źródło
8
Ale robi to tylko dlatego, że nieświadomy deweloper zignorował zasady obliczania podatku VAT i udokumentowane ograniczenia precyzji pieniędzy.
TomTom
1
@TomTom, ale zwracasz uwagę na możliwość niewłaściwego wykorzystania tego typu danych jest argumentem przemawiającym za tym, aby w ogóle go nie używać.
Nathan Griffiths
@Nathan Nie. Zwracam uwagę, że argument podany jako powód, aby nigdy go nie używać, jest zasadniczo niekompetentnym programistą, więc argument jest fałszywy.
TomTom
1
@TomTom niestety jest wielu niekompetentnych programistów (a także wielu niesamowitych) i dla mnie, chyba że mogę zagwarantować, w jaki sposób dane będą wyszukiwane w przyszłości i nikt nigdy nie popełni błędów opisanych tutaj , lepiej pomylić się po stronie ostrożności i użyć dziesiętnego typu. To powiedziawszy, po przeczytaniu wszystkich tych odpowiedzi widzę, że istnieją pewne konkretne przypadki użycia, w których pieniądze byłyby optymalnym rodzajem wykorzystania, po prostu nie użyłbym ich, chyba że byłby to bardzo dobry przypadek użycia (np. Kolumna będzie tylko kiedykolwiek agregowane według SUM, ładowanie zbiorcze dużych ilości danych finansowych).
Nathan Griffiths
@TomTom to nie tylko ograniczenia precyzji. Wewnętrzna reprezentacja może również powodować problemy. Pieniądze są wygodnym rodzajem łapania nieświadomych programistów, a nie świetnym typem, który deweloperzy niewłaściwie wykorzystują. Przykład kadzi, bez względu na zasady jej obliczania, powinien wyraźnie odstraszyć nieświadomych programistów, gdy zastosują to do ogólnego.
Gerard ONeill
12

Jako kontrapunkt dla ogólnego ciągu innych odpowiedzi. Zobacz wiele zalet pieniędzy… Typ danych! w Przewodniku SQLCAT po silniku relacyjnym

W szczególności chciałbym zwrócić uwagę na następujące kwestie

Pracując nad implementacjami dla klientów, znaleźliśmy kilka interesujących liczb dotyczących wydajności dotyczących typu danych pieniężnych. Na przykład, gdy Analysis Services ustawiono na typ danych waluty (od podwójnego) w celu dopasowania do typu danych pieniężnych programu SQL Server, nastąpiła 13% poprawa szybkości przetwarzania (wierszy / s). Aby uzyskać wyższą wydajność w ramach SQL Server Integration Services (SSIS), aby załadować 1,18 TB w mniej niż trzydzieści minut, jak zauważono w SSIS 2008 - rekordowy rekord ETL wydajności świata, zaobserwowano zmianę czterech kolumn dziesiętnych (9,2) o rozmiarze 5 bajtów w tabeli LINEITEM TPC-H na pieniądze (8 bajtów) poprawiło szybkość wstawiania zbiorczego o 20% ... Przyczyną poprawy wydajności jest protokół SQL Server z tabelowym strumieniem danych tabelarycznych (TDS), który ma kluczową zasadę projektowania do przesyłania danych w kompaktowej formie binarnej i jak najbliżej wewnętrznego formatu pamięci SQL Server. Empirycznie zaobserwowano to podczas SSIS 2008 - rekordowego testu wydajności ETL z wykorzystaniem Kernrate; protokół znacznie spadł, gdy typ danych został zmieniony na pieniądze z dziesiętnego. Dzięki temu przesyłanie danych jest tak wydajne, jak to możliwe. Złożony typ danych wymaga dodatkowych cykli analizowania i cykli procesora niż typ o stałej szerokości.

Tak więc odpowiedź na pytanie brzmi „to zależy”. Należy zachować ostrożność przy niektórych operacjach arytmetycznych, aby zachować precyzję, ale może się okazać, że warto wziąć pod uwagę względy wydajności.

Martin Smith
źródło
Jak w takim razie przechowujesz bitcoiny ?
Panagiotis Kanavos
@PanagiotisKanavos - nie mam pojęcia. Nigdy nie zagłębiałem się w bitcoiny i nic o tym nie wiem!
Martin Smith
6

Chcę przedstawić inne spojrzenie na PIENIĄDZE w porównaniu z NUMERYCZNYM, w dużej mierze oparte na mojej własnej wiedzy i doświadczeniu ... Moim punktem widzenia są PIENIĄDZE, ponieważ pracowałem z tym przez długi czas i nigdy tak naprawdę nie korzystałem z NUMERYCZNEGO dużo… .

MONEY Pro:

  • Rodzimy typ danych . Używa rodzimego typu danych ( liczba całkowita ) tak samo jak rejestr procesora (32- lub 64-bitowy), więc obliczenia nie wymagają zbędnego narzutu, więc są mniejsze i szybsze ... PIENIĄDZE potrzebują 8 bajtów i NUMERYCZNE (19, 4 ) potrzebuje 9 bajtów (o 12,5% więcej) ...

    PIENIĄDZE są szybsze, o ile są wykorzystywane, ponieważ miały być (jako pieniądze). Jak szybko? Mój prosty SUMtest na 1 milionie danych pokazuje, że PIENIĄDZE to 275 ms, a NUMERIC 517 ms ... To prawie dwa razy szybciej ... Dlaczego test SUM? Zobacz następny punkt Pro

  • Najlepsze dla pieniędzy . PIENIĄDZE najlepiej nadają się do przechowywania pieniędzy i wykonywania operacji, na przykład w zakresie księgowości. Pojedynczy raport może uruchamiać miliony dodatków (SUM) i kilka zwielokrotnień po zakończeniu operacji SUM. W przypadku bardzo dużych aplikacji księgowych jest prawie dwa razy szybszy i ma ogromne znaczenie ...
  • Niska precyzja pieniędzy . Pieniądze w prawdziwym życiu nie muszą być bardzo precyzyjne. Mam na myśli, że wiele osób może obchodzić około 1 cent USD, ale co powiesz na 0,01 centa USD? W rzeczywistości w moim kraju banki nie dbają już o centy (cyfra po przecinku dziesiętnym); Nie wiem o banku amerykańskim ani innym kraju ...

MONEY Con:

  • Ograniczona precyzja . PIENIĄDZE mają tylko cztery cyfry (po przecinku) precyzji, więc muszą zostać przekonwertowane przed wykonaniem operacji takich jak dzielenie ... Ale z drugiej strony moneynie musi być tak precyzyjne i ma służyć jako pieniądze, a nie tylko numer...

Ale ... Duże, ale tutaj twoja aplikacja dotyczy prawdziwych pieniędzy, ale nie używaj ich w wielu operacjach SUM, na przykład w rachunkowości. Jeśli zamiast tego używasz wielu podziałów i mnożenia, nie powinieneś używać PIENIĘDZY ...

Susilo
źródło
1
Jeśli masz zamiar powiedzieć, że pieniądze są szybsze niż dziesiętne, musisz nam powiedzieć takie rzeczy, jak rdbms, na jakim sprzęcie, z jakim systemem operacyjnym, z konkretnymi danymi obsługującymi dane zapytanie. Co więcej, jeśli nie jest to DOKŁADNIE dokładne, NIE przeprowadzam z nim żadnych operacji finansowych, ponieważ podatnik będzie raczej niezadowolony z odzyskania złych numerów. Dbasz o tysiąc centów, jeśli na przykład masz do czynienia z walutą amerykańską. Jeśli pieniądze tego nie robią, nie można ich użyć.
Haakon Løtveit
3
@ HaakonLøtveit ten cały wątek pytań i odpowiedzi dotyczy typu danych SQL Server „pieniądze”, więc nie sądzę, aby musieli to podawać w odpowiedzi. W niektórych okolicznościach pieniądze mogą być szybsze w użyciu niż dziesiętne (np. Ładowanie danych), więcej informacji można znaleźć w odpowiedzi Martina Smitha. Zgadzam się z większością tej odpowiedzi, ponieważ istnieją pewne przypadki użycia, które mogą sprawić, że Pieniądze będą bardziej efektywnym wyborem niż dziesiętne, jednak chyba, że ​​istnieją bardzo ważne argumenty przemawiające za ich użyciem, uważam, że należy tego unikać.
Nathan Griffiths
1
Bitcoin ma 8 miejsc po przecinku. Nie można nawet przechowywać w moneykolumnie
Panagiotis Kanavos
4

Wszystkie poprzednie posty przynoszą ważne punkty, ale niektóre nie odpowiadają dokładnie na pytanie.

Pytanie brzmi: dlaczego ktoś wolałby pieniądze, skoro wiemy, że jest to mniej precyzyjny typ danych i może powodować błędy, jeśli jest stosowany w złożonych obliczeniach?

Używasz pieniędzy, kiedy nie wykonujesz skomplikowanych obliczeń i możesz wymienić tę precyzję na inne potrzeby.

Na przykład, gdy nie trzeba wykonywać tych obliczeń i trzeba zaimportować dane z prawidłowych ciągów tekstowych waluty. Ta automatyczna konwersja działa tylko z typem danych MONEY:

SELECT CONVERT(MONEY, '$1,000.68')

Wiem, że możesz stworzyć własną procedurę importu. Ale czasami nie chcesz odtwarzać procedury importu z formatami regionalnymi specyficznymi dla całego świata.

Kolejny przykład, gdy nie musisz wykonywać tych obliczeń (musisz tylko zapisać wartość) i musisz zaoszczędzić 1 bajt (pieniądze zajmują 8 bajtów, a dziesiętne (19,4) - 9 bajtów). W niektórych aplikacjach (szybki procesor, duża pamięć RAM, wolne IO), np. Po prostu odczytywanie dużej ilości danych, może to być również szybsze.

Weber K.
źródło
2

Nie powinieneś używać pieniędzy, gdy musisz wykonać pomnożenie / podział wartości. Pieniądze są przechowywane w taki sam sposób, jak liczba całkowita, podczas gdy dziesiętny jest przechowywany jako przecinek dziesiętny i cyfry dziesiętne. Oznacza to, że pieniądze spadną dokładność w większości przypadków, podczas gdy dziesiętne zrobi to tylko po przywróceniu do pierwotnej skali. Pieniądze są stałym punktem, więc ich skala nie zmienia się podczas obliczeń. Ponieważ jednak jest to punkt stały, gdy jest drukowany jako ciąg dziesiętny (w przeciwieństwie do stałej pozycji w łańcuchu podstawowym 2), wartości do skali 4 są dokładnie reprezentowane. Więc dodawanie i odejmowanie pieniędzy jest w porządku.

Dziesiętny jest reprezentowany wewnętrznie w podstawie 10, a zatem pozycja punktu dziesiętnego jest również oparta na liczbie podstawowej 10. Co sprawia, że ​​jego ułamkowa część dokładnie reprezentuje jego wartość, tak jak w przypadku pieniędzy. Różnica polega na tym, że pośrednie wartości dziesiętne mogą zachować dokładność do 38 cyfr.

W przypadku liczby zmiennoprzecinkowej wartość jest zapisywana w postaci binarnej, tak jakby była liczbą całkowitą, a pozycja punktu dziesiętnego (lub binarnego, ahem) jest względna do bitów reprezentujących liczbę. Ponieważ jest to binarny przecinek dziesiętny, podstawowe liczby 10 tracą precyzję zaraz po przecinku. 1/5, czyli 0,2, nie może być dokładnie przedstawiona w ten sposób. Ograniczenia nie dotyczą ani pieniędzy, ani dziesiętnych.

Łatwo jest przekonwertować pieniądze na dziesiętne, wykonać obliczenia, a następnie zapisać wynikową wartość z powrotem w polu pieniężnym lub zmiennej.

Z mojego POV chcę, aby rzeczy, które zdarzają się z liczbami, po prostu się wydarzyły, bez konieczności zbytniego zastanawiania się nad nimi. Jeśli wszystkie obliczenia zostaną przekonwertowane na dziesiętne, to dla mnie chciałbym użyć dziesiętnego. Zaoszczędziłbym pole pieniędzy do celów wyświetlania.

Pod względem wielkości nie widzę wystarczającej różnicy, aby zmienić zdanie. Pieniądze zajmują 4 - 8 bajtów, podczas gdy dziesiętne mogą być 5, 9, 13 i 17. 9 bajtów może obejmować cały zakres, w jakim może być 8 bajtów pieniędzy. Pod względem indeksu (porównywanie i wyszukiwanie powinny być porównywalne).

Gerard ONeill
źródło
Dzięki za upvote. Patrzę na to i chociaż rozumiem, co próbowałem powiedzieć, widzę, że jest to bardzo mylące. Być może przepiszę to później, podając przykłady bitów vs. dziesiętne.
Gerard ONeill
2

Znalazłem powód używania dziesiętnego zamiast pieniędzy w temacie dokładności.

DECLARE @dOne   DECIMAL(19,4),
        @dThree DECIMAL(19,4),
        @mOne   MONEY,
        @mThree MONEY,
        @fOne   FLOAT,
        @fThree FLOAT

 SELECT @dOne   = 1,
        @dThree = 3,    
        @mOne   = 1,
        @mThree = 3,    
        @fOne   = 1,
        @fThree = 3

 SELECT (@dOne/@dThree)*@dThree AS DecimalResult,
        (@mOne/@mThree)*@mThree AS MoneyResult,
        (@fOne/@fThree)*@fThree AS FloatResult

Wynik dziesiętny> 1,000000

MoneyResult> 0,9999

Wynik Float> 1

Po prostu przetestuj i podejmij decyzję.

QMaster
źródło
2
Bardzo chcielibyśmy usłyszeć (przeczytać, to znaczy) twój wniosek.
Peter Mortensen
@PeterMortensen Myślę, że jeśli chcę mieć kompletność i dokładność między rodzajami pieniędzy i dziesiętnymi, moja decyzja powinna być dziesiętna.
QMaster
1
Zastanów się nad zaktualizowaniem swojej odpowiedzi o rzeczywisty wynik powyższego. Wtedy twój wniosek będzie od razu oczywisty dla każdego, kto czyta :-)
Agreax
1
@Ageax Wynik dodany do odpowiedzi.
QMaster
1

Właśnie zobaczyłem ten wpis na blogu: Pieniądze vs. dziesiętne w SQL Server .

Co w zasadzie mówi, że pieniądze mają problem z precyzją ...

declare @m money
declare @d decimal(9,2)

set @m = 19.34
set @d = 19.34

select (@m/1000)*1000
select (@d/1000)*1000

Za ten moneytyp otrzymasz 19,30 zamiast 19,34. Nie jestem pewien, czy istnieje scenariusz aplikacji, który dzieli pieniądze na 1000 części do obliczeń, ale ten przykład narzuca pewne ograniczenia.

Harsha
źródło
15
To nie jest „problem”, to „zgodnie ze specyfikacjami”: „Dane moneyi smallmoneytypy danych są dokładne z dokładnością do dziesięciu tysięcznych reprezentowanych przez nich jednostek monetarnych.” jak powiedziano w msdn.microsoft.com/en-us/library/ms179882.aspx, więc każdy, kto mówi „to śmieci”, nie wie o czym mówi.
Albireo,