BiTel

Форум BiTel
bgbilling.ru     docs.bitel.ru     wiki.bitel.ru     dbinfo.bitel.ru     bgcrm.ru     billing.bitel.ru     bitel.ru    
Текущее время: 21 июн 2025, 23:42

Часовой пояс: UTC + 5 часов [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 28 ] 
Автор Сообщение
СообщениеДобавлено: 05 июн 2009, 13:42 
Имеются две таблицы:
contract_balance и её копия недельной давности contract_balance_bckup.

на текущий момент:
Код:
select sum(cb.summa1+cb.summa2-cb.summa3-cb.summa4)
from contract_balance cb
left join contract c on c.id=cb.cid
where c.gr&(1<<0)>0
and cb.mm=04 and cb.yy=2009


даёт:

2300471.22

и

Код:
select sum(cb.summa1+cb.summa2-cb.summa3-cb.summa4)
from contract_balance_bckup cb
left join contract c on c.id=cb.cid
where c.gr&(1<<0)>0
and cb.mm=04 and cb.yy=2009


даёт:

2300371.22

Как видно, за неделю появилась разница в 100 рублей.

Сравниваю кол-во записей в таблицах при (mm=04 and yy=2009) -- одинаковое.

Сравниваю построчно суммы:

Код:
select (cb.summa1+cb.summa2-cb.summa3-cb.summa4) as cb, (cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4) as cbb,
(cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4) as diff
from contract_balance cb
left join contract_balance_bckup cb1 on cb1.cid=cb.cid
left join contract c on c.id=cb.cid
where cb.yy=2009 and cb.mm=04 and cb1.yy=2009 and cb1.mm=04
and c.gr&(1<<0)>0


Результат:

Код:
 cb         cbb        diff   
 ---------  ---------  -------
 0          0          0       
 -1000      -1000      0       
 -2.33      -2.33      -0     
 -295.32    -295.32    -0     
 -1471.81   -1471.81   0       
 34.15      34.15      -0     
 -112.79    -112.79    0       
 320.18     320.18     0     


Дальше интереснее. Если в крайний запрос добавить условие:

Код:
and c.gr&(1<<0)>0
and (cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)>0.001


и менять число в условии от 0.00001 до 0.1, то кол-во результатов, соотв. этому условию уменьшается от ~300 до 0.


вопрос 1. В связи с каким событием изменилась сумма? напомню, что это происходило не постепенно от 10 рублей до 100, например, а в один день примерно через неделю после сохранения копии таблицы.

вопрос 2. Почему вообще возникает такая ситуация, если столбцы сумм в тблицах имеют тип decimal(10,2)?

(Бухгалтерия не верит в мистику, и потихоньку сооружает для меня эшафот)

Спасибо.


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 05 июн 2009, 14:08 
Не в сети
Разработчик

Зарегистрирован: 07 апр 2007, 23:51
Сообщения: 4494
Откуда: Уфа, Россия
Карма: 187
попробуйте прочечать базу

такое случается когда повреждены индексы, в запросах в которых участвует индекс выдается одни результаты, а в которых не участвует - другие...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 05 июн 2009, 14:10 
не понял, что надо сделать?


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 05 июн 2009, 14:42 
mysqlchek? сделал. ничего не изменилось


И причём здесь индексы, если я построчно сравниваю таблицы?
берем сумму из одной таблицы и сумму из другой таблицы, вычитаем одну из другой и видим, что разница не равна нулю и отличается от нуля на тысячные или десятитысячные доли единицы, в то время как значения сумм должны быть десятичными числами с двумя знаками после запятой.


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 05 июн 2009, 18:12 
Не в сети
Разработчик

Зарегистрирован: 07 апр 2007, 23:51
Сообщения: 4494
Откуда: Уфа, Россия
Карма: 187
ау вас группа у договора не могла поменять? кол-во записей одинаково?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 06 июн 2009, 09:53 
Кол-во записей одинаково, об этом я писал выше. Проверил первым делом, конечно. Но, я всё-таки ещё раз повторю, расхождение по все таблице - это следствие вот этого:

Код:
select if((cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)>0.00001,"YES","NO")
from contract_balance cb
left join contract_balance_bckup cb1 on cb1.cid=cb.cid
where cb.yy=2009 and cb.mm=04 and cb1.yy=2009 and cb1.mm=04
and cb1.cid=902


результат: YES

А откуда оно берётся, если в обеих таблицах тип всех слагаемых decimal(10,2) и они соответственно равны?


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 07 июн 2009, 04:41 
Не в сети

Зарегистрирован: 07 май 2008, 13:34
Сообщения: 594
Откуда: Москва
Карма: 27
извиняюсь за возможную глупость, но кто мешает таки сравнить таблицы целиком за апрель и найти те строки где данные не идентичны ?
если разница в 1-2 копейки на куче договоров, то это одно, а если 100 рублей разницы на одном договоре то как бы...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 07 июн 2009, 13:28 
Jimson писал(а):
извиняюсь за возможную глупость, но кто мешает таки сравнить таблицы целиком за апрель и найти те строки где данные не идентичны ?
если разница в 1-2 копейки на куче договоров, то это одно, а если 100 рублей разницы на одном договоре то как бы...



Вы не внимательно читали мой первый пост.


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 07 июн 2009, 18:14 
Не в сети

Зарегистрирован: 07 май 2008, 13:34
Сообщения: 594
Откуда: Москва
Карма: 27
читал, я спрашиваю почему нельзя сравнить "select *", чудес то не бывает, ну или сделать select с условиями на неравенство и увидить воочию как у тебя не будут равны два числа decimal(10,2)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 07 июн 2009, 22:45 
1) Третий sql-запрос в первом посте -- построчное сравнение.
2) Последний sql-запрос, который я приводил -- это то, о чём вы говорите для одного конкретного договора (cid указан явно).
Или я что-то не понимаю?


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 07 июн 2009, 23:06 
Не в сети

Зарегистрирован: 07 май 2008, 13:34
Сообщения: 594
Откуда: Москва
Карма: 27
наверно я чего то не понимаю...
я вижу несхождение по двум агрегирующим выборкам, бог с ними
я вижу выборку где вычисляется разность и результат который дает нули в этой разности
а строки где разность будет не равна нулю есть ?
не будет ли проще сделать выборку с условием на <> что бы увидить сколько будет таких строк и будут ли они вообще


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 00:27 
таких строк будет около тысячи. но сравниваемые значения визуально (в формате decimal(10,2)) будут равны, понимаете?
Т.е., например:
select cbb.summa, cb.summa
from cbb, cb
where ...
and cb.summa!=cbb.summa

даст около тысячи вот таких строк:

122.10 122.10

Если попросить показать строки, в которых разница мжду суммами будет больше 1 копейки - таких строк будет 0.
Если попросить показать строки, в которых разница между суммами будет больше 0.001 копейки - то таких строк уже будет пара сотен. Понимаете?


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 10:18 
Не в сети

Зарегистрирован: 07 май 2008, 13:34
Сообщения: 594
Откуда: Москва
Карма: 27
Понимаю. Виновата mysql. Искать схожие проблемы с decimal через гугл пробовали ?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 12:03 
Не в сети
Разработчик

Зарегистрирован: 07 апр 2007, 23:51
Сообщения: 4494
Откуда: Уфа, Россия
Карма: 187
храняться значения в decimal(10,2) но для арифметических операция приводяться к float отсюда и разница

попробуйте исходящий остаток умножить на 100 и отбросить дробную часть а потом уже просумировать


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 12:24 
Не в сети

Зарегистрирован: 07 май 2008, 13:34
Сообщения: 594
Откуда: Москва
Карма: 27
он то "отбросит", а вы ? :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 13:45 
Не в сети
Разработчик

Зарегистрирован: 07 апр 2007, 23:51
Сообщения: 4494
Откуда: Уфа, Россия
Карма: 187
мы стараемся считать средствами java в частности класс BigDecimal, а не средствами mysql

у вас не схождение в биллинге вылезло или на базе?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 15:52 
Не в сети

Зарегистрирован: 07 май 2008, 13:34
Сообщения: 594
Откуда: Москва
Карма: 27
на самом деле достаточно странная проблема, если ошибка только из за округлений float то значит на одном вычислении ошибка может составить лишь копейку, следовательно для разницы в 100 рублей договоров должно быть 10к

а о то что ошибка вылазит в базе это в любом случае не хорошо, отчеты то мы строим по базе, в моем понимании это все же проблема mysql раз она decimal приводит неявно к float на операциях сложения и вычитания


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 17:09 
Не в сети
Разработчик
Аватара пользователя

Зарегистрирован: 19 дек 2006, 21:04
Сообщения: 5970
Карма: 256
http://dev.mysql.com/doc/refman/5.0/en/ ... float.html ?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 19:39 
Не в сети

Зарегистрирован: 07 май 2008, 13:34
Сообщения: 594
Откуда: Москва
Карма: 27
жесть, я вообще не врубаюсь в это:

Код:
 The problem cannot be solved by using ROUND() or similar functions, because the result is still a floating-point number:

mysql> SELECT i, ROUND(SUM(d1), 2) AS a, ROUND(SUM(d2), 2) AS b
    -> FROM t1 GROUP BY i HAVING a <> b;
+------+--------+-------+
| i    | a      | b     |
+------+--------+-------+
|    1 |  21.40 | 21.40 |
|    2 |  76.80 | 76.80 |
|    3 |   7.40 |  7.40 |
|    4 |  15.40 | 15.40 |
|    5 |   7.20 |  7.20 |
|    6 | -51.40 |  0.00 |
+------+--------+-------+


потипу round(x,2) <> round(x,2) и это нормально или как ?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 08 июн 2009, 23:16 
Не в сети
Разработчик

Зарегистрирован: 07 апр 2007, 23:51
Сообщения: 4494
Откуда: Уфа, Россия
Карма: 187
насколько я понял результат round все также число в формате float, а то, что видно в распечатке можно считать округленным форматированным выводом

как вариант можете попробовать проапгрейдить БД, или хотя бы для эксперимента


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 09 июн 2009, 14:14 
skn писал(а):
храняться значения в decimal(10,2) но для арифметических операция приводяться к float отсюда и разница

попробуйте исходящий остаток умножить на 100 и отбросить дробную часть а потом уже просумировать



Зачем мне это?
(Дальше следует небольшая речь о том, что у каждого из нас своя работа и так далее. По причине очевидности, я её опущу.)


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 09 июн 2009, 14:34 
Не в сети
Разработчик

Зарегистрирован: 07 апр 2007, 23:51
Сообщения: 4494
Откуда: Уфа, Россия
Карма: 187
kompot писал(а):
Зачем мне это?
(Дальше следует небольшая речь о том, что у каждого из нас своя работа и так далее. По причине очевидности, я её опущу.)


Затем, что если вы используете mysql напрямик для построения отчетов, мы ничем кроме советов помочь не сможем....


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 09 июн 2009, 14:59 
Хорошо. А как вы делаете на java?
Вы обращаетесь к базе не с суммимрующим запросом, а построчно вытаскиваете значения из базы и средствами java их суммируете, так?
Т.е. если я буду использовать вместо java какой-нибудь, например, php, то такой способ не должен дать такого эффекта?


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 09 июн 2009, 16:01 
Не в сети
Разработчик
Аватара пользователя

Зарегистрирован: 19 дек 2006, 21:04
Сообщения: 5970
Карма: 256
При работе с числом с плавающей точкой погрешность будет возникать всегда. Во всех языках идет просто округление, поэтому число выглядит нормально.
Когда же вы пытаетесь сравнить
(cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)>0.001
то точность результата разности mysql приходится делать также 0.001. А в этом месте уже вылезает погрешность плавающей точки.
Т.е.
(cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)=0.00
(cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)=0
будет TRUE
(cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)>=0.01
false

Разность же ровно в 100 рублей вряд ли погрешность.

В mysql 5.0.7 с полем DECIMAL нормально, а также при использовании FLOAT с округлением (FLOAT(,2)), он автоматически округляет результат суммы.

Если измените конец запроса с
and (cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)>0.001
на
and (cb.summa1+cb.summa2-cb.summa3-cb.summa4)!=(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)
должен быть нормальный результат.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 09 июн 2009, 16:17 
Нет, с этого я и начинал, когда искал разницу.

Смотрите:

Код:
select count(*)
from contract_balance cb
left join contract_balance_bckup cb1 on cb1.cid=cb.cid
left join contract c on c.id=cb.cid
where cb.yy=2009 and cb.mm=04 and cb1.yy=2009 and cb1.mm=04
and c.gr&(1<<0)>0


результат:

Код:
 count(*)   
 -----------
 7834       


Это было кол-во всех строк. Теперь выберем только неравные суммы, как вы посоветоваали:

Код:
select (cb.summa1+cb.summa2-cb.summa3-cb.summa4) as cb, (cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4) as cbb,
(cb.summa1+cb.summa2-cb.summa3-cb.summa4)-(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4) as diff
from contract_balance cb
left join contract_balance_bckup cb1 on cb1.cid=cb.cid
left join contract c on c.id=cb.cid
where cb.yy=2009 and cb.mm=04 and cb1.yy=2009 and cb1.mm=04
and c.gr&(1<<0)>0
and [b](cb.summa1+cb.summa2-cb.summa3-cb.summa4)!=(cb1.summa1+cb1.summa2-cb1.summa3-cb1.summa4)[/b]


результат:

Код:
 cb         cbb        diff   
 ---------  ---------  -------
 -2.33      -2.33      -0     
 -295.32    -295.32    -0     
 -1471.81   -1471.81   0       
 34.15      34.15      -0     
 -112.79    -112.79    0       
 320.18     320.18     0       
 -1643.82   -1643.82   -0     
 -330.79    -330.79    0       
 -5881.88   -5881.88   -0     
 . . . .

 1964 record(s) selected [Fetch MetaData: 0/ms] [Fetch Data: 68/ms]

 [Executed: 6/9/09 4:06:35 PM YEKST ] [Execution: 301/ms]



Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 09 июн 2009, 16:40 
Не в сети
Разработчик
Аватара пользователя

Зарегистрирован: 19 дек 2006, 21:04
Сообщения: 5970
Карма: 256
А версия mysql какая? Таблицу contract_balance_bckup как создавали? Выполните
SHOW COLUMNS FROM contract_balance
SHOW COLUMNS FROM contract_balance_bckup


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: 09 июн 2009, 16:46 
Ver 5.0.18


contract_balance:

Код:
 Field     Type                  Null     Key     Default     Extra   
 --------  --------------------  -------  ------  ----------  --------
 yy        smallint(5) unsigned  NO       PRI     0                   
 mm        tinyint(3) unsigned   NO       PRI     0                   
 cid       int(10) unsigned      NO       PRI     0                   
 summa1    decimal(10,2)         NO                                   
 summa2    decimal(10,2)         NO                                   
 summa3    decimal(10,2)         NO                                   
 summa4    decimal(10,2)         NO   


contract_balance_bckup:


Код:
 Field     Type                  Null     Key     Default     Extra   
 --------  --------------------  -------  ------  ----------  --------
 yy        smallint(5) unsigned  NO       PRI     0                   
 mm        tinyint(3) unsigned   NO       PRI     0                   
 cid       int(10) unsigned      NO       PRI     0                   
 summa1    float(10,2)           NO               0.00                 
 summa2    float(10,2)           NO               0.00                 
 summa3    float(10,2)           NO               0.00                 
 summa4    float(10,2)           NO               0.00   


Вернуться к началу
  
 
 Заголовок сообщения:
СообщениеДобавлено: 09 июн 2009, 17:00 
Не в сети
Разработчик
Аватара пользователя

Зарегистрирован: 19 дек 2006, 21:04
Сообщения: 5970
Карма: 256
На 5.0.77 при использовании в обоих таблицах decimal (float(,2)) нормально.
Правда тут написано http://dev.mysql.com/doc/refman/5.0/en/ ... float.html что нужно перезагрузить таблицу, не уверен с какой версии у нас таблица contract_balance не передампивалась...

Теоретически такой дамп (из decimal в float) не корректен, т.е. какое-либо значение могло перенестись неверно.
Скажем в 4 байтном float -383130.27 будет -383130.28
Однако в 8 байтный double влезет нормально.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 28 ] 

Часовой пояс: UTC + 5 часов [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
POWERED_BY
Русская поддержка phpBB
[ Time : 0.100s | 50 Queries | GZIP : On ]