Интересно. Поведение можно объяснить следующим образом:
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
, является правильным.