随机获取无效数字错误

时间:2013-02-07 05:40:52

标签: oracle ado.net devart

我在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();
            }
        }

2 个答案:

答案 0 :(得分:5)

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

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

这很重要,因为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上创建索引src_id_num_fbi(is_a_number(SRC_ID_VALUE));

  3. 在查询中使用该功能:

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

  4. 只有你能决定这是否值得付出努力。

答案 1 :(得分:4)

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

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