2

我们正在构建一个客户端程序,其中存储在具有 Oracle 后端的 Web 服务器中的参数在 .Net 客户端程序中设置,并通过 Web 服务作为数据集上传。

在 Web 服务代码中,从数据集中读取数据并添加到 Web 服务器(Oracle 后端)上的 UPDATE 语句中。

因为服务器将在防火墙后面的客户 LAN 上运行,并且由于所涉及参数的动态特性,所以没有使用存储过程 - SQL 字符串内置在逻辑中。

这是一个示例字符串:

UPDATE WorkOrders 
   SET TravelTimeHours = :TravelTimeHours, 
       TravelTimeMinutes = :TravelTimeMinutes,  
       WorkTimeHours = :WorkTimeHours, 
       WorkTimeMinutes = :WorkTimeMinutes, 
       CompletedPersonID = :CompletedPersonID, 
       CompletedPersonName = :CompletedPersonName, 
       CompleteDate = :CompleteDate 
 WHERE WorkOrderNumber = :WorkOrderNumber

在 VS 2010 中调试代码并进入服务器代码时,我们收到以下错误:

ORA-01036: illegal variable name/number

在目标 oracle 机器上执行 SQL 命令时,系统提示我们输入上述语句的绑定变量,只要我们使用正确的日期格式,UPDATE 语句就可以正常工作。

问题:

1)当月份格式错误时,oracle是否有可能抛出ORA-01036错误?

2) 为什么我们不必从运行在 Oracle 机器上的 ASP.net 网站转换日期格式?Oracle 是否有排除绑定变量输入屏幕的默认转换例程?

3) 如果日期格式不是问题,ORA-1036 究竟是什么意思,我如何发现 WHICH 变量的名称/编号是非法的?


这是一个函数片段,它采用数据集的类型 (WOName) 并返回适当的 SQL 字符串。许多案例存在,但为了便于阅读已被删除。

Private Function GetMainSQLString(ByVal WOName As String) As String
    Dim Result As String = ""
    Select Case WOName
        Case "Monthly Site Inspection"              
            Dim sb As New StringBuilder
            sb.Append("UPDATE WorkOrders SET ")
            sb.Append("CompletedPersonID = :CompletedPersonID, CompletedPersonName = :CompletedPersonName, CompleteDate = :CompleteDate, ")
            sb.Append("SupervisorID = :SupervisorID, SupervisorName = :SupervisorName ")
            sb.Append("WHERE WorkOrderNumber = :WorkOrderNumber")
            Result = sb.ToString
    End Select
    Return Result
End Function

这是一个函数片段,它接受 Oracle 命令对象 byRef 并向其添加所需的参数,具体取决于从客户端程序接收到的可能的 15 种数据集(WOName)中的哪一种。许多案例存在,但为了便于阅读已被删除。

然后将更新后的 Cmd 对象返回到调用 ExecuteNonQuery() 的主程序逻辑。

下面params的测试值如下:

dr.Item("CompletedPersonID")    21
dr.Item("CompletedPersonName")  Pers Name
dr.Item("CompleteDate")     #8/16/2010#
dr.Item("SupervisorID")     24
dr.Item("SupervisorName")   Sup Name
dr.Item("WorkOrderNumber")  100816101830


Private Function addMainCmdParams(ByVal WOName As String, ByRef cmd As OracleCommand, ByVal dr As DataRow) As OracleCommand
    Select Case WOName
        Case "Monthly Site Inspection"              
            cmd.Parameters.Add(":CompletedPersonID", Oracle.DataAccess.Client.OracleDbType.Int32).Value = dr.Item("CompletedPersonID")
            cmd.Parameters.Add(":CompletedPersonName", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("CompletedPersonName")
            cmd.Parameters.Add(":CompleteDate", Oracle.DataAccess.Client.OracleDbType.Date).Value = dr.Item("CompleteDate")
            cmd.Parameters.Add(":SupervisorID", Oracle.DataAccess.Client.OracleDbType.Int32).Value = dr.Item("SupervisorID")
            cmd.Parameters.Add(":SupervisorName", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("SupervisorName")
            cmd.Parameters.Add(":WorkOrderNumber", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("WorkOrderNumber")
    End Select
    Return cmd
End Function

今天运行它时,这个精确的代码是成功的;但另一个类似的情况不是。我仍然不相信 Oracle 执行的任何隐式类型转换(如果有的话)——我特别怀疑 Oracle 如何处理通过 dbNull.value 传递的任何这些参数——我知道它会发生。所以如果这是问题,我将不得不解决它。有太多的可选参数和列并不总是让这个系统传入的值在空值上中断。

4

3 回答 3

3

一个可能导致此错误的 Oracle “陷阱”是这样一个事实,即默认情况下,Oracle 按顺序而不是名称将参数映射到查询中的参数符号。如果参数的数量/类型不匹配,则会出现类似这样的错误。

解决方案是告诉 Oracle 按名称绑定:

cmd.BindByName = true

在不深入了解代码细节的情况下,这可能是也可能不是您特定问题的答案,但此设置应该是默认设置,并且应该是任何使用参数的命令设置的一部分。看到这句话解决了一些晦涩难懂的问题,真是太神奇了。

编辑:这假设您正在使用 Oracle 的数据访问提供程序。在 .NET 中,您应该使用它,而不是 Microsoft 的 Oracle 提供程序。

于 2010-08-17T12:17:30.993 回答
1

该错误与日期格式无关,这意味着语句中的变量未绑定。

可能就像拼写错误一样简单(如果 Oracle 在错误消息中包含变量名会很好)。

你能用创建、绑定和执行语句的周围代码来更新你的问题吗?

于 2010-08-16T02:10:13.600 回答
-1

这是一个函数片段,它采用数据集的类型 (WOName) 并返回适当的 SQL 字符串。许多案例存在,但为了便于阅读已被删除。

Private Function GetMainSQLString(ByVal WOName As String) As String
    Dim Result As String = ""
    Select Case WOName
        Case "Monthly Site Inspection"              
            Dim sb As New StringBuilder
            sb.Append("UPDATE WorkOrders SET ")
            sb.Append("CompletedPersonID = :CompletedPersonID, CompletedPersonName = :CompletedPersonName, CompleteDate = :CompleteDate, ")
            sb.Append("SupervisorID = :SupervisorID, SupervisorName = :SupervisorName ")
            sb.Append("WHERE WorkOrderNumber = :WorkOrderNumber")
            Result = sb.ToString
    End Select
    Return Result
End Function

这是一个函数片段,它接受 Oracle 命令对象 byRef 并向其添加所需的参数,具体取决于从客户端程序接收到的可能的 15 种数据集(WOName)中的哪一种。许多案例存在,但为了便于阅读已被删除。

然后将更新后的 Cmd 对象返回到调用 ExecuteNonQuery() 的主程序逻辑。

下面params的测试值如下:

dr.Item("CompletedPersonID")    21
dr.Item("CompletedPersonName")  Pers Name
dr.Item("CompleteDate")     #8/16/2010#
dr.Item("SupervisorID")     24
dr.Item("SupervisorName")   Sup Name
dr.Item("WorkOrderNumber")  100816101830


Private Function addMainCmdParams(ByVal WOName As String, ByRef cmd As OracleCommand, ByVal dr As DataRow) As OracleCommand
    Select Case WOName
        Case "Monthly Site Inspection"              
            cmd.Parameters.Add(":CompletedPersonID", Oracle.DataAccess.Client.OracleDbType.Int32).Value = dr.Item("CompletedPersonID")
            cmd.Parameters.Add(":CompletedPersonName", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("CompletedPersonName")
            cmd.Parameters.Add(":CompleteDate", Oracle.DataAccess.Client.OracleDbType.Date).Value = dr.Item("CompleteDate")
            cmd.Parameters.Add(":SupervisorID", Oracle.DataAccess.Client.OracleDbType.Int32).Value = dr.Item("SupervisorID")
            cmd.Parameters.Add(":SupervisorName", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("SupervisorName")
            cmd.Parameters.Add(":WorkOrderNumber", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("WorkOrderNumber")
    End Select
    Return cmd
End Function

今天运行它时,这个精确的代码是成功的;但另一个类似的情况不是。我仍然不相信 Oracle 执行的任何隐式类型转换(如果有的话)——我特别怀疑 Oracle 如何处理通过 dbNull.value 传递的任何这些参数——我知道它会发生。所以如果这是问题,我将不得不解决它。有太多的可选参数和列并不总是让这个系统传入的值在空值上中断。

于 2010-08-16T21:41:32.723 回答