【问题标题】:Oracle database - ORA-01460 - unimplemented or unreasonable conversion requestedOracle 数据库 - ORA-01460 - 请求的转换未实现或不合理
【发布时间】:2011-12-29 15:47:50
【问题描述】:

我收到一条错误消息:使用以下代码请求未实现或不合理的转换:

OdbcConnection oConn = new OdbcConnection();
oConn.ConnectionString = @"Driver={Oracle ODBC Driver};Data Source=*****;UID=********;PWD=******;DBQ=*****;DBA=R;APA=T;FEN=T;QTO=F;FRC=10;FDL=10;LOB=F;RST=T;FRL=T;MTS=F;CSR=F;PFC=10;TLO=0;";

oConn.Open();

string user = "ANYUSER";
string family = "ANYFAMILY";
DateTime date = DateTime.Today;

OdbcCommand FindCases = new OdbcCommand(@"select TABLE_CASE.ID_NUMBER, TABLE_USER.LOGIN_NAME
                                          from TABLE_CASE, TABLE_USER, TABLE_PRIVCLASS, TABLE_CONDITION, TABLE_PART_NUM
                                          where TABLE_CASE.CASE_ORIGINATOR2USER=TABLE_USER.OBJID and TABLE_CASE.CASE_STATE2CONDITION=TABLE_CONDITION.OBJID and TABLE_CASE.CASE_PRT2PART_INFO=TABLE_PART_NUM.OBJID
                                          and TABLE_USER.USER_ACCESS2PRIVCLASS=TABLE_PRIVCLASS.OBJID and TABLE_USER.LOGIN_NAME=? and TABLE_PART_NUM.FAMILY=? and TABLE_CONDITION.S_TITLE='CLOSED' and TABLE_CASE.CREATION_TIME > to_date(?,'MM/DD/YYYY HH:MI:SS AM')", oConn);

FindCases.CommandType = System.Data.CommandType.Text;
FindCases.Parameters.Add(@"user", OdbcType.Text, 4000).Value = user;
FindCases.Parameters.Add(@"family", OdbcType.Text, 4000).Value = family;
FindCases.Parameters.Add(@"date", OdbcType.DateTime, 4000).Value = date;

if (oConn.State == System.Data.ConnectionState.Open)
{
     try
     {
         OdbcDataReader readCases = FindCases.ExecuteReader(); //errors at this line

我在网上四处查看,唯一能找到的建议是使用 to_clob 语句。要么我不明白它是如何工作的,要么不能解决问题。据我所知,不应该涵盖任何数据类型。 'user'字段为文本,'family'字段为文本,'date'字段为数据库中的DateTime。

非常感谢任何想法!

更新 此代码有效:

OdbcCommand FindCases = new OdbcCommand(@"select TABLE_CASE.ID_NUMBER, TABLE_USER.LOGIN_NAME
                                                    from TABLE_CASE, TABLE_USER, TABLE_PRIVCLASS, TABLE_CONDITION, TABLE_PART_NUM
                                                    where TABLE_CASE.CASE_ORIGINATOR2USER=TABLE_USER.OBJID and TABLE_CASE.CASE_STATE2CONDITION=TABLE_CONDITION.OBJID and TABLE_CASE.CASE_PRT2PART_INFO=TABLE_PART_NUM.OBJID
                                                    and TABLE_USER.USER_ACCESS2PRIVCLASS=TABLE_PRIVCLASS.OBJID and TABLE_USER.LOGIN_NAME=? and TABLE_PART_NUM.FAMILY='Desktop' and TABLE_CONDITION.S_TITLE='CLOSED' and TABLE_CASE.CREATION_TIME > ?", oConn);

        FindCases.CommandType = System.Data.CommandType.Text;
        FindCases.Parameters.Add(@"user", OdbcType.Text, 4000).Value = user;
        //FindCases.Parameters.Add(@"family", OdbcType.Text, 4000).Value = family;
        FindCases.Parameters.Add(@"date", OdbcType.DateTime, 4000).Value = date;

更新(再次)

尽管易受 SQL 注入攻击,但此代码也能正常运行。

        OdbcCommand FindCases = new OdbcCommand(@"select TABLE_CASE.ID_NUMBER
                                                    from TABLE_CASE, TABLE_USER, TABLE_PRIVCLASS, TABLE_CONDITION, TABLE_PART_NUM
                                                    where TABLE_CASE.CASE_ORIGINATOR2USER=TABLE_USER.OBJID and TABLE_CASE.CASE_STATE2CONDITION=TABLE_CONDITION.OBJID and TABLE_CASE.CASE_PRT2PART_INFO=TABLE_PART_NUM.OBJID
                                                    and TABLE_USER.USER_ACCESS2PRIVCLASS=TABLE_PRIVCLASS.OBJID and TABLE_USER.LOGIN_NAME=? and TABLE_PART_NUM.FAMILY='" + family + "' and TABLE_CONDITION.S_TITLE='CLOSED' and TABLE_CASE.CREATION_TIME > ?", oConn);

        FindCases.CommandType = System.Data.CommandType.Text;
        FindCases.Parameters.Add(@"user", OdbcType.Text, 4000).Value = user; //field size 30, text
        //FindCases.Parameters.Add(@"family", OdbcType.Text, 4000).Value = family; //field size 20, text
        FindCases.Parameters.Add(@"date", OdbcType.DateTime, 4000).Value = date;

解决方案

我没有意识到“文本”不是真正的类型。改成 NVARCHAR 就行了:

        OdbcCommand FindCases = new OdbcCommand(@"select TABLE_CASE.ID_NUMBER
                                                    from TABLE_CASE, TABLE_USER, TABLE_CONDITION, TABLE_PART_NUM
                                                    where TABLE_CASE.CASE_ORIGINATOR2USER=TABLE_USER.OBJID and TABLE_CASE.CASE_STATE2CONDITION=TABLE_CONDITION.OBJID and TABLE_CASE.CASE_PRT2PART_INFO=TABLE_PART_NUM.OBJID
                                                    and TABLE_USER.LOGIN_NAME=? and TABLE_PART_NUM.FAMILY=? and TABLE_CONDITION.S_TITLE='CLOSED' and TABLE_CASE.CREATION_TIME > ?", oConn);

        FindCases.CommandType = System.Data.CommandType.Text;
        FindCases.Parameters.Add(@"user", OdbcType.NVarChar, 30).Value = user; //field size 30, text
        FindCases.Parameters.Add(@"family", OdbcType.NVarChar, 20).Value = family; //field size 20, text
        FindCases.Parameters.Add(@"date", OdbcType.DateTime, 4000).Value = date;

【问题讨论】:

  • 我取出了“family”变量,并将其替换为我正在寻找的一个家庭,它按预期运行。我放入家庭变量的方式一定有问题,但我不知道它可能是什么
  • 你失败的例子有family = "ANYFAMILY",你成功的例子有FAMILY='Desktop'。如果问题取决于查询找到的记录,则可能值得在这两种方法中尝试相同的系列。 (Oracle 经常执行对某些值有效但对其他值无效的隐式强制转换。例如,将数字与字符串进行比较,只要字符串可以转换为数字就可以正常工作,但如果不能转换,则会中断。)

标签: c# oracle


【解决方案1】:

一些问题、猜测和建议……

TABLE_PART_NUM.FAMILY 的确切 DDL SQL 类型是什么?

您是否尝试过使用OdbcType.VarCharOdbcType.NVarChar 甚至OdbcType.NText 而不是OdbcType.Text

另外,请注意,默认情况下 NVARCHAR2 大小以字符为单位,而 VARCHAR2 以字节为单位 - 可能您的代码中的“4000”被解释为 4000 个字符,超过了字符数据的最大字段宽度4000 字节。仅出于测试目的尝试使用 2000 甚至更低的数字。

尝试从 SQL Developer 执行查询。你有什么问题吗?

您是否在数据库中使用了任何“不寻常”的字符编码?你可以执行...

SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER LIKE '%CHARACTERSET';

...查看NLS_CHARACTERSET 的VARCHAR2 编码和NLS_NCHAR_CHARACTERSET 的NVARCHAR2 编码。

您的 ODBC 驱动程序和 Oracle 服务器的确切版本是什么?它们匹配吗?

如果您尝试使用等效的 ODP.NET 代码,是否会遇到此问题?

【讨论】:

    【解决方案2】:

    怀疑是因为你在用这个:

    TABLE_CASE.CREATION_TIME > to_date(?,'MM/DD/YYYY HH:MI:SS AM')
    

    它需要一个 string 参数,但您已经传入了 DateTime 值:

    FindCases.Parameters.Add(@"date", OdbcType.DateTime, 4000).Value = date;
    

    我怀疑你可以改变你的 SQL 来使用:

    TABLE_CASE.CREATION_TIME > ?
    

    【讨论】:

    • 感谢您的回复。我没有运气就尝试过你的建议。我只试过“TABLE_CASE.CREATION_TIME > ?”以及使用我的原始声明,但将类型更改为文本:
    • @DarkShadow:你不应该做任何你不需要的字符串转换——所以我建议的改变应该是你最好的选择,IMO。你说你“没有运气”尝试过 - 这是否意味着你得到了同样的例外?
    • 是的,当我更改为:TABLE_CASE.CREATION_TIME > 时仍然出现相同的异常?
    • @DarkShadow:我认为使用 just CREATION_TIME 执行查询是值得的,以检查这确实是导致问题的参数 - 基本上,简化事情直到你有最简单的可能的查询来证明问题,然后尝试其他选项会更容易。 CREATION_TIME 的类型是什么?
    • 感谢所有帮助...日期似乎没问题。我尝试了相同的查询,但为家庭输入了一个静态值,它可以工作。必须和家人一起做点什么,但我不知道是什么。
    【解决方案3】:

    使用下面的示例代码。您需要创建临时 LOB。这对我有用

    using System.Data.OracleClient;
    
    OracleConnection objConnection = new OracleConnection();
    OracleCommand objCommand = new OracleCommand();
    try
    {
        objConnection.ConnectionString = System.Configuration.ConfigurationManager.AppSettings["YourConnectionString"].ToString();
    
        if (objConnection.State != System.Data.ConnectionState.Open)
        {
            objConnection.Open();
        }
    
        objCommand.Connection = objConnection;
    
        //Create Temporary LOB @Start
        //Error Without Temp LOB { ORA-01460: unimplemented or unreasonable conversion requested }
        objCommand.CommandText = "DECLARE dpBlob BLOB; BEGIN DBMS_LOB.CREATETEMPORARY(dpBlob, False, 0); :tmpBlob := dpBlob; END;";
        objCommand.Parameters.Add(new OracleParameter("tmpBlob", OracleType.Blob)).Direction = System.Data.ParameterDirection.Output;
        objCommand.ExecuteNonQuery();
        OracleLob tempLob = default(OracleLob);
        tempLob = (OracleLob)objCommand.Parameters[0].Value;
        tempLob.BeginBatch(OracleLobOpenMode.ReadWrite);
        tempLob.EndBatch();
        objCommand.Parameters.Clear();
        //Create Temporary LOB @End
    
        objCommand.CommandType = System.Data.CommandType.StoredProcedure;
        objCommand.CommandText = "INSERT_BLOB";
    
        objCommand.Parameters.AddWithValue("IN_USERNAME", "Sample Name");
        objCommand.Parameters.AddWithValue("IN_UPLOADED_BY", "Sample Name");
    
        string excelFileName = FileUpload1.PostedFile.FileName;
        int intlength = FileUpload1.PostedFile.ContentLength;
    
        Byte[] byteData = new Byte[intlength];
        FileUpload1.PostedFile.InputStream.Read(byteData, 0, intlength);
    
        objCommand.Parameters.AddWithValue("IN_ATTACH_FILE_ORIGINAL", excelFileName);
        objCommand.Parameters.Add("IN_ATTACH_BLOB_ORIGINAL", OracleType.Blob).Value = tempLob;
    
        objCommand.ExecuteNonQuery();
    
    }
    catch (Exception ex)
    {
    }
    finally
    {
        objCommand.Parameters.Clear();
        if (objConnection.State != System.Data.ConnectionState.Closed)
            objConnection.Close();
    }
    

    【讨论】:

      猜你喜欢
      • 2020-06-28
      • 2012-06-17
      • 2015-10-14
      • 1970-01-01
      • 2018-08-23
      • 1970-01-01
      • 1970-01-01
      • 2014-12-15
      • 2011-12-09
      相关资源
      最近更新 更多