mysql select sum(row1)

4 отговора 126 прегледа
#1

mysql select sum(row1)

Имам един ред в таблицата.Полетата са тип float(4,2)
select payed,total from tbl1
| payed | total |
+-------+--------+
| 0 | 206.15 |
+-------+--------+
До тук ОК; сега обаче :
select sum(payed),sum(total) from tbl1;
+------------+-----------------+
| sum(payed) | sum(total) |
+------------+-----------------+
| 0 | 206.14999389648 |
+------------+-----------------+

Много странна стойност за второ поле ?! Защо се получава така ?Не че е проблем но ми е интересно.
select sum(payed),round(sum(total),2) as summ from tbl1;
и всичко се оправя но не е там въпроса.

Отговор
в отговор на newbie #2

Re: mysql select sum(row1)

Обикновено SUM каства до флоат. Вероятно така е и в MySQL.

Отговор
в отговор на newbie #3

Re: mysql select sum(row1)

Защото всички операции с тип float се извършват с "аритметика с плаваща запетая" т.е. винаги са приблизителни. Всъщност как точно се съхранява в таблицата числото 206.15 зависи от много неща но най-общо изобщо не е задължително да е 206.15 а по вероятно е нещо в стил 206.14999389648 което и получаваш като резултат от SUM()

Също както 3.0 вможе да се окаже 2.99999999999999945356265 например.

Тъй като полето ти е дефинирано като float(4,2) MySQL "знае", че трябва да закръгли до втория десетичен знак при

select payed,total from tbl1;

При
select sum(payed),sum(total) from tbl1;

обаче си няма идея каква точност ти трябва.

В случая трябва да използаш някоя от функциите за закръгляване като примерно

select round(sum(total), 2) from tbl1;


Като цяло обаче се сблъскваш с добре известния факт, че аритметиката с плаваща запетая е НЕТОЧНА.

Например правилото (a / b) * b = a при аритметика с плаваща запетая почти никога не е вярно!

както и да речем sum(a * b) = sum(a) * sum(b)

Тъй, че не се изненадвай от ефекти като:

mysql> select a, b, round(a, 10), round(b, 10) from newbie;

+------+--------+--------------+----------------+
| a | b | round(a, 10) | round(b, 10) |
+------+--------+--------------+----------------+
| 0.10 | 206.15 | 0.1000000015 | 206.1499938965 |
+------+--------+--------------+----------------+

съответно:

mysql> select @x:=round(sum(a+b), 20), @y:=round(sum(a), 20) + round(sum(b), 20)from newbie;
+--------------------------+-------------------------------------------+
| @x:=round(sum(a+b), 20) | @y:=round(sum(a), 20) + round(sum(b), 20) |
+--------------------------+-------------------------------------------+
| 206.24999389797446269768 | 206.24999389797451954109 |
+--------------------------+-------------------------------------------+

mysql> select @x = @y, @x - @y;
+---------+----------------------+
| @x = @y | @x - @y |
+---------+----------------------+
| 0 | -5.6843418860808e-14 |
+---------+----------------------+
0 => false


и така нататък.

Както и документацията на MySQL препоръчва ако ти трябва точно изчисление трябва или да използваш тип DECIMAL (който се съхранява като стринг с фиксирана запетая) или да преобразиваш всичко до INTEGER примерно да разбиеш на две колонки или пак да умножаваш по 100 и да пазиш всичко като "стотинки"

Всъщност това отговаря на спецификацията на SQL-99

salle.online.bg/sig
Отговор
в отговор на salle #4

Re: mysql select sum(row1)

Само една забележка:

>>>
...почти никога не е вярно! ....
както и да речем sum(a * b) = sum(a) * sum(b)
...
<<<

Израза:
sum(a * b) = sum(a) * sum(b)
не е верен и в математиката.
Предполагам, че е написан по инерция.

Отговор
в отговор на Eмил #5

Re: s/*/+/g

Или с други думи * да се чете +

т.е. sum(a + b) != sum(a) + sum(b)



Абе човек като е уморен трябва да спи а не да пише глупости.

Благодаря за забележката.

salle.online.bg/sig
Отговор