Проблема округления и усечения SQL Server - PullRequest
0 голосов
/ 07 сентября 2018

Итак, я столкнулся со странной проблемой в SQL Server с округлением.

Вот мой пример:

declare @amount float = 178.69999999

select
    @amount as [amount],
    round(@amount, 6) as [round],
    round(round(@amount, 6), 2, 1) as [trim_1],
    floor(round(@amount, 6) * power(10.0, 2)) / power(10.0, 2) as [trim_2]

И вот результат, который я получаю:

+--------------+-------+--------+--------+
|    amount    | round | trim_1 | trim_2 |
+--------------+-------+--------+--------+
| 178.69999999 | 178.7 | 178.69 | 178.7  |
+--------------+-------+--------+--------+

Общая идея здесь заключается в том, что я пытаюсь округлить до 6 десятичных знаков, а затем обрезать / пол / усечь до 2 десятичных знаков.Это означает, что я ожидаю результат 178.7, но я получаю результат 178.69 для trim_1 (trim_2 - альтернативный подход, предназначенный для получения того же результата).

Насколько я могу судить, я правильно использую функцию round, поскольку в документации SQL Server указано:

Синтаксис

ROUND ( numeric_expression , length [ ,function ] )  

функция

Тип операции, которую необходимо выполнить. функция должна быть tinyint , smallint или int .Когда функция опущена или имеет значение 0 (по умолчанию), numeric_expression округляется.Если указано значение, отличное от 0, numeric_expression усекается.

Так что я бы ожидал, что trim_1 будет соответствовать trim_2.

Вот кикер: если я передаю результат round как константу, а не как переменную, она работает как ожидалось:

select round(178.7, 2, 1) -- Yields 178.7

Я предполагаю, что SQL Server делает что-то странное с плавающей запятой, или яКак-то удалось что-то пропустить.Что бы это ни стоило, я использую SQL Server 2014, так что, возможно, это моя проблема.

Я бы хотел получить результат trim_1 с как можно меньшим количеством кода, чтобы мой конечный результат выгляделочиститель.

1 Ответ

0 голосов
/ 07 сентября 2018

Используйте decimal вместо float.

Взято из Float и Real (Transact-SQL)

Данные с плавающей запятой являются приблизительными;следовательно, не все значения в диапазоне типов данных могут быть представлены точно.

Замена float на decimal в вашем коде дает желаемый результат:

declare @amount decimal(18, 10) = 178.69999999

select
    @amount as [amount],
    round(@amount, 6) as [round],
    round(round(@amount, 6), 2, 1) as [trim_1],
    floor(round(@amount, 6) * power(10.0, 2)) / power(10.0, 2) as [trim_2]

Результаты:

╔════════════════╦════════════════╦════════════════╦════════════╗
║     amount     ║     round      ║     trim_1     ║   trim_2   ║
╠════════════════╬════════════════╬════════════════╬════════════╣
║ 178.6999999900 ║ 178.7000000000 ║ 178.7000000000 ║ 178.700000 ║
╚════════════════╩════════════════╩════════════════╩════════════╝
...