pl/sql 程序员在计算货币时常犯的错误是啥?

Posted

技术标签:

【中文标题】pl/sql 程序员在计算货币时常犯的错误是啥?【英文标题】:What are the common mistakes pl/sql programmers make with money computation?pl/sql 程序员在计算货币时常犯的错误是什么? 【发布时间】:2011-08-26 02:09:24 【问题描述】:

您好,我正在寻找 pl/sql 程序员在编写处理大量货币计算的应用程序时常犯的错误。 (折扣、税收、税率等) 据我所知,我一直在使用 java 和 hibernate 进行货币计算,java 有一套规则和最佳实践,比如 BigDecimal 来保持精度等。现在我正在努力提高我在处理金融模块方面的 pl/sql 技能这就是为什么我想知道这个陷阱并避免它们。还有任何现有的口头禅或 pl/sql 最佳实践吗? 在此先感谢各位。

【问题讨论】:

你为什么认为这是一个错误?我的意思是与我的问题有关Money computations, comparison between java and Oracle/PL SQL which to use 甚至有人建议使用 pl/sql 100% Oracle 几乎在任何地方都使用十进制数(您必须不遗余力地使用二进制数)。但是,插入表格会默默地将值截断为数字格式,因此存在一些舍入错误的范围(如果其他人投票重新打开问题,我会对此进行扩展) 我真的不知道他们为什么要关闭这个问题,而我要问的只是新的 pl/sql 程序员犯的常见错误?这个问题的目的是避免这些错误,并从 SO 中的 pl/sql 专家那里学习最佳实践。这个问题甚至没有将 pl/sql 与任何引发任何辩论或争论的东西进行比较。除非 pl/sql 在处理货币计算时没有任何既定的最佳实践,否则我没有发现任何关于陷阱和最佳实践的问题,我强烈怀疑这一点,因为 pl/sql 已经存在了很长时间。 我承认这是一个有点主观的问题,但对于这个话题,具有使用 PL/SQL 开发金融应用程序经验的开发人员可能会提供具体的、可支持的建议。 (可悲的是,我不是那个人。)重新打开。 这可能有助于使问题更具体。例如,陈述您在 Java 中使用的一些特定最佳实践,并询问在 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 语句时,使用锚定到基础表的类型(包括长度/比例/精度)的绑定变量。

【讨论】:

更多请 :) 您还知道任何讨论货币计算的 pl/sql 最佳实践的链接/博客吗?【参考方案2】:

这里有 2 个快速提示:

实用的 Oracle 提示:在表列类型和 PL/SQL 中都使用 NUMBER(不带比例/精确度).. 为您省去了很多麻烦。 NUMBER(x,y) 不会为您节省任何存储或 CPU 周期..

一般提示(您想先了解大局):

首先,研究您对十进制算术的具体应用程序要求:您是否纳税?如果是,美国还是欧盟?取整规则因管辖权和/或应用程序而异。 Oracle SQL 是否支持所需的东西? PL/SQL 吗?如果不是,那么错误就是使用 PL/SQL 来做这些事情。

即将推出的十进制算术黄金标准是 IEEE decimal128。您可能想阅读 Wikipedia 并可能以 http://www.carus-hannover.de/doc/DFP_PW6_in_SAP_NetWeaver_0907.pdf 为例。它支持所有类型的舍入等。不知道何时涉及 Oracle QL / PL/SQL

【讨论】:

【参考方案3】:

用任何语言处理 MONEY 类型的问题是:

截断 - 当您应该四舍五入但结果却被截断时。 四舍五入 - 当你应该截断时,它却被四舍五入了。

如果您在每一步都小心这些,那么处理 MONEY 并不是一件很难的工作。

【讨论】:

以上是关于pl/sql 程序员在计算货币时常犯的错误是啥?的主要内容,如果未能解决你的问题,请参考以下文章

逆序枚举时常犯的一个错误

在使用 Python 时常犯的9个错误,建议看看如何规避

社区交易中-选择信号时常犯的 10 个错误(第一章)

使用 @Transactional 时常犯的N种错误

使用 @Transactional 时常犯的N种错误

社区交易-选择信号时常犯的10个错误(第二章)