سؤال

أدى تصحيح بعض أكواد SQL المتعلقة بالتمويل إلى العثور على مشكلة غريبة تتعلق بدقة الرياضيات الرقمية (24,8).

بتشغيل الاستعلام التالي على MSSQL الخاص بك، ستحصل على نتيجة تعبير A + B * C لتكون 0.123457

حدد A ، B ، C ، A + B * C من (SELECT CAST (0.12345678 AS NUMERIC (24،8)) كـ A ، الممثلون (0 كـ NUMERIC (24،8)) كـ B ، CAST (500 AS NUMERIC (24 ، 8)) كما ج) ر

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

وأخيرا لديك حل.ولكن لا يزال لدي سؤال - لماذا يتصرف MSSQL بهذه الطريقة وما نوع التحويلات التي حدثت بالفعل في العينة الخاصة بي؟

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

المحلول

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

منذ أن كثرت NUMERIC(24,8) و NUMERIC(24,8), ، وسيقوم SQL Server بالتحقق فقط من النوع وليس المحتوى، ومن المحتمل أن يحاول حفظ 16 رقمًا غير عشري محتمل (24 - 8) عندما لا يتمكن من حفظ جميع أرقام الدقة البالغ عددها 48 رقمًا (الحد الأقصى هو 38).اجمع اثنين منهم، وستحصل على 32 رقمًا غير عشري، مما يترك لك 6 أرقام عشرية فقط (38 - 32).

وبالتالي الاستعلام الأصلي

SELECT A, B, C, A + B * C
FROM ( SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A,
  CAST(0 AS NUMERIC(24,8)) AS B,
  CAST(500 AS NUMERIC(24,8)) AS C ) T

يقلل ل

SELECT A, B, C, A + D
FROM ( SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A,
  CAST(0 AS NUMERIC(24,8)) AS B,
  CAST(500 AS NUMERIC(24,8)) AS C,
  CAST(0 AS NUMERIC(38,6)) AS D ) T

مرة أخرى بين NUMERIC(24,8) و NUMERIC(38,6), ، سيحاول SQL Server حفظ الأرقام غير العشرية المحتملة البالغ عددها 32 رقمًا A + D يقلل ل

SELECT CAST(0.12345678 AS NUMERIC(38,6))

الذي يعطيك 0.123457 بعد التقريب.

نصائح أخرى

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

في هذه الحالة يمكن أن تبدو الوظيفة كما يلي:

create function dbo.myMath(@a as numeric(24,8), @b as numeric(24,8), @c as numeric(24,8))
returns  numeric(24,8)
as
begin 
    declare @d as numeric(24,8)
    set @d = @b* @c
    return @a + @d
end

بالرغم مما ورد فيه الدقة والقياس والطول (Transact-SQL).أعتقد أنه يطبق أيضًا الحد الأدنى من "المقياس" (عدد المنازل العشرية) وهو 6 على النوع NUMERIC الناتج للضرب كما هو الحال في القسمة وما إلى ذلك.

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