powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Точное значение NUMBER
25 сообщений из 33, страница 1 из 2
Точное значение NUMBER
    #39847291
Maxmix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сломал голову уже, помогите!

С помощью процедуры в базе сохраняются суммы в колонке NUMBER(14,2).
На входе процедуры - параметр P_SUM типа NUMBER.
Прежде чем делать insert, процедура выполняет проверки, среди прочего есть условие:
P_SUM <= MAXIMUM_ALLOWED_AMOUNT
которое никогда не должно нарушаться, так как клиент автоматически подставляет корректное значение суммы в параметр P_SUM, то есть всегда вставляется максимально допустимое значение суммы.
И всё было хорошо, но на днях условие стало изредка нарушаться, и исключение выбрасывается. Если походить отладчиком PL/SQL Developer-а по процедуре, то всегда всё хорошо, а вот когда пользователи вызывают процедуру через клиента - ошибка возникает часто.
Ну я вставил в исключение текст
Код: plsql
1.
to_char((P_SUM - max_allowed_amount),'FM999,999,999,999,990.0000000000000000')


и наблюдаю, что значение параметра P_SUM слегка неровное, что-то вроде
97.679999999930000000
или
98.680000000023000000

Мы не знаем, почему так стало, но вопрос в другом.
Я подавляю исключение, записываю округлённое значение в NUMBER(14,2) и всё опять хорошо.
Но!
Попутно я записываю P_SUM в специально созданную тестовую таблицу в колонку P_SUM_COPY типа NUMBER(38,20).
И вот любые действия с этой колонкой всегда почему-то приводят к округлённым числам. То есть to_char(p_sum_copy, '99999.9999999999999999999999999999999) возвращает всегда красивое число (98.68 например).
Где-то дефект в моём понимании NUMBER, я не могу понять где.
Oracle теряет точность при записи параметра в колонку NUMBER(38,20)? Или изначально в параметре 98.68, а микроскопическая прибавка - это только видимость? Как одно и то же число может быть то ровной суммой в копейках, то слегка больше, то слегка меньше?
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39847295
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MaxmixOracle теряет точностьПриведи вручную заместо оракла число 99999.9999999999999999999999999999999 к NUMBER(38,20).
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39847332
Maxmix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
-2-,

такого числа нигде нет, моё число предположительно 98.680000000023

Я могу вставить его вручную в колонку NUMBER(38,20), через sql*plus, и на выходе SELECT вижу
98.680000000023000000000000
После set numformat 99999999999.99999999999999999990 во-всяком случае.

То есть, судя по to_char() из процедуры, там на входе параметр NUMBER имеет нецелое число копеек, после перекладывания этого NUMBER в NUMBER(38,20) с целью отладки получается целое число копеек. Как так?
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39847513
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не пользуйтесь double для денег и будет Вам счастье.
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39847547
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymousНе пользуйтесь double для денег и будет Вам счастье.currency наше всё
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39848063
Maxmix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Как-то непонятно, внутри процедуры уже нет никаких double и currency, и вот такой результат ;-(
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39848067
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MaxmixКак-то непонятно, внутри процедуры уже нет никаких double и currency, и вот такой результат ;-(Инженера должна отличать приобретённая способность понимать и объяснять неожиданный результат.
Начни свой путь с понимания того, что double вне процедуры.
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39851070
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MaxmixСломал голову уже, помогите!

Попутно я записываю P_SUM в специально созданную тестовую таблицу в колонку P_SUM_COPY типа NUMBER(38,20).


не то вставляете (не значение параметра)

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
SQL> set serveroutput on
SQL> declare
  2   procedure p(p_id int,p_sum number) is
  3   begin
  4   dbms_output.put_line('proc p_sum='||to_char(p_sum, '99999.9999999999999999999999999999999'));
  5   insert into log_p_sum(id,p_sum_copy) values (p_id,p_sum);
  6   end;
  7  begin
  8   p(1,98.680000000023);
  9   p(2,20/3);
 10  end;
 11  /
proc p_sum=    98.6800000000230000000000000000000
proc p_sum=     6.6666666666666666666666666666667

PL/SQL procedure successfully completed.

SQL> set numformat 99999999999.99999999999999999990
SQL> col id format 9999
SQL> select * from log_p_sum;

   ID                        P_SUM_COPY
----- ---------------------------------
    1           98.68000000002300000000
    2            6.66666666666666666667



.....
stax
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39855495
Maxmix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо, Stax
У меня примерно такая же картина, но я думал, что мой select * from log_p_sum; врёт, показывая какие-то миллиардные доли копейки, а вот to_char() всегда говорит правду.
Результат применения TO_CHAR на колонке -- круглые копейки, вот почему так?
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
select rmz_ref, amount_param, to_char(amount_param, '999999999.99999999999999999990') as  amount_string
 from FLOAT_TROUBLES t where rmz_ref in ('562575','562576','562577','562578','562579','562580','562581','562582','562583');
   RMZ_REF                             AMOUNT_PARAM AMOUNT_STRING
---------- ---------------------------------------- -------------------------------
    562575                 68640.000000000000000000      68640.00000000000000000000
    562576                 21760.000000000000000000      21760.00000000000000000000
    562577                358068.000000000000000000     358068.00000000000000000000
    562578               1677217.500000000000000000    1677217.50000000000000000000
    562579                243432.000000000000000000     243432.00000000000000000000
    562580                379995.840000000026000000     379995.84000000000000000000
    562581                155280.000000000000000000     155280.00000000000000000000
    562582                 82080.000000000000000000      82080.00000000000000000000
    562583                447703.369999999995000000     447703.37000000000000000000
9 rows selected


TO_CHAR() врёт, что ли? Куда делась точность в числе 447703.369999999995000000 после TO_CHAR?

У вас колонка P_SUM_COPY такого же размера, как моя AMOUNT_PARAM то есть NUMBER(38,20)?

Код: plsql
1.
2.
3.
4.
5.
6.
SQL> desc float_troubles
Name                  Type          Nullable Default Comments                                                                    
--------------------- ------------- -------- ------- --------------------------------------------------------------------------- 
RMZ_REF               NUMBER        Y                                                                                            
AMOUNT_PARAM_STANDARD NUMBER(15,2)  Y                                                 
AMOUNT_PARAM          NUMBER(38,20) Y                
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39855500
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxmixпочему так?RTFM dump()
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39855515
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxmix,
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
SQL> desc log_p_sum
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                                 NUMBER(38)
 P_SUM_COPY                                         NUMBER(38,20)

SQL> insert into log_p_sum values (3,447703.369999999995000000);

1 row created.


SQL> set numformat 99999999999.99999999999999999990
SQL> col id format 9999
SQL> select id, p_sum_copy, to_char(p_sum_copy, '999999999.99999999999999999990') as  p_sum_string
  2  from log_p_sum
  3  /

   ID                        P_SUM_COPY P_SUM_STRING
----- --------------------------------- -------------------------------
    3       447703.36999999999500000000     447703.36999999999500000000
    1           98.68000000002300000000         98.68000000002300000000
    2            6.66666666666666666667          6.66666666666666666667



.....
stax
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39855518
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxmix,
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
SQL> set lines 333
SQL> /

   ID                        P_SUM_COPY P_SUM_STRING                    D
----- --------------------------------- ------------------------------- --------------------------------------------------
    3       447703.36999999999500000000     447703.36999999999500000000 Typ=2 Len=10: 195,45,78,4,37,100,100,100,100,96
    1           98.68000000002300000000         98.68000000002300000000 Typ=2 Len=8: 193,99,69,1,1,1,1,24
    2            6.66666666666666666667          6.66666666666666666667 Typ=2 Len=12: 193,7,67,67,67,67,67,67,67,67,67,68



....
stax
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39855609
Maxmix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: plsql
1.
2.
3.
4.
5.
6.
7.
select rmz_ref, amount_param, to_char(amount_param, '999999999.99999999999999999990') as  amount_string
      , dump(amount_param) as amount_param_dump
 from FLOAT_TROUBLES 
 where rmz_ref in (562583);
   RMZ_REF                             AMOUNT_PARAM AMOUNT_STRING                   AMOUNT_PARAM_DUMP
---------- ---------------------------------------- ------------------------------- --------------------------------------------------------------------------------
    562583                447703.369999999995000000     447703.37000000000000000000 Typ=2 Len=5: 195,45,78,4,38


У нас в одинаковых колонках лежат одинаковые NUMBER, но дампы отличаются, правильно я понял?
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39855627
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxmix
Код: plsql
1.
2.
3.
   RMZ_REF                             AMOUNT_PARAM AMOUNT_STRING                   AMOUNT_PARAM_DUMP
---------- ---------------------------------------- ------------------------------- --------------------------------------------------------------------------------
    562583                447703.369999999995000000     447703.37000000000000000000 Typ=2 Len=5: 195,45,78,4,38

Это не может быть выводом из SQL*Plus-а.
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39855664
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxmix
Код: plsql
1.
2.
3.
4.
5.
6.
7.
select rmz_ref, amount_param, to_char(amount_param, '999999999.99999999999999999990') as  amount_string
      , dump(amount_param) as amount_param_dump
 from FLOAT_TROUBLES 
 where rmz_ref in (562583);
   RMZ_REF                             AMOUNT_PARAM AMOUNT_STRING                   AMOUNT_PARAM_DUMP
---------- ---------------------------------------- ------------------------------- --------------------------------------------------------------------------------
    562583                447703.369999999995000000     447703.37000000000000000000 Typ=2 Len=5: 195,45,78,4,38


У нас в одинаковых колонках лежат одинаковые NUMBER, но дампы отличаются, правильно я понял?
в табличке у Вас хранится 447703. 37 (Typ=2 Len=5: 195,45,78,4,38)
откуда взялось 447703.369999999995000000 я не знаю (мож клиент глючит)

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
  1* insert into log_p_sum values (4,447703.37)
SQL> /

1 row created.

SQL> select id, p_sum_copy, to_char(p_sum_copy, '999999999.99999999999999999990') as  p_sum_string
  2  ,dump(p_sum_copy) d
  3  from log_p_sum
  4  /

   ID                        P_SUM_COPY P_SUM_STRING                    D
----- --------------------------------- ------------------------------- --------------------------------------------------
    4       447703.37000000000000000000     447703.37000000000000000000 Typ=2 Len=5: 195,45,78,4,38
    3       447703.36999999999500000000     447703.36999999999500000000 Typ=2 Len=10: 195,45,78,4,37,100,100,100,100,96
    1           98.68000000002300000000         98.68000000002300000000 Typ=2 Len=8: 193,99,69,1,1,1,1,24
    2            6.66666666666666666667          6.66666666666666666667 Typ=2 Len=12: 193,7,67,67,67,67,67,67,67,67,67,68



.....
stax
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39855686
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxmixв одинаковых колонках лежат одинаковые NUMBER, но дампы отличаютсяУже сказали тебе про клиента.
Код: plsql
1.
2.
3.
4.
5.
select to_char(447703.37d-447703.369999999995d) zero from dual;

Z
-
0
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856154
Maxmix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ребята, вы круты, что выводу дампа понимаете, какое значение в базе!

Теперь выясняется, что PL/SQL Developer не (всегда) показывает правильно значения NUMBER.
Попутно выяснили, что to_char() показывает истинное значение.
Параметр, я думаю, записываю в отладочную таблицу правильно, так как там просто insert values (... P_AMOUNT...)
Далее, просмотрев накопленные значения, я вижу, что все сохранённые значения параметра уже за большой период времени вполне себе целые (в копейках).

Возвращаясь к первому посту с вопросом... Тайна так и не раскрыта, почему случилось так, что в параметре оказалось нецелое число копеек. Разработчики клянутся, что галочка Currency стоит.

Но, похоже, это был единичный случай!
Спасибо, что не бросили!
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856192
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxmix Разработчики клянутся, что галочка Currency стоит.

возможно кто-то (что-то), отработало без галочки

зы
самое простое - на тестовой посмотреть поведение "без галочки"

.....
stax
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856229
Maxmix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Да, проще, но только если микрокопейки будут регулярно появляться, а то вдруг есть только одна магическая сумма то будем долго тыкаться!

Спасибо за помощь!
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856321
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MaxmixПопутно выяснили, что to_char() показывает истинное значение.


У каждого своя истина. Твою похоже не смущает что TO_CHAR округляет:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
SQL> select to_char(1.99999999999999995,'FM999,999,999,999,990.0000000000000000') from dual
  2  /

TO_CHAR(1.99999999999999995,'FM999,99
-------------------------------------
2.0000000000000000

SQL> 



SY.
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856371
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY
У каждого своя истина. Твою похоже не смущает что TO_CHAR округляет:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
SQL> select to_char(1.99999999999999995,'FM999,999,999,999,990.0000000000000000') from dual
  2  /

TO_CHAR(1.99999999999999995,'FM999,99
-------------------------------------
2.0000000000000000

SQL> 



SY.

нет, не смущает
у него в маске '999999999.99999999999999999990' "разрядов" как-бы хватает

імхо зазвоздка в чем-то другом
напр клиєнт не так понимает number

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
SQL> ed
Wrote file afiedt.buf

  1  declare
  2   f binary_float;
  3  begin
  4   for r in (select * from log_p_sum order by id) loop
  5     f:=r.p_sum_copy;
  6     dbms_output.put_line(r.id
  7        ||' в таблице='||to_char(r.p_sum_copy,'999999999.99999999999999999990')
  8        ||' binary_float='||to_char(f,'999999999.99999999999999999990')
  9       );
 10   end loop;
 11* end;
SQL> /
1 в таблице=        98.68000000002300000000 binary_float=        98.68000030000000000000
2 в таблице=         6.66666666666666666667 binary_float=         6.66666651000000000000
3 в таблице=    447703.36999999999500000000 binary_float=    447703.37500000000000000000
4 в таблице=    447703.37000000000000000000 binary_float=    447703.37500000000000000000

PL/SQL procedure successfully completed.



откуда пятеречка (447703.37 5 ) хз, у меня не было практики с binary_float

......
stax
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856375
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax
откуда пятеречка (447703.37 5 ) хз, у меня не было практики с binary_float


Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
SQL> ed
Wrote file afiedt.buf

  1  declare
  2   f binary_float;
  3  begin
  4     f:=447703.37;
  5     dbms_output.put_line('f='||f||' to_char(f)='||to_char(f,'999999999.99999999999999999990'));
  6* end;
SQL> /
f=4,47703375E+005 to_char(f)=    447703.37500000000000000000

PL/SQL procedure successfully completed.



.....
stax
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856407
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax,

причeм тут "пятерочка"? TO_CHAR дает округленное значение если дробная часть "не влезает" в маску. И почему-то это документировано не в SQL Reference Manual а в OLAP DML Reference Manual и то вскользь:

Possible Effects of TO_CHAR Rounding

All number format models cause the number to be rounded to the specified number of significant digits.

SY.
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856410
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SYИ почему-то это документировано не в SQL Reference ManualRTFM Number Format Models (FAQ)
...
Рейтинг: 0 / 0
Точное значение NUMBER
    #39856412
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY,


какой разряд (дробная часть) 447703.369999999995000000 не влезает в маску '999999999.99999999999999999990'?



Код: plsql
1.
2.
3.
4.
5.
6.
  1* select 447703.369999999995000000 с, to_char(447703.369999999995000000,'999999999.99999999999999999990') to_char from dual
SQL> /

                              С TO_CHAR
------------------------------- -------------------------------
    447703.36999999999500000000     447703.36999999999500000000



.....
stax
...
Рейтинг: 0 / 0
25 сообщений из 33, страница 1 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Точное значение NUMBER
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]