Каковы распространенные ошибки, которые программисты pl/sql делают с вычислением денег?

Привет, я ищу общие ошибки, которые программисты pl/sql делают, когда они программируют приложения, которые имеют дело с большими денежными расчетами. (Скидки, налог, ставки и т.д.) Я использовал java и hibernate для денежных вычислений, насколько я помню, java имеет набор правил и лучших практик, таких как BigDecimal, чтобы сохранить точность и т.д. Сейчас я пытаюсь улучшить свои навыки pl/sql при работе с финансовыми модулями вот почему я хочу знать эту ошибку и избегать их. Также есть ли какая-либо существующая мантра или передовая практика pl/sql для этого? Спасибо заранее, ребята.

Ответ 1

Используя этот пример:

create table t_val
  (id number(10,0),
  value number(5,2));

declare
  v_dummy number;
begin
  delete from t_val;
  for i in 9 .. 20 loop
    insert into t_val values (i, 1/i);
    select count(*)
    into v_dummy 
    from t_val 
    where value = 1/i;
    dbms_output.put_line(to_char(i,'00')||':'||v_dummy||':'||
              to_char(1/i,'000.999999'));  
  end loop;
  --
end;
/

select id, value from t_val order by 1;

Вы можете видеть, что код вставляет, например, 0.11111, который неявно округлен до 0.11 Когда код сразу пытается подсчитать значения для 0.11111, он не находит совпадений.

Аналогично, значения для (1/14) и (1/15) оба округляются до 0,07.

Это не проблема, характерная для PL/SQL, и я видел подобные проблемы в Java и PHP-коде, когда значение в "клиенте" округляется, когда оно попадает в базу данных. PL/SQL действительно предлагает лучшее решение, поскольку вы можете объявить переменную типа конкретной таблицы/столбца, и эта привязка сохраняется, даже если столбец изменен.

declare
  v_value  t_val.value%type;
  v_dummy number;
begin
  delete from t_val;
  for i in 9 .. 20 loop
    v_value := 1/i;
    insert into t_val values (i, v_value);
    select count(*)
    into v_dummy 
    from t_val 
    where value = v_value;
    dbms_output.put_line(to_char(i,'00')||':'||v_dummy||':'||
            to_char(1/i,'000.999999')||':'||to_char(v_value,'000.999999'));  
  end loop;
  --
end;
/

Так наилучшей практикой является то, что при работе с оператором SQL используйте переменные bind, привязанные к типу (включая длину/масштаб/точность) базовой таблицы.

Ответ 2

Вот 2 быстрых подсказки:

Практический совет Oracle: используйте NUMBER (без scale/prec) как в виде столбца таблицы, так и в PL/SQL.. экономит вам много головных болей. NUMBER (x, y) не сохраняет вам никаких циклов хранения или процессора.

Общий намек (сначала вы хотите иметь большую картинку):

  • Во-первых, изучите, каковы ваши конкретные требования к приложениям относительно десятичной арифметики: действительно ли вы делаете налог? если да, то США или ЕС? правила округления различаются в зависимости от юрисдикции и/или применения. Поддерживает ли Oracle SQL необходимый материал? Есть ли PL/SQL? Если нет, ошибка заключается в том, чтобы использовать PL/SQL в любом случае.

  • Предстоящий золотой стандарт для десятичной арифметики - IEEE decimal128. Вы можете прочитать в Википедии и, возможно, http://www.carus-hannover.de/doc/DFP_PW6_in_SAP_NetWeaver_0907.pdf в качестве примера. Он поддерживает весь вкус округления и т.д. Не знаю, когда дело доходит до Oracle QL/PL/SQL

Ответ 3

Проблема с использованием типов денежных средств на любом языке:

  • Усечение. Когда вы должны округлить, но результат будет усечен.
  • Округление. Когда вы должны усечь, но он округлен.

Если вы внимательно относитесь к этим на каждом шагу, обработка ДЕНЕГ не является такой трудной задачей.