SQL Серверный десятичный расчет и значение по умолчанию - PullRequest
0 голосов
/ 17 июня 2020

Кто-нибудь может объяснить следующие результаты. Я читал о десятичном типе SQL, а также о точности и масштабах при умножении и делении, но я до сих пор не могу этого понять:

select cast(7 as decimal(25,13))*cast(15 as decimal(25,13)) = 105.0000000000000

select cast(15 as decimal(25,13))/cast(11 as decimal(25,13)) = 1.3636363636363

select cast(7 as decimal(25,13))*cast(15 as decimal(25,13))/cast(11 as decimal(25,13)) = 9.545454

select cast(cast(7 as decimal(25,13))*cast(15 as decimal(25,13)) as decimal(25,13))/cast(11 as decimal(25,13)) = 9.5454545454545

Итак, умножение и деление дают 13 десятичных знаков, но когда в цепочке они внезапно дают 6 десятичных знаков. Только когда умножение сначала приводится как десятичное (25,13) и только затем делится, оно снова дает 13 десятичных знаков. Приводит ли SQL сервер умножение к десятичному виду по умолчанию (38,0), а затем делит его на десятичное (25,13)?

Я работаю над расчетами bom для очень недорогих продуктов, и Мне нужны все десятичные дроби, которые я могу получить. Нужно ли мне выполнять это приведение на каждом шаге, или я могу каким-то образом установить значение по умолчанию для одного запроса, чтобы использовать это десятичное число (25,13) для всех десятичных знаков, если не указано иное?

Ответы [ 2 ]

1 голос
/ 17 июня 2020

Ниже приведены соответствующие выдержки из документации по точности, масштабу и длине для контекста поведения десятичного умножения и деления.

+--------------------------------------+-------------------------------------+---------------------+
|              Operation               |          Result precision           |   Result scale *    |
+--------------------------------------+-------------------------------------+---------------------+
| e1 * e2                              | p1 + p2 + 1                         | s1 + s2             |
| e1 / e2                              | p1 - s1 + s2 + max(6, s1 + p2 + 1)  | max(6, s1 + p2 + 1) |
+--------------------------------------+-------------------------------------+---------------------+

* The result precision and scale have an absolute maximum of 38. When a result precision is greater than 38, it's reduced to 38, and the corresponding scale is reduced to try to prevent truncating the integral part of a result. In some cases such as multiplication or division, scale factor won't be reduced, to maintain decimal precision, although the overflow error can be raised.

In multiplication and division operations, we need precision - scale places to store the integral part of the result. The scale might be reduced using the following rules:

1. The resulting scale is reduced to min(scale, 38 - (precision-scale)) if the integral part is less than 32, because it can't be greater than 38 - (precision-scale). Result might be rounded in this case.

2. The scale won't be changed if it's less than 6 and if the integral part is greater than 32. In this case, overflow error might be raised if it can't fit into decimal(38, scale)

3. The scale will be set to 6 if it's greater than 6 and if the integral part is greater than 32. In this case, both integral part and scale would be reduced and resulting type is decimal(38,6). Result might be rounded to 6 decimal places or the overflow error will be thrown if the integral part can't fit into 32 digits.

Пункт 3 относится к третьему запросу в вашем вопрос, который можно наблюдать с помощью sp_describe_first_result_set:

EXEC sp_describe_first_result_set N'
select cast(7 as decimal(25,13))*cast(15 as decimal(25,13))/cast(11 as decimal(25,13)) --= 9.545454
';

system_type_name из приведенного выше запроса показывает decimal(38,6). Поскольку шкала результата выражения, равная 6, недостаточна для ваших нужд, явное преобразование CAST выражения умножения в десятичный тип с более низкой точностью (как вы это делали в последнем запросе в вашем вопросе) обеспечит больший масштаб для результата тип, но с повышенным риском переполнения.

Явное выражение CAST - decimal(25, 13) приводит к типу результата decimal(38, 13):

EXEC sp_describe_first_result_set N'
select cast(
       cast(7 as decimal(25,13))*cast(15 as decimal(25,13)) as decimal(25,13))/cast(11 as decimal(25,13)) --= 9.5454545454545
';
0 голосов
/ 17 июня 2020

Я пытаюсь произвести умножение, а затем преобразовать в десятичное

select cast(7*15 as decimal(25,13))/cast(11 as decimal(25,13))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...