【问题标题】:SQL error: BCD overflow caused by too many coalesceSQL错误:过多coalesce导致BCD溢出
【发布时间】:2022-04-08 06:29:07
【问题描述】:

由于某种原因从字段中消除空值,使用过多的合并会导致 BCD 溢出错误

我将错误消除到选择部分的 1 行。

  • 如果任何(4 个)合并被替换为固定值,则可以
  • 如果去掉任何coalesce,结果也是ok的
  • 如果对任何字段使用另一个字段,错误仍然存​​在

将“/”替换为“-”也会给出结果,但不是正确的值。

所有字段都是数字(10,4)。
这是火鸟 2.5.8 版

select 
coalesce(Field1, 0) * coalesce(Field2, 0) * ((100 - coalesce(Field3, 0)) / 100) * ((100 + coalesce(Field4, 0)) / 100)
from Table

应为计算列,实际结果是 BCD 溢出

【问题讨论】:

  • 你试过 IsNull(x,y) 函数吗?
  • BCD 溢出是什么意思?这不是 Firebird 错误。
  • @JasonDimmick 这个函数是什么? Firebird中没有这个功能!
  • @MarkRotteveel 我相信一些较旧的 Delphi 库(BDE ?)可以将 BCD 用于某些浮点 Interbase 数据类型,但这是过去的猜测和寓言 :-)

标签: sql firebird


【解决方案1】:

不完全是答案,只是一个测试。

火鸟 2.1.7、IBExpert、SQL 方言 3

create table t58096187 (
 f1 numeric(10,4),
 f2 numeric(10,4),
 f3 numeric(10,4),
 f4 numeric(10,4)
);

insert into t58096187 values ( 50, 50, 50, 50 );

select
 coalesce(F1, 0) * coalesce(F2, 0) * ((100 - coalesce(F3, 0)) / 100) * ((100 + coalesce(F4, 0)) / 100)
from t58096187;

错误:执行不成功...整数溢出...导致结果的最高有效位进位


•Dialect 3 数据库允许在精度大于 9 时将数字(DECIMAL 和 NUMERIC 数据类型)存储为 INT64


Numeric(9,4) 相同的错误应该避免使用int64 内部数据类型。

如果我将字段声明为 floatselect 会产生结果 1875,这完全在 Numeric(10,4) 数据类型内。

也许某些中间结果导致反向抛光超出范围?


如果要避免使用 INT64,这也可以使用

recreate table t58096187 (
 f1 numeric(6,2),
 f2 numeric(6,2),
 f3 numeric(6,2),
 f4 numeric(6,2)
)

Firebird 3.0.5 似乎也受到了影响 - https://dbfiddle.uk/?rdbms=firebird_3.0&fiddle=57729b31e0a5019aea68a136638d9f50

没有错误 - 但也没有结果!

Numeric-as-Int32 有效:https://dbfiddle.uk/?rdbms=firebird_3.0&fiddle=c4a4230e855b0ce4fd2b0c7b3b697cda

报告为https://www.sql.ru/forum/1317439-a/


Mark 对小数部分精度的假设可能是正确的。

recreate table t58096187 (
 f1 numeric(10,4),
 f2 numeric(10,4),
 f3 numeric(10,4),
 f4 numeric(10,3)
)

仍然有效。

https://dbfiddle.uk/?rdbms=firebird_3.0&fiddle=29a6c15d6e1854be230d29aea30307cf


Coalesce 似乎与我的问题无关,不知道它是否与主题启动者的问题有关,因为他所说的“删除coalesce”的意思是模棱两可的。在我删除coalesce 之后,它变成了这样

select
 F1 * F2 * F3 * F4
from t58096187

很可能是同样的错误

https://dbfiddle.uk/?rdbms=firebird_3.0&fiddle=1f29aff4102ace57e8fa27d83e59b93f

【讨论】:

  • 问题可能在于应用于数字/小数乘法和除法的规则(即新比例 = scale_lhs + scale_rhs),这导致比例变得太大(在你的例子中比例会变成16,这会为小数点前的值留下足够的空间。
  • @MarkRotteveel 当然,乘法和边界很棘手。汇编程序只是将数据类型加倍:int16 * in16 = int32 等。但是像 C 或 Java 这样的高级语言却没有……也就是说,它应该是下溢的 :-)
  • 你的乘法结果类型是 NUMERIC(18,16),值 1875 不合适,导致溢出。
  • 为什么应该是 NUMERIC(18,16) 而不是 NUMERIC(10,4)NUMERIC(40,4) ? @MarkRotteveel
  • 至少它没有记录在“定点数据类型”FB 2.5 中。手册参考
【解决方案2】:

显然问题更具体一点:The result of an integer operation caused the most significant bit of the result to carry.

所以应用建议的解决方案(定义我们想要使用的结果数字的格式)我们会这样做:

select
    cast( (cast(coalesce(f1, 0) as numeric(10,4)) * cast(coalesce(f2, 0) as numeric(10,4)) ) as numeric(10,4)) * cast(((100 - coalesce(f3, 0)) / 100) as numeric(10,4)) * cast(((100 + coalesce(f4, 0)) / 100) as numeric(10,4))
-- cast(coalesce(f1, 0) as numeric(10,4)) * cast(coalesce(f2, 0) as numeric(10,4)) * cast(((100 - coalesce(f3, 0)) / 100) as numeric(10,4)) * cast(((100 + coalesce(f4, 0)) / 100) as numeric(10,4)) -- sigue dando el mismo error
-- coalesce(F1, 0) * coalesce(F2, 0) * ((100 - coalesce(F3, 0)) / 100) * ((100 + coalesce(F4, 0)) / 100)
from t58096187;

感谢Arioch 'The 的精彩分析和重现错误的示例!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 2018-04-09
    相关资源
    最近更新 更多