【问题标题】:ODP.net Oracle Decimal Number precision problem when filling a dataset. Exception: Arithmetic operation resulted in an overflow填充数据集时 ODP.net Oracle 十进制数精度问题。例外:算术运算导致溢出
【发布时间】:2010-11-05 19:55:00
【问题描述】:

我正在使用 c# .net 2 (Visual Studio 2005 SP1) 尝试使用来自 Oracle10g 数据库的 select * from table 的结果填充数据集。 .net 框架、IDE 和数据库无法在此客户端站点更改。

我正在使用 ODP.net 提供程序进行连接,dll 版本是 2.102.2.20

当我运行填充命令时,我得到一个异常:

算术运算导致溢出

此外,如果我尝试在 Visual Studio 设计器(显示表数据)中查看有问题的列,我会为表中该列的每一行得到 。如果我的查询选择其他具有整数的列(例如省略此列),该代码将完美运行。

当我在 Toad 的数据库中查看有问题的列时,它看起来很好,数据看起来像:

919.742866695572

我需要 精度,因为它是蒙特卡罗模拟所必需的。

如果我不使用数据适配器来填充数据表,而是使用数据读取器并调用 dataReader.getValue(columnIndex) 我会得到相同的错误,但如果我调用 dataReader.GetOracleDecimal(columnIndex) 那么我会得到我正在寻找的结果,没有错误。

我宁愿使用数据适配器并填充数据集(请注意,这些是无类型数据集,因为我无法从 oracle db 中获取自动生成的强类型数据集)。我不想使用 datareader 并遍历结果(选择列值),因为我试图将其编写为适用于许多场景的通用方法,无论列数如何,十进制列的索引需要特定按数据类型获取调用。

有人可以帮忙吗? 我可以使用新版本的 ODP.net dll 连接到旧的 Oracle10g 数据库吗?我想知道这是否会有所帮助。

谢谢

【问题讨论】:

  • 将 ODP.net 版本更改为 11g (Oracle.DataAccess.dll 2.111.6.20) 并没有帮助我仍然得到算术运算导致溢出异常。一种虽然不理想的解决方案是这样做:SELECT TO_CHAR(offendingColumn) FROM Table 但是现在我的 dataColumn 类型不同,我将这些数据写入 Excel,所以我不确定这是否也会影响单元格格式。跨度>
  • 另外这意味着我需要知道表格中的每一列我不能只做一个毯子 Select * From Table

标签: c# oracle datatable oracle10g odp.net


【解决方案1】:

如果您迁移到更高版本的 ODP.NET(例如 12.x),错误只会从“算术溢出”更改为“无效转换异常”。您必须 CAST 数值来减少疯狂的精度值,如 29 或 30 位小数,使其更实用,如 2 到 4 位小数。

要识别具有过大十进制值的列和行,您可以在将 MY_SCHEMA、MY_TABLE 和数字 10 替换为 25 后运行下面的 SQL 来识别值超过 25 位小数的列。此 SQL 将生成一条 SQL,应运行该 SQL 来识别问题列。

SELECT 'SELECT ' || LISTAGG('MAX(LENGTH(TO_CHAR(ABS(' || column_name || ') - FLOOR(ABS(' || column_name || '))))) - 1  AS decimals_' || column_name || CHR(13)
                    , CHR(9)|| ', ') WITHIN GROUP (ORDER BY rn)  ||
                    ' FROM ' || owner || '.' || table_name  || CHR(13) ||
                    ' WHERE '  || CHR(13) ||
                      LISTAGG('(LENGTH(TO_CHAR(ABS(' || column_name || ') - FLOOR(ABS(' || column_name || ')))) - 1) > 10 ' || CHR(13)
                                , CHR(9)|| '  OR  ')
WITHIN GROUP (ORDER BY rn) AS Nasty_Numbers_Finder_Query
FROM
(
    SELECT  owner, table_name, column_name,
        row_number() OVER ( PARTITION BY table_name  ORDER BY rownum) rn
    FROM  dba_tab_columns
    WHERE
        OWNER = 'MY_SCHEMA'
        AND table_name = 'MY_TABLE'
        AND (data_type LIKE '%FLOAT%'
            OR data_type LIKE '%NUMERIC%')
) a
GROUP BY owner, table_name

如需了解更多信息,我已在博客here

【讨论】:

    【解决方案2】:

    问题是结果值的精度太高,无法在不丢失数据的情况下转换为 System.Decimal。我忘记了允许的确切位数,但大约是 18 位左右。将结果值舍入到那么多位数是否可以接受?在您给出的示例中,round(MyColumn, 15) 左右就足够了...

    【讨论】:

      【解决方案3】:

      You can try the latest version of ODP.Net (11g)。它向后兼容。我用它来连接一个10g的数据库就好了。我认为它也应该适用于 VS 2005。对于 clickonce 部署,只需添加此问题引用的 dll:What is the minimum client footprint required to connect C# to an Oracle database? 重要说明是,如果您拥有最新版本的 odp.net,则所有 dll 都包含在安装目录中。您无需单独下载即时客户端。只需搜索它们。

      【讨论】:

      • 太好了,我在我的电脑上试试这个会让你知道我的进展如何。在部署的机器上我是否也需要安装它?或者我可以使用更新版本的 Oracle.DataAccess.Dll 部署我的控制台应用程序?它不是我宁愿只在我的应用程序 bin 文件夹中部署这个应用程序,并在我的应用程序 bin 文件夹中部署所有需要 oracle 的 dll,而不是安装在目标部署的机器(服务器)上,这涉及什么以及需要哪些文件?谢谢
      • 您会希望 Oracle Developer Tools for Visual Studio 包含您需要的所有 dll。将它安装在客户端计算机上的唯一方法是安装完整的 Oracle 客户端或使用即时客户端(我推荐)。对于即时客户端,您只需找到 .dll(请参阅stackoverflow.com/questions/70602/…)以获取更多信息并将它们添加为内容进行复制。这将确保它们正确部署。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-15
      • 2013-04-09
      • 2012-02-19
      • 2011-06-12
      • 2011-05-11
      相关资源
      最近更新 更多