SQL Server'da PARA veya DECIMAL (x, y) veri türlerini seçmeli misiniz?


443

moneyVeri türü ve benzeri bir şey arasında gerçek bir fark olup olmadığını merak ediyorum decimal(19,4)(paranın dahili olarak kullandığı şey , inanıyorum).

moneySQL Server'a özgü olduğunun farkındayım . Birini diğerinden seçmek için zorlayıcı bir neden olup olmadığını bilmek istiyorum; En SQL Server örnekleri (örn AdventureWorks veritabanı) kullanımı moneyve decimalfiyat bilgileri gibi şeyler için.

Para veri tipini kullanmaya devam etmeli miyim yoksa ondalık kullanmanın bir yararı var mı? Para yazmak için daha az karakter var, ancak bu geçerli bir neden değil :)


12
DECIMAL(19, 4) popüler bir seçim olduğunu kontrol bu da kontrol buraya kullanımına kaç ondalık basamak karar vermek Dünya Para Biçimleri, umut yardımcı olur.
shaijut

Neden para veri türü 4 değil ondalık .. merak ediyorum 2 değil .. yani bir dolar 100 sent yani sadece 2 ondalık basamak gerekli? 9999,99 $ 'dan daha az bir miktar para biriktirmek için, ondalık veri türüne gidecektim (6,2). Bölme veya çarpma hesaplamaları, sadece depolama ve toplama hakkında endişelenmiyorum ..
Allan F

Yanıtlar:


326

Asla para kullanmamalısınız. Kesin değildir ve saf çöptür; her zaman ondalık / sayısal kullanın.

Ne demek istediğimi görmek için bunu çalıştırın:

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

Çıktı: 2949.0000 2949.8525

Parayı paraya bölmediğinizi söyleyen bazı insanlara:

İşte korelasyonları hesaplamak için sorgularımdan biri ve bunu paraya çevirmek yanlış sonuçlar veriyor.

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

61
"Asla" güçlü bir kelimedir. "Para", kullanıcıya kültüre duyarlı bir şekilde görüntülenmesi için bu tür sonuçların yayınlanmasında yararlıdır, ancak hesaplamaların kendisi için kullanmanın çok kötü olduğunu doğru düşünüyorsunuz.
Joel Coehoorn

36
Örneğiniz anlamlı değil, çünkü hiç kimse iki para türü nesneyi çoğaltmayacak. Eğer noktanızı kanıtlamak istiyorsanız, bir ondalık sayıyı ondalık ile çarpmak için bir paranın ondalık sayı ile çarpılmasını karşılaştırmanız gerekir.
Brian

27
.. ama yine de neden paranın * paranın paranın hassasiyetine sahip olmayacağı şaşırtıcı.
öğrenme

4
@ Öğrenme: para hassasiyeti var. Ancak, yine de zamanla birikebilecek yuvarlama hatalarıyla karşılaşırsınız. Ondalık türü ikili aritmetik kullanmaz: kağıt üzerinde yapacağınız aynı temel 10 sonucu almasını garanti eder.
Joel Coehoorn

55
Çarpma ve bölünmesi moneyüzerinde moneybir yana, bu 'örnekleme' manipülatif. moneySabit ve çok sınırlı bir hassasiyete sahip belgelenmiş bir gerçektir . Bu gibi durumlarda önce çarpılmalı, sonra bölünmelidir. Bu örnekteki işleçlerin sırasını değiştirdiğinizde aynı sonuçları elde edersiniz. Bir moneyesasen 64-bit int olur ve ints başa olsaydı, çarpma bölme olacak önce.
Andriy M

272

SQLMenace, paranın tam olmadığını söyledi. Ama parayı parayla çarpmaz / bölmezsiniz! 3 dolar 50 sent ne kadar? 150 dolar mı? Parayı ondalık olması gereken skalerlerle çarpıyorsunuz / bölüyorsunuz.

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

Sonuçlar doğru sonuç:

moneyresult sayısal sonuçlar
--------------------- ----------------------------- ----------
2949.8525 2949.8525

money4'ten fazla ondalık basamağa ihtiyacınız olmadığı sürece iyidir ve parayı temsil etmeyen skalerlerinizin decimals olduğundan emin olun .


57
Bir dolarlık banknot kaç tane kuruş para alabilir? buna cevap para / para gerektirir.
öğrenme

48
@Bu durumda öğrenme para değil, bir şamandıradır. (Temel boyutlu analiz.)
Richard

11
@ Öğrenme: Veritabanına bir dolar içinde kaç sent çok soruyor musunuz? Her neyse, bu doğru sonucu döndürür. Onun problemi, paranın / paranın sadece dört basamağa (0.2949) hassas olmasıydı, daha sonra 10000 ile çarpıldığında 2949.0000 oldu.
yapılandırıcı

26
@mson O doğru ve tek satırlık bir açıklama dayalı kişisel eleştiriler yapmayın, bu yararlı değil. Eğer 0,01 dolara bölünmezse, 0,01 yerine sonuç 100 yerine 100 dolar olur. 100 sent değil, bir dolar içinde 100 sent vardır. Birimler önemlidir! Parayı parayla dalmak ve belki de çoğaltmak için kesinlikle büyük bir yer var.
andrewb

19
36 $ 'lık hisse senedi satın almak için 1000 $ harcamak istersem, bu meşru bir kullanım değil money / moneymi? Cevap dolar işareti olmayan tüm birimlerdir, bu doğru! Bu, oldukça garip bir senaryodur, bu gibi garip kenar vakaları nedeniyle, moneykullanım için iyi bir veri türü değildir, çünkü sonuç, moneyhassasiyet ve ölçek için normal kurallara uymak yerine her zaman sığacak şekilde kesilir . Bir değer kümesinin standart sapmasını hesaplamak isterseniz ne olur money? Evet, Sqrt(Sum(money * money))(basitleştirilmiş) aslında mantıklı.
ErikE

59

Ne yaptığını bilmiyorsan her şey tehlikelidir

Yüksek hassasiyetli ondalık türler bile günü kurtaramaz:

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

1.000000 <- 0.6000000 olmalıdır


moneyTürleri tam sayılardır

Metin temsili smallmoneyve decimal(10,4)benzer görünebilir, ancak bu onları değiştirilebilir yapmaz. Tarihlerin depolandığını gördüğünüzde küfür ediyor musunuz varchar(10)? Bu aynı şey.

Sahnelerin arkasında, money/ smallmoneysadece a bigint/ y'nin int metin temsilindeki ondalık noktası moneygörsel tüylerdir, tıpkı yyyy-aa-gd tarihindeki çizgiler gibi. SQL bunları dahili olarak saklamaz.

decimalVs ile ilgili moneyolarak, ihtiyaçlarınıza uygun olanı seçin. moneyBiriminin 1/10000 tam katı olarak muhasebe değerleri depolamak çok yaygın olduğu için tipleri vardır. Ayrıca, basit toplama ve çıkarma ötesinde gerçek para ve hesaplamalar ile uğraşıyorsanız, bunu veritabanı düzeyinde yapmamalısınız! Bankacı Yuvarlamasını destekleyen bir kütüphane ile uygulama düzeyinde yapın (IEEE 754)


1
Bu örnekte ne olduğunu açıklayabilir misiniz?
Sergey Popov

4
Ölçek taşması. Küçük ölçeklerde sayısal (a, b) * sayısal (c, d) sayısal verir (a-b + c-d + 1, maks. (B, d)). Ancak, (a + b + c + d)> 38 ise, SQL ölçeği kapatır ve tamsayı tarafını doldurmak için kesir tarafındaki hassasiyeti sorar ve yuvarlama hatasına neden olur.
Anon

Tüm sayısal hesaplamalar, ölçeklendirme nedeniyle hassasiyet kaybına karşı hassastır: bunun yerine hesaplama 1000000 * @ num1 * @ num2'yi seçin
Mitch Wheat

Anon'un örneği sürüme ve veritabanına özgüdür. ancak dikkat edilmesi gereken nokta geçerlidir. sqlanywhere sürüm 1.1, örnek 0.600000 doğru verir. (Burada ms sql hakkında konuştuğumuzu biliyorum). para türünün diğer veritabanında bulunmamasıyla ilgili başka bir nokta, etki alanı oluşturmak gibi ondalık veya sayısal olarak para olarak adlandırmanın yolları vardır.
gg89

3
Bunun en aydınlatıcı cevap olduğunu düşünüyorum çünkü sadece yayılan hataları değil, sahnenin arkasında neler olup bittiğini ve ilk olarak neden PARA'nın var olduğunu açıkladınız. Bu cevabı almak için neden 4 yıl sürdüğünden emin değilim, ama belki de hesaplama "problemine" çok fazla odaklanıldığından ve neden ondalık ve paranın ondalıklarına çok fazla odaklanmadığı için.
Steve Sether

44

WayneM'in paranın SQL Server'a özgü olduğunu bildiğini belirttiğini anlıyorum. Ancak, ondalık üzerinde para kullanmak için herhangi bir neden olup olmadığını soruyor ya da tam tersi ve bence açık bir neden hala belirtilmelidir ve ondalık kullanmak DBMS'nizi değiştirmek zorunda kalırsanız endişelenmeniz gereken daha az şey anlamına gelir. - bu olabilir.

Sistemlerinizi mümkün olduğunca esnek hale getirin!


1
Muhtemelen, ancak teoride başka bir DBMS'de (etki alanlarının bildirimini destekleyen) Money adlı bir etki alanı bildirebilirsiniz.
debater

Birisi şu anda bir SQL Server veritabanını Amazon Redshift'e dönüştürürken, bunun gerçek bir sorun olduğunu garanti edebilirim. Kullanmak için çok sağlam ticari nedenler olmadıkça, belirli bir veritabanı platformuna özel veri türlerinden kaçınmaya çalışın.
Nathan Griffiths

@Nathn Redshift'in PostgreSQL veya SQL Server ile karşılaştırıldığında zayıf tip sistemi verildi, örneğin datetip yok , her zaman bu tür sorunlarınız olacağını söyleyebilirim . "Veritabanı zaten daha iyi, daha standart uyumlu türler sağladığında ve kullanımdan kaldırılanlara karşı uyarı verdiğinde kullanımdan kaldırılan türleri kullanmayın" demelisiniz .
Panagiotis Kanavos

@PanagiotisKanavos - Para kullanımdan kaldırıldı
Martin Smith

@MartinSmith, 2017'de BTC gibi para değerlerini işleyemediğinden bunu görmek için şok verdi. Ya da pariteye doğru hareket etseler bile GBP ve EUR tutarları arasında ayrım yapın: P. Her neyse, Redshift'e geçmek çok acı
çekiyor

32

Sevdim MONEY! Bu değerden daha ucuz bir bayttır DECIMALve hesaplamalar daha hızlı gerçekleşir, çünkü (kapakların altında) toplama ve çıkarma işlemleri esasen tamsayı işlemleridir. @ SQLMenace'in - habersiz için büyük bir uyarı olan INTörneği, sonucun sıfır olacağı egers'e eşit olarak uygulanabilir . Ama bu integers- kullanmak için hiçbir neden var uygun .

Yani, mükemmel bir şekilde 'güvenli' ve MONEYuğraştığınız zaman MONEYkullanmak ve onu takip eden matematiksel kurallara göre kullanmak için uygundur ( INTeger ile aynı ).

SQL Server MONEY'ın bölünmesini ve çoğaltılmasını DECIMALs (veya FLOATs'ye) yükseltmesi daha iyi olurdu , ama bunu yapmayı seçmediler; ne de INTböldüklerinde egleri FLOATs'ye yükseltmeyi seçmediler .

MONEYhassas bir sorunu yoktur; Bu DECIMALhesaplamalar sırasında kullanılan daha büyük bir ara tür olsun sadece bu tür kullanmanın bir 'özellik' (ve aslında bu 'özellik' ne kadar uzandığından emin değilim).

Belirli bir soruyu cevaplamak için “zorlayıcı bir neden” mi? Peki, bir SUM(x)yerde mutlak maksimum performans istiyorsanız xya DECIMALda olabilir MONEY, o MONEYzaman bir kenarı olacaktır.

Ayrıca, daha küçük kuzen olduğunu unutmayın SMALLMONEY- sadece 4 bayt, ancak maksimumda 214,748.3647- para için oldukça küçüktür - ve genellikle iyi bir uyum değildir.

Etraftaki noktayı daha büyük ara türler kullanarak kanıtlamak için, DECIMALaracıyı bir değişkene açıkça atarsanız , aynı sorunla karşılaşırsınız:

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

Üretir 2950.0000(tamam, en azından kesilmiş DECIMALyerine en azından yuvarlak - MONEYtamsayı ile aynıdır.)


21
MONEYbir byte az daha büyük bir DECIMAL kesinlik 19 basamağa kadar sahip. Bununla birlikte, gerçek dünyadaki parasal hesaplamaların çoğu (9.99 M $ 'a kadar), DECIMAL(9, 2)sadece beş bayt gerektiren bir a sığabilir . Boyut kaydedebilir, yuvarlama hataları hakkında daha az endişe duyabilir ve kodunuzu daha taşınabilir hale getirebilirsiniz.

@JonofAllTrades doğru olsa da, sadece kuruş veya sent içeren bir tamsayı kullanarak tamsayı performansını geri alabilir ve ondalık noktasının konumunu kodlayan ve ondalık sayıları eklerken kontrol edilmesi gereken ekstra baytı kaydedebilirsiniz.
dsz

"Yani, mükemmel 'güvenli' ve uğraştığınız şey PARA olduğunda ve bunu takip matematiksel kurallara göre kullanmak PARA kullanmak için uygundur" -> Ancak, ayrıca bkz Anon'un cevabı: " ne yaptığını biliyorum ". İnsanların oluşturduğunuz sistemi nasıl sorgulayacağını asla tahmin edemezsiniz, en iyisi mümkün olduğunda yanlış kullanım olasılığından kaçınmak için. Depolamadaki ufak kazanç IMHO'ya değmez.
Nathan Griffiths

1
Bir Bitcoin değeri depolamayı deneyin. 8 ondalık vardır
Panagiotis Kanavos

14

Çok benzer bir sorunla karşılaştık ve şimdi üst düzey sunum dışında asla Money kullanmamaya + 1'im. Tarihsel nedenlerden ötürü her biri bir veya daha fazla Para alanı içeren birden fazla tablonuz (etkin bir satış fişi ve satış faturası) var ve her bir Verginin toplam tutarının ne kadarıyla alakalı olduğunu hesaplamak için orantılı bir hesaplama yapmamız gerekiyor fişi üzerine yazılır. Bizim hesaplama

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

Bu, bölünme kısmında ölçek hatalarına neden olan ve daha sonra yanlış bir KDV oranına çarparak gerçek bir dünya para / para hesaplaması ile sonuçlanır. Bu değerler daha sonra eklendiğinde, toplam fatura değerine eklenmeyen KDV oranlarının toplamı ile sonuçlanır. Parantez içindeki değerlerden biri bir ondalık sayı olsaydı (bunlardan birini böyle dökmek üzereyim) KDV oranı doğru olurdu.

Köşeli parantezler başlangıçta bu işe yaramadıysa, daha büyük değerler nedeniyle, daha yüksek bir ölçeği etkili bir şekilde simüle ediyordu. Köşeli parantezleri ekledik, çünkü ilk önce çarpımı gerçekleştiriyordu, bu da bazı nadir durumlarda hesaplama için kullanılabilir hassasiyeti üfledi, ancak şimdi bu çok daha yaygın bir hataya neden oldu.


8
Ancak bunu sadece cahil bir geliştirici KDV hesaplamaları ve paranın belgelenmiş hassasiyet sınırlamalarını göz ardı ettiği için yapar.
TomTom

1
@TomTom ancak bu veri türünü kötüye kullanma olasılığı hakkında konuştuğunuz nokta, onu hiç kullanmaktan kaçınmak için bir argüman.
Nathan Griffiths

@Nathan Hayır. Bunu asla kullanmamak için bir neden olarak verilen argümanın temelde yetersiz bir geliştirici olduğuna işaret ediyorum, bu yüzden argüman sahte.
TomTom

1
@TomTom ne yazık ki birçok beceriksiz geliştirici (yanı sıra birçok harika olanlar) var ve benim için, bu verilerin gelecekte nasıl sorgulanacağını garanti edemezsek ve hiç kimse burada açıklanan hataları yapamaz. , dikkatli olun ve ondalık tip kullanın. Bununla birlikte, paranın kullanım için en uygun tür olacağı bazı özel kullanım durumları olduğunu görebildiğim tüm bu cevapları okuduktan sonra, bunun için çok iyi bir kullanım durumu olmadıkça kullanmam. büyük miktarlarda finansal verinin toplu yüklenmesi ile SUM tarafından toplanmalıdır).
Nathan Griffiths

@TomTom sadece hassas sınırlamalar değil. Dahili temsil de sorunlara neden olabilir. Para, cahil geliştiricileri yakalamak için uygun bir türdür, geliştiricilerin kötüye kullandıkları harika bir tür değildir. KDV örneği, hesaplama kurallarına bakılmaksızın, cahil olmayan geliştiricileri, genel olana uyguladıklarında açıkça korkutmalıdır.
Gerard ONeill

12

Karşılık olarak diğer cevapların genel itişine işaret eder. Paranın Birçok Avantajına Bakın … Veri Türü! içinde İlişkisel Veri Yönetim Sistemi'ne SQLCAT Kılavuzu

Özellikle aşağıdakilere dikkat çekerim

Müşteri uygulamaları üzerinde çalışırken, para veri türü ile ilgili bazı ilginç performans sayıları bulduk. Örneğin, Analysis Services, SQL Server para veri türüyle eşleşmesi için para birimi veri türüne (çiftten) ayarlandığında, işlem hızında (satırlar / sn)% 13'lük bir iyileşme oldu. SSIS 2008 - dünya rekoru ETL performansında belirtildiği gibi, SQL Server Entegrasyon Hizmetleri'nde (SSIS) otuz dakikadan kısa bir sürede 1,18 TB yüklemek için daha hızlı performans elde etmek için, dört ondalık (9,2) sütununun TPC-H LINEITEM tablosundaki 5 bayt paraya (8 bayt) toplu ekleme hızını% 20 artırdı ... Performans artışının nedeni SQL Server'ın Tablo Veri Akışı (TDS) protokolü, verileri kompakt ikili biçimde ve SQL Server'ın dahili depolama biçimine mümkün olduğunca yakın aktarmak için anahtar tasarım ilkesine sahiptir. Ampirik olarak bu, Kernrate kullanılarak yapılan SSIS 2008 - dünya rekoru ETL performans testi sırasında gözlemlenmiştir; veri türü ondalıktan paraya çevrildiğinde protokol önemli ölçüde düştü. Bu, veri aktarımını mümkün olduğunca verimli hale getirir. Karmaşık bir veri türünün işlenmesi için sabit genişlikli bir türden daha fazla ayrıştırma ve CPU döngüsü gerekir.

Yani sorunun cevabı "duruma bağlıdır". Hassasiyeti korumak için belirli aritmetik işlemlere daha dikkatli olmanız gerekir, ancak performansla ilgili hususların bunu değerli kıldığını görebilirsiniz.


Bitcoin'i nasıl saklarsınız ?
Panagiotis Kanavos

@PanagiotisKanavos - Hiçbir fikrim yok. Asla bitcoin'e bakmadım ve neredeyse hiçbir şey bilmedim!
Martin Smith

6

MONEY'a karşı NUMERICAL'a farklı bir bakış açısı vermek istiyorum, büyük ölçüde kendi uzmanlığımı ve deneyimimi esas aldım ... Burada benim görüşüm MONEY, çünkü onunla uzun bir süre çalıştım ve gerçekten NUMERICAL'i çok kullanmadım .. .

PARA Pro:

  • Yerel Veri Türü . CPU kaydı (32 veya 64 bit) ile aynı yerel veri türü ( tamsayı ) kullanır , bu nedenle hesaplama gereksiz ek yüke ihtiyaç duymaz, bu yüzden daha küçük ve daha hızlıdır ... MONEY 8 bayt ve NUMERICAL (19, 4) gerektirir ) 9 bayta (% 12.5 daha büyük) ihtiyaç duyar ...

    PARA (para olarak) olması gerektiği sürece kullanıldığı sürece daha hızlıdır. Ne kadar hızlı? SUM1 milyon verideki basit testim, PARA'nın 275 ms ve NUMERIC 517 ms olduğunu gösteriyor ... Bu neredeyse iki kat daha hızlı ... Neden SUM testi? Bir sonraki Pro noktasına bakın

  • Para için en iyisi . PARA, örneğin muhasebe alanında para depolamak ve işlemler yapmak için en iyisidir. TOPLA işlemi yapıldıktan sonra tek bir rapor milyonlarca ekleme (SUM) ve birkaç çarpma gerçekleştirebilir. Çok büyük muhasebe uygulamaları için neredeyse iki kat daha hızlıdır ve son derece önemlidir ...
  • Düşük Para Hassasiyeti . Gerçek hayatta paranın çok kesin olması gerekmez. Yani, birçok insan yaklaşık 1 cent USD umurunda olabilir, ama 0.01 cent USD hakkında ne dersiniz? Aslında, ülkemde bankalar artık sentleri umursamıyor (ondalık virgülden sonraki rakam); ABD bankasını veya başka bir ülkeyi bilmiyorum ...

PARA Con:

  • Sınırlı Hassasiyet . MONEY'in yalnızca dört basamaklı (virgülden sonra) hassasiyeti vardır, bu nedenle bölme gibi işlemler yapmadan önce dönüştürülmelidir ... Ama sonra tekrar o moneykadar hassas olmak zorunda değildir ve sadece bir değil, para olarak kullanılması gerekir numara...

Ama ... Büyük, ama burada uygulamanız bile gerçek para ile ilgili, ancak muhasebe gibi birçok SUM işleminde kullanmayın. Bunun yerine çok sayıda bölme ve çarpma kullanırsanız, PARA kullanmamalısınız ...


1
Paranın ondalıktan daha hızlı olduğunu söyleyecekseniz, hangi rdbms, hangi donanımda, hangi işletim sisteminde çalıştığında, hangi spesifik veriyle ilgili konuştuğunuz hakkında belirli bilgileri söylemeniz gerekir. Ayrıca, eğer TAMAMEN doğru değilse, ben onunla herhangi bir finansal işlem yapmıyorum, çünkü vergi adam kötü sayılar geri almak oldukça memnun olacaktır. Örneğin ABD para birimi ile uğraşıyorsanız bininci senti önemsiyorsunuz. Para bunu yapmazsa, kullanılabilir değildir.
Haakon Løtveit

3
@ HaakonLøtveit tüm bu Q & A iş parçacığı SQL Server veri türü "para" hakkında, bu yüzden cevap bu belirtmek gerektiğini sanmıyorum. Paranın kullanımı bazı durumlarda ondalıktan daha hızlı olabilir (örn. Veri yükleme), daha fazla ayrıntı için Martin Smith'in cevabına bakın. Bu cevabın çoğuna katılıyorum, Parayı ondalıktan daha etkili bir seçim haline getirebilecek bazı kullanım durumları var, ancak kullanmak için çok zorlayıcı bir durum olmadıkça bundan kaçınılması gerektiğini düşünüyorum.
Nathan Griffiths

1
Bitcoin'in 8 ondalığı vardır. Bir moneysütunda bile saklayamazsınız
Panagiotis Kanavos

4

Önceki tüm gönderiler geçerli puanlar getiriyor, ancak bazıları soruyu tam olarak cevaplamıyor.

Soru şudur: Neden daha az kesin bir veri türü olduğunu ve karmaşık hesaplamalarda kullanılırsa hatalara neden olabileceğini bildiğimizde neden para tercih edilmeli?

Karmaşık hesaplamalar yapmayacağınız zaman para kullanırsınız ve bu hassasiyeti diğer ihtiyaçlarınız için takas edebilirsiniz.

Örneğin, bu hesaplamaları yapmak zorunda olmadığınızda ve geçerli para birimi metin dizelerinden veri almanız gerektiğinde. Bu otomatik dönüşüm yalnızca MONEY veri türüyle çalışır:

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

Kendi ithalat rutininizi yapabileceğinizi biliyorum. Ancak bazen dünya çapında belirli yerel ayar biçimleriyle bir içe aktarma rutini yeniden oluşturmak istemezsiniz.

Başka bir örnek, bu hesaplamaları yapmanız gerekmediğinde (sadece bir değer depolamanız gerekir) ve 1 bayt kaydetmeniz gerektiğinde (para 8 bayt alır ve ondalık (19,4) 9 bayt alır). Bazı uygulamalarda (hızlı CPU, büyük RAM, yavaş IO), sadece büyük miktarda veri okumak gibi, bu da daha hızlı olabilir.


2

Değer üzerinde çarpma / bölme yapmanız gerektiğinde para kullanmamalısınız. Para bir tamsayının depolandığı şekilde saklanırken, ondalık basamak ondalık basamak ve ondalık basamak olarak saklanır. Bu, paranın çoğu durumda doğruluğu düşüreceği anlamına gelirken, ondalık yalnızca orijinal ölçeğine dönüştürüldüğünde bunu yapar. Para sabittir, bu nedenle hesaplamalar sırasında ölçeği değişmez. Bununla birlikte, ondalık bir dize olarak yazdırıldığında (bir temel 2 dizede sabit bir konumun aksine) sabit nokta olduğundan, 4 ölçeğine kadar olan değerler tam olarak temsil edilir. Toplama ve çıkarma için para iyidir.

Ondalık bir taban 10'da dahili olarak temsil edilir ve bu nedenle ondalık noktanın konumu da taban 10 numarasına dayanır. Bu da onun kesirli kısmını parayla olduğu gibi tam olarak değerini temsil eder. Fark, ondalık ara değerlerin 38 basamağa kadar hassasiyeti koruyabilmesidir.

Kayan nokta sayısı ile, değer bir tamsayı gibi ikili olarak saklanır ve ondalık (veya ikili, ahem) noktasının konumu, sayıyı temsil eden bitlere göredir. İkili ondalık noktası olduğundan, temel 10 sayıları ondalık noktadan hemen sonra kesinlik kaybeder. 1/5 veya 0,2 tam olarak bu şekilde temsil edilemez. Ne para ne de ondalık sayı bu sınırlamadan etkilenmez.

Parayı ondalığa dönüştürmek, hesaplamaları yapmak ve daha sonra elde edilen değeri bir para alanına veya değişkene geri depolamak yeterince kolaydır.

POV'umdan, sayılara olan şeylerin çok fazla düşünmek zorunda kalmadan gerçekleşmesini istiyorum. Tüm hesaplamalar ondalık sayıya dönüştürülecekse, o zaman bana sadece ondalık sayı kullanmak istiyorum. Para alanını görüntüleme amacıyla saklardım.

Boyut-bilge Fikrimi değiştirmek için yeterli bir fark görmüyorum. Para 4 - 8 bayt alırken, ondalık sayı 5, 9, 13 ve 17 olabilir. 9 bayt, 8 baytlık paranın yapabileceği tüm aralığı kapsayabilir. Endeks yönünden (karşılaştırma ve arama karşılaştırılabilir olmalıdır).


Olumlu oy için teşekkürler. Buna bakıyorum ve söylemeye çalıştığım şeyi alırken, bunun çok kafa karıştırıcı olduğunu da görebiliyorum. Belki daha sonra ondalık örneklere göre biraz yeniden yazacağım.
Gerard ONeill

2

Doğruluk konusunda ondalık paranın kullanılması konusunda bir neden buldum.

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

Ondalık Sonuç> 1.000000

MoneyResult> 0.9999

FloatResult> 1

Sadece test edin ve kararınızı verin.


2
Biz duymak için (olduğunu, okuyun) çok çok gibi olur senin sonuca.
Peter Mortensen

@PeterMortensen Para ve Ondalık türleri arasında tamlık ve doğruluk elde etmek istiyorsam kararımın Ondalık olması gerektiğini düşünüyorum.
QMaster

1
Yanıtınızı yukarıdakilerin gerçek sonuçlarıyla güncellemeyi düşünün. Sonra sonucunuz hemen okuyan herkes için açık olacak :-)
Agreax

1
@Ageax Sonuç cevaba eklendi.
QMaster

1

Bu blog girişini gördüm: SQL Server'da Money vs. Decimal .

Temel olarak paranın hassas bir sorunu olduğunu söylüyor ...

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

set @m = 19.34
set @d = 19.34

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

İçin moneytipi, sen 19,30 yerine 19,34 alacak. Hesaplama için parayı 1000 parçaya bölen bir uygulama senaryosu olup olmadığından emin değilim, ancak bu örnek bazı sınırlamaları ortaya koyuyor.


15
Bu bir "sorun" değil, "spesifikasyonlara göre": « moneyve smallmoneyveri türleri, temsil ettikleri para birimlerinin on binde biri kadar doğrudur.» msdn.microsoft.com/en-us/library/ms179882.aspx'de söylendiği gibi "çöp" diyen herkes ne hakkında konuştuğunu bilmiyor.
Albireo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.