随机获取无效数字错误

Sun*_*nil 1 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();
            }
        }
Run Code Online (Sandbox Code Playgroud)

APC*_*APC 5

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

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

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

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

 1234
10789
Run Code Online (Sandbox Code Playgroud)

...和table2有这个数据......

'1234'
'45o7'
Run Code Online (Sandbox Code Playgroud)

第一行将正常连接,但第二行将抛出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

只有你可以决定这是否值得付出努力.