Запросы, планы, оптимизация запросов, ...
Модераторы: kdv, CyberMax
-
Prog
- Сообщения: 12
- Зарегистрирован: 15 июл 2009, 11:01
Сообщение
Prog » 11 авг 2009, 20:32
Наткнулся на дурацкую проблему с делением-округлением "больших" числел:
Код: Выделить всё
select
cast(-6000000 as numeric(17,8)) / cast(32 as numeric(5,2)),
cast(-6000000 as numeric(17,8)) / cast(32 as numeric(17,5)),
cast(-6000000 as numeric(17,9)) / cast(32 as numeric(5,2))
from rdb$database
Результат:
-187500 2732.04826012975 -14561.774308973
Вроде всё должно быть просто: либо запрошенной точности хватает и тогда всё считается, либо нет и тогда вываливается
numeric overflow. А тут ни то ни сё: молча пишет в базу неверные значения..
И вообще, какой тип стоит использовать для денег, с учётом высокой требуемой точности, наличия математических операций и приличного разброса по
суммам?
IB 7.5
-
WildSery
- Заслуженный разработчик
- Сообщения: 1738
- Зарегистрирован: 05 июн 2006, 16:19
Сообщение
WildSery » 11 авг 2009, 21:54
Код: Выделить всё
ISQL Version: WI-V2.1.1.17910 Firebird 2.1
SQL> select
CON> cast(-6000000 as numeric(17,8)) / cast(32 as numeric(5,2)),
CON> cast(-6000000 as numeric(17,8)) / cast(32 as numeric(17,5)),
CON> cast(-6000000 as numeric(17,9)) / cast(32 as numeric(5,2))
CON> from rdb$database;
DIVIDE DIVIDE DIVIDE
===================== ===================== =====================
-187500.0000000000 -187500.0000000000000 -187500.00000000000
-
Prog
- Сообщения: 12
- Зарегистрирован: 15 июл 2009, 11:01
Сообщение
Prog » 13 авг 2009, 14:22
Да, я знаю, что FB2.1 во многом превосходит IB7.5..
И всё же, остаётся практический вопрос: какой тип стоит использовать для денег?
-
kdv
- Forum Admin
- Сообщения: 6595
- Зарегистрирован: 25 окт 2004, 18:07
Сообщение
kdv » 14 авг 2009, 02:16
numeric. только предварительно все-таки надо внимательно прочитать
http://www.ibphoenix.com/main.nfs?a=ibp ... act_num_fs , и поэтому не использовать при перемножении и делении numeric(15,8) и т.п. В numeric(15,8) цифра 8 означает МАСШТАБ, т.е. умножение числа на 10^8 при сохранении в целом числе на сервере, и деление на 10^8 при возврате его клиенту. В данном случае переполнения неизбежны, если перемножать или делить здоровенные числа, да еще для них указывать немеряное кол-во знаков после десятичной точки.
-
Prog
- Сообщения: 12
- Зарегистрирован: 15 июл 2009, 11:01
Сообщение
Prog » 14 авг 2009, 19:47
kdv, спасибо за прямую ссылку. Но всё же, как можно в общем случае "не использовать при перемножении и делении numeric(15,8)", если в процедуре надо обработать число из такого поля? Или имелся в виду какой-то другой numeric?
Dimitry Sibiryakov:
Имхо все, у кого есть деньги, считают их с приличной точностью ;)
Вот, например, есть миллион записей о списаниях со счёта, по -0.002 евро каждая. Надо посчитать сумму, добавить какой-нибудь налог и вывести это в рублях "по курсу" (курс, как минимум, с точностью (7,4); налог тоже не меньше чем (4,2)). Если считать в еврокопейках (18,2), то сумма так и будет ноль.
-
Dimitry Sibiryakov
- Заслуженный разработчик
- Сообщения: 1436
- Зарегистрирован: 15 сен 2005, 09:05
Сообщение
Dimitry Sibiryakov » 15 авг 2009, 12:20
Движение по валютному счёту может быть и происходит в 18.4 (хотя лично я не видел банка, позволяющего списать 0.002 евро). Сумма, стало быть, тоже 18.4. Курс рубля - 8.4, что даёт 18.8, правильно. Но! По налоговому кодексу суммы округляются до копеек, так что 18.8 превращаются в 18.2 ДО начисления налога. Налог 4.2, что даёт 18.4. Но! Налоги тоже округляются до копейки, так что результат должен быть 18.2 и ни цифрой после запятой больше.