1

我将以下代码与 Oracle ADO.Net 提供程序(DevArt 的dotConnect Universal)一起使用。有趣的是它有时会起作用,然后大多数时候它会抛出Devart.Data.Oracle.OracleException: ORA-01722: invalid number

  string sql = "SELECT DISTINCT  B.PRICE_TIER_KEY,b.label, a.INSERT_DATE   AS PriceEffectiveDate,B.PROGRAM_KEY AS PRICE_PROGRAM_KEY FROM GHX_MEMBER_TIER A INNER JOIN VHA_INT_PRICE_TIER B ON A.SRC_ID_VALUE = B.PRICE_TIER_KEY WHERE RowNum <=100";

        DbProviderFactory dpf = DbProviderFactories.GetFactory(System.Configuration.ConfigurationManager.ConnectionStrings["Con_ORA_DevArt"].ProviderName);
        DbConnection conn = dpf.CreateConnection();
        conn.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Con_ORA_DevArt"].ConnectionString;

        DbCommand dbcmd = dpf.CreateCommand();
        dbcmd.Connection = conn;
        //dbcmd.Connection = uniConnection1;
        dbcmd.CommandText = sql;
        dbcmd.CommandType = CommandType.Text;
        dbcmd.CommandTimeout = 0;


        DataTable table = new DataTable();



        try
        {
            System.Data.Common.DbDataAdapter da = dpf.CreateDataAdapter();
            da.SelectCommand = dbcmd;
            // Fill the DataTable.

            da.Fill(table);
        }
        catch (Exception ex)
        {
            throw;
        }
        finally
        {
            if (conn != null && conn.State != ConnectionState.Closed)
            {
                conn.Close();
                conn.Dispose();
            }
            if (dbcmd != null)
            {
                dbcmd.Dispose();
            }
        }
4

2 回答 2

5

ORA-01722 是数据转换错误。当字符串包含非数字值时,当我们尝试将字符串转换为数字时,就会发生这种情况。这可以通过 TO_NUMBER() 强制转换显式发生,也可以通过在 JOIN 或 WHERE 子句中使用不同数据类型的列隐式发生。

所以你现在可以看到你发布了所有错误的信息:重要的是所涉及的表的数据结构和内容。最有可能出现问题的是连接中的两列:SRC_ID_VALUE 和 PRICE_TIER_KEY。这些都是数字列还是两个字符串?如果一个是数字而另一个不是,那么字符串之一是否只包含数字数据?

这很重要,因为 Oracle在尝试比较之前会将字符串列转换为数字。

例如,如果 table1 有这个数据......

 1234
10789

...而table2有这个数据...

'1234'
'45o7'

第一行将正常连接,但第二行将抛出 ORA-01722 并使查询脱轨。

解决这个问题的方法是使用 TO_CHAR() 将数值列转换为字符串。这将阻止 Oracle 在该列上使用任何索引。这可能与您的情况无关,因为您很可能只是对两个表进行全表扫描,但更精确的查询可能很重要。


“我认为这是甲骨文的一个可怕特性。”

将字符串转换为数字会更改排序顺序。这 ...

'1'、'10'、'2'、'21'、'3'

……变成这个……

1、2、3、10、21

当然它不能使用原始索引。

有一种解决方法,但它有点涉及。

  1. 构建一个函数来测试输入字符串,如果它是数字则返回一个数字,如果不是则返回 null。
  2. 使用该函数构建基于函数的索引:

    在 GHX_MEMBER_TIER(is_a_number(SRC_ID_VALUE)) 上创建索引 src_id_num_fbi ;

  3. 在查询中使用该函数:

    ... ON is_a_number(A.SRC_ID_VALUE) = B.PRICE_TIER_KEY

只有您可以决定这是否值得努力。

于 2013-02-07T06:20:16.257 回答
4

尝试更改ON A.SRC_ID_VALUE = B.PRICE_TIER_KEYON A.SRC_ID_VALUE = to_char(B.PRICE_TIER_KEY).

来自手册:“将字符值与数值进行比较时,Oracle 将字符数据转换为数值。”。这种隐式转换并不总是安全的,您需要强制 Oracle 将数字转换为字符串。

于 2013-02-07T06:18:08.237 回答