Функция MySQL Round () для десятичной записи в строке - PullRequest
0 голосов
/ 27 апреля 2018

MySQL версия 5.66.22

Когда я использую функцию ROUND для десятичных чисел, хранящихся в varchar, я вижу странное поведение для всех .5 чисел

Select round(0.5)
1

Select round('0.5')
0

Select round('26.5' + 0.00)
26

но

Select round(1.5)
2

Select round('1.5')
2

Select round(0.55, 1)
0.6

Select round('0.55', 1)
0.6

Я проверил функцию ROUND в Oracle DB (12c), она работает как положено

Select round('0.5') from dual 
1

Select round(0.5) from dual 
1

Кто-нибудь знает, как это объяснить?

Описанное поведение функции mysql round (), вызывающее проблему «округления» в приложении. Для решения проблемы я использую:

Select round (CAST('0.5' AS DECIMAL(10,2)))
1

Я понимаю, что хранение чисел в varchar - плохой дизайн, но это приложение было написано давно, и никто не хочет реорганизовать код сейчас

1 Ответ

0 голосов
/ 27 апреля 2018

Интересно. Поведение можно объяснить следующим образом:

1) MySQL преобразует строки в значения с плавающей запятой при использовании в числовом контексте ( ref ):

CREATE TABLE test AS (
    SELECT 0.5, '0.5' * 1 AS str_to_numeric
);

DESCRIBE test;

+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| 0.5            | decimal(2,1) | NO   |     | 0.0     |       |
| str_to_numeric | double       | NO   |     | 0       |       |
+----------------+--------------+------+-----+---------+-------+

2) Как описано в руководстве:

Поведение при округлении

Функция ROUND() округляется по-разному в зависимости от того, Аргумент является точным или приблизительным:

  • Для чисел с точным значением ROUND() использует правило «округления пополам»: A значение с дробной частью .5 или больше округляется до следующее целое число, если положительное, или до следующего целого, если отрицательное. (В другими словами, он округляется от нуля.) Значение с дробным часть меньше чем .5 округляется до следующего целого числа, если оно положительное или до следующего целого числа, если оно отрицательное.

  • Для чисел с приблизительными значениями результат зависит от библиотеки C. На во многих системах это означает, что ROUND() использует «округление до ближайшего четного» правило: значение с любой дробной частью округляется до ближайшего четного целое число.

Вот несколько тестов, иллюстрирующих окончательное поведение функции ROUND:

CREATE TABLE test(
   fix DECIMAL(10,2),
   arb DOUBLE
);

INSERT INTO test(fix, arb) VALUES
    (0.5, 0.5),
    (1.5, 1.5),
    (2.5, 2.5),
    (3.5, 3.5);

SELECT fix, ROUND(fix) fix_roundex, arb, ROUND(arb) arb_rounded
FROM test

+------+-------------+------+-------------+
| fix  | fix_roundex | arb  | arb_rounded |
+------+-------------+------+-------------+
| 0.50 |           1 |  0.5 |           0 |
| 1.50 |           2 |  1.5 |           2 |
| 2.50 |           3 |  2.5 |           2 |
| 3.50 |           4 |  3.5 |           4 |
+------+-------------+------+-------------+

Ваше решение, явное приведение числовых строк к DECIMAL, является правильным.

...