سؤال

أنا أستخدم عمودًا عشريًا لتخزين قيم الأموال على قاعدة بيانات ، واليوم كنت أتساءل عن الدقة والحجم الذي يجب استخدامه.

نظرًا لأن الأعمدة المفترضة ذات العرض الثابت أكثر كفاءة ، فقد كنت أفكر أن الشيء نفسه قد يكون صحيحًا بالنسبة للأعمدة العشرية. فعلا؟

وما الدقة والحجم الذي يجب أن أستخدمه؟ كنت أفكر في الدقة 24/8. هل هذا مبالغة ، لا يكفي أم موافق؟


هذا ما قررت القيام به:

  • قم بتخزين معدلات التحويل (عند الاقتضاء) في جدول المعاملات نفسه ، كتعويم
  • تخزين العملة في جدول الحساب
  • سيكون مبلغ المعاملة أ DECIMAL(19,4)
  • سيتم التعامل مع جميع العمليات الحسابية التي تستخدم معدل التحويل من خلال طلبي ، لذا أستمر في السيطرة على مشكلات التقريب

لا أعتقد أن تعويم معدل التحويل يمثل مشكلة ، لأنها في الغالب للرجوع إليها ، وسأقوم بإلقاءها على أي حال.

شكرا لكم جميعا على مدخلاتك القيمة.

هل كانت مفيدة؟

المحلول

إذا كنت تبحث عن حجم واحد يناسب الجميع ، أقترح DECIMAL(19, 4) هو خيار شائع (يحمل Google السريع هذا). أعتقد أن هذا ينشأ من نوع بيانات العملة VBA/Access/Jet القديمة ، كونه أول نوع عشري النقطة الثابتة في اللغة ؛ Decimal جاء فقط في نمط "الإصدار 1.0" (أي لم يتم تنفيذه بالكامل) في VB6/VBA6/JET 4.0.

قاعدة الإبهام ل تخزين من القيم العشرية النقطة الثابتة هي تخزين مكان عشري واحد على الأقل مما تحتاجه بالفعل للسماح بالتقريب. أحد أسباب تعيين القديم Currency اكتب في الواجهة الأمامية إلى DECIMAL(19, 4) اكتب في النهاية الخلفية كان ذلك Currency عرض المصرفيين حول الطبيعة ، في حين DECIMAL(p, s) تقريب عن طريق الاقتطاع.

مكان عشري إضافي في التخزين ل DECIMAL يسمح بتنفيذ خوارزمية التقريب المخصصة بدلاً من أخذ التخلف عن السداد للبائع (والتقريب المصرفيين مقلقون ، على أقل تقدير ، لمصمم يتوقع أن تنتهي جميع القيم في 0.5 من الصفر).

نعم، DECIMAL(24, 8) يبدو مثل المبالغة بالنسبة لي. ونقلت معظم العملات إلى أربعة أو خمسة أماكن عشرية. أنا أعرف المواقف التي يكون فيها مقياس عشري 8 (أو أكثر) هو مطلوب ولكن هذا هو المكان الذي تم فيه تخفيض المبلغ النقدي "الطبيعي" (على سبيل المثال أربعة أماكن عشرية) ، مما يعني ضمنا الدقة العشرية وفقًا لذلك (ضع في اعتبارك أيضًا نوع النقطة العائمة في مثل هذه الظروف). ولا أحد لديه الكثير من المال في الوقت الحاضر ليتطلب دقة عشرية 24 :)

ومع ذلك ، بدلاً من نهج واحد يناسب الجميع ، قد تكون بعض الأبحاث في حالة جيدة. اسأل مصممك أو خبير المجال عن قواعد المحاسبة التي قد تكون قابلة للتطبيق: GAAP ، الاتحاد الأوروبي ، إلخ DECIMAL(p, 6) للتخزين. يبدو أن المحاسبين يفضلون أربعة أماكن عشرية.


ملاحظة تجنب SQL Server MONEY نوع البيانات لأنه لديه مشاكل خطيرة مع الدقة عند التقريب ، من بين اعتبارات أخرى مثل قابلية النقل وما إلى ذلك ، انظر مدونة آرون برتراند.


اختارت Microsoft ومصممي اللغة التقريب Banker لأن مصممي الأجهزة اختاروها [الاقتباس؟]. إنه مكرس في معايير معهد مهندسي الكهرباء والإلكترونيات (IEEE) ، على سبيل المثال. واختار مصممو الأجهزة ذلك لأن علماء الرياضيات يفضلون ذلك. نرى ويكيبيديا; ؛ لإعادة صياغة: طبعة 1906 من احتمال ونظرية الأخطاء التي تسمى "قاعدة الكمبيوتر" ("أجهزة الكمبيوتر" تعني البشر الذين يقومون بالحسابات).

نصائح أخرى

قمنا مؤخرًا بتنفيذ نظام يحتاج إلى التعامل مع القيم في عملات متعددة والتحويل بينها ، واكتشفوا بعض الأشياء بالطريقة الصعبة.

لا تستخدم أرقام النقاط العائمة مقابل المال

يقدم النقطة العائمة الحساب عدم الدقة التي قد لا يتم ملاحظتها حتى يثبّت شيئًا ما. يجب تخزين جميع القيم على أنها إما أعداد صحيحة أو أنواع غير مقلية ثابتة ، وإذا اخترت استخدام نوع ثابت غير طبيعي ، فتأكد من أنك تفهم بالضبط ما يفعله هذا النوع تحت الغطاء (أي ، هل يستخدم داخليًا عددًا صحيحًا أو نقطة عائمة يكتب).

عندما تحتاج إلى إجراء حسابات أو تحويلات:

  1. تحويل القيم إلى نقطة عائمة
  2. حساب قيمة جديدة
  3. حول الرقم وتحويله إلى عدد صحيح

عند تحويل رقم النقطة العائمة مرة أخرى إلى عدد صحيح في الخطوة 3 ، لا تقم بإلقاءها فقط - استخدم وظيفة الرياضيات لتدويرها أولاً. هذا عادة round, ، على الرغم من أنه في الحالات الخاصة يمكن أن يكون floor أو ceil. تعرف الفرق واختر بعناية.

قم بتخزين نوع الرقم إلى جانب القيمة

قد لا يكون هذا مهمًا بالنسبة لك إذا كنت تتعامل فقط مع عملة واحدة ، ولكن كان من المهم بالنسبة لنا في التعامل مع عملات متعددة. استخدمنا رمز 3-character للعملة ، مثل الدولار ، GBP ، JPY ، EUR ، إلخ.

اعتمادًا على الموقف ، قد يكون من المفيد أيضًا تخزين:

  • ما إذا كان الرقم قبل الضريبة أو بعده (وما هو معدل الضريبة)
  • ما إذا كان الرقم هو نتيجة للتحويل (وما تم تحويله منه)

تعرف على حدود الدقة للأرقام التي تتعامل معها

للقيم الحقيقية ، تريد أن تكون دقيقًا مثل أصغر وحدة العملة. هذا يعني أنه ليس لديك قيم أصغر من المائة ، أو بنس ، أو ين ، أو فين ، وما إلى ذلك ، لا تخزن القيم بدقة أعلى من ذلك دون سبب.

داخليًا ، يمكنك اختيار التعامل مع القيم الأصغر ، وفي هذه الحالة ، هذه أ نوع مختلف من قيمة العملة. تأكد من أن الكود الخاص بك يعرف أي منهما ولا يتم خلطه. تجنب استخدام قيم النقطة العائمة حتى هنا.


إضافة كل هذه القواعد معًا ، قررنا القواعد التالية. في رمز التشغيل ، يتم تخزين العملات باستخدام عدد صحيح لأصغر وحدة.

class Currency {
   String code;       //  eg "USD"
   int value;         //  eg 2500
   boolean converted;
}

class Price {
   Currency grossValue;
   Currency netValue;
   Tax taxRate;
}

في قاعدة البيانات ، يتم تخزين القيم كسلسلة في التنسيق التالي:

USD:2500

التي تخزن قيمة 25.00 دولار. تمكنا من القيام بذلك فقط لأن الكود الذي يتعامل مع العملات لا يحتاج إلى أن يكون داخل طبقة قاعدة البيانات نفسها ، بحيث يمكن تحويل جميع القيم إلى ذاكرة أولاً. لا شك أن المواقف الأخرى ستضفي على حلول أخرى.


وفي حال لم أوضح ذلك في وقت سابق ، لا تستخدم تعويم!

عند التعامل مع الأموال في MySQL ، استخدم العشرية (13،2) إذا كنت تعرف دقة قيم أموالك أو استخدم مزدوجة إذا كنت تريد فقط قيمة تقريبية سريعة للغاية. لذلك إذا احتاج طلبك إلى التعامل مع قيم المال تصل إلى تريليون دولار (أو يورو أو جنيه) ، فيجب أن يعمل هذا:

DECIMAL(13, 2)

أو ، إذا كنت بحاجة إلى الامتثال مبادئ المحاسبة المقبولة عموما ثم استخدام:

DECIMAL(13, 4)

ستمنحك 4 أماكن عشرية الدقة لتخزين أصغر الوحدات الفرعية للعملة في العالم. يمكنك أن تنزل أكثر إذا كنت بحاجة إلى دقة micropayment (nanopayment؟!).

أنا أيضا أفضل DECIMAL لأنواع الأموال الخاصة بـ DBMS ، فأنت أكثر أمانًا لإبقاء هذا النوع من المنطق في تطبيق IMO. هناك نهج آخر على نفس المنوال هو ببساطة استخدام عدد صحيح [طويل] ، مع التنسيق في ¤unit.subunit لقابلية القراءة البشرية (¤ = رمز العملة) التي تتم على مستوى التطبيق.

يحتوي نوع بيانات الأموال على SQL Server على أربعة أرقام بعد العشرية.

من كتب SQL Server 2000 عبر الإنترنت:

تمثل البيانات النقدية مبالغ إيجابية أو سلبية من المال. في Microsoft® SQL Server ™ 2000 ، يتم تخزين البيانات النقدية باستخدام أنواع بيانات الأموال وأنواع البيانات الصغيرة. يمكن تخزين البيانات النقدية لدقة أربعة أماكن عشرية. استخدم نوع بيانات الأموال لتخزين القيم في النطاق من -922،337،203،685،477.5808 إلى +922،337،203،685،477.5807 (يتطلب 8 بايت لتخزين قيمة). استخدم نوع بيانات SmallMoney لتخزين القيم في النطاق من -214،748.3648 إلى 214،748.3647 (يتطلب 4 بايت لتخزين قيمة). إذا كان هناك حاجة إلى عدد أكبر من الأماكن العشرية ، فاستخدم نوع البيانات العشرية بدلاً من ذلك.

Sometimes you will need to go to less than a cent and there are international currencies that use very large demoniations. For example, you might charge your customers 0.088 cents per transaction. In my Oracle database the columns are defined as NUMBER(20,4)

If you're going to be doing any sort of arithmetic operations in the DB (multiplying out billing rates and so on), you'll probably want a lot more precision than people here are suggesting, for the same reasons that you'd never want to use anything less than a double-precision floating point value in application code.

If you were using IBM Informix Dynamic Server, you would have a MONEY type which is a minor variant on the DECIMAL or NUMERIC type. It is always a fixed-point type (whereas DECIMAL can be a floating point type). You can specify a scale from 1 to 32, and a precision from 0 to 32 (defaulting to a scale of 16 and a precision of 2). So, depending on what you need to store, you might use DECIMAL(16,2) - still big enough to hold the US Federal Deficit, to the nearest cent - or you might use a smaller range, or more decimal places.

I would think that for a large part your or your client's requirements should dictate what precision and scale to use. For example, for the e-commerce website I am working on that deals with money in GBP only, I have been required to keep it to Decimal( 6, 2 ).

A late answer here, but I've used

DECIMAL(13,2)

which I'm right in thinking should allow upto 99,999,999,999.99.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top