Умножение и деление чисел типа NUMERICИсточник: SQL Exercises
Может быть вам покажутся удивительными результаты следующих арифметических операций: declare @num1 numeric(38,10) Дает: .0000010000 Почему? Ну, BOL (смотри Precision, Scale и Length) определяет следующие правила для арифметических операций c числами типа NUMERIC:
В нашем случае точность и масштаб умножения вычисляется так: Точность = P1 + P2 + 1 = 38 + 38 + 1 = 77 Соответственно, результатом должно быть число типа numeric(77, 20), что не допускается. Вот где нам понадобится сноска: * Точность и масштаб результата имеет абсолютный максимум 38. Если точность результата превышает 38, соответствующий масштаб уменьшается, чтобы предотвратить усечение целой части результата. BOL в настоящий момент не вдается в подробности того, как выполняется усечение. Поскольку точность превышает 38, мы постараемся избежать усечения целой части значения уменьшением масштаба (вместо этого усекая дробную часть значения). Каким количеством масштаба пожертвовать? Здесь нет правильного ответа. Если оставить слишком много, то будет потерян результат умножения больших чисел. Если оставить слишком мало, умножение малых чисел станет проблемой. В SQL Server 2005 RTM (и предыдущих версиях) мы решили оставить минимальный масштаб - 6 как для умножения, так и деления. Поэтому наше numeric(77,20) усекалось до numeric(38,6), а затем приводилось к numeric(38,10). Однако это было сделано слишком поздно, и некоторые данные были потеряны. Это объясняет результат, который вы можете увидеть выше. Поэтому важно стараться задавать по минимуму точность и масштаб операндов в умножении и делении. В этом случае: declare @num1 numeric(18,10) тип результата должен быть numeric(37,20). Поскольку точность и масштаб типа не превышает наших текущих пределов, неявное усечение не проводится. Затем мы приводим результат к numeric(38,10), что не вызывает потери данных в нашем случае. Если вы не можете точно типизировать значения, участвующие в умножении и делении, например, если они являются параметрами процедуры, которая вызывается с большим разбросом значений, возможно, стоит обратить внимание на приближенные числовые типы (float, real) или определить свой собственный "высокоемкий" пользовательский точный числовой тип данных, используя CLR. Я надеюсь, что это было полезно для вас. Mat (оригинал: Multiplication and Division with Numerics) |