ORA-01008:并非所有变量都绑定。他们受到约束

时间:2011-09-20 23:36:03

标签: oracle data-binding oracle9i ora-01008

我遇到了一个Oracle问题,到目前为止我无法找到原因。 下面的查询适用于Oracle SQL开发人员,但在.NET中运行时会抛出:

  

ORA-01008:并非所有变量都绑定

我试过了:

  • 更改lot_priority(Varchar2或int32)的Oracle数据类型。
  • 更改lot_priority(string或int)的.NET数据类型。
  • 在查询中使用两次绑定变量名称。这不是我的问题 在多个中使用相同绑定变量的其他查询 位置,但只是为了确保我尝试制作第二个实例 拥有不同的变量:name并单独绑定它。
  • 绑定变量的几种不同方法(参见注释代码; 还有其他)。
  • 移动bindByName()调用。
  • 用文字替换每个绑定变量。我有两个独立的变量导致问题(:lot_pri和:lot_priprc)。在两者之间我记不起一些小的变化。更改为文字使查询起作用,但它们确实需要使用绑定。

查询和代码如下。变量名已被更改以保护无辜者:

SELECT rf.myrow floworder, rf.stage, rf.prss,
rf.pin instnum, rf.prid, r_history.rt, r_history.wt
FROM
(
    SELECT sub2.myrow, sub2.stage, sub2.prss, sub2.pin, sub2.prid
    FROM (
        SELECT sub.myrow, sub.stage, sub.prss, sub.pin,
            sub.prid, MAX(sub.target_rn) OVER (ORDER BY sub.myrow) target_row
            ,sub.hflag
        FROM (
            WITH floc AS 
            (
                SELECT flow.prss, flow.seq_num
                FROM rpf@mydblink flow
                WHERE flow.parent_p = :lapp
                AND flow.prss IN (
                    SELECT r_priprc.prss
                    FROM r_priprc@mydblink r_priprc
                    WHERE priprc = :lot_priprc
                )
                AND rownum = 1
            )
            SELECT row_number() OVER (ORDER BY pp.seq_num, rpf.seq_num) myrow,
                rpf.stage, rpf.prss, rpf.pin,
                rpf.itype, hflag,
            CASE WHEN rpf.itype = 'SpecialValue'
                THEN rpf.instruction
                ELSE rpf.parent_p
            END prid,
            CASE WHEN rpf.prss = floc.prss
                AND rpf.seq_num = floc.seq_num
                THEN row_number() OVER (ORDER BY pp.seq_num, rpf.seq_num)
            END target_rn
            FROM floc, rpf@mydblink rpf
            LEFT OUTER JOIN r_priprc@mydblink pp
                ON (pp.prss = rpf.prss)
            WHERE pp.priprc = :lot_priprc
            ORDER BY pp.seq_num, rpf.seq_num
        ) sub
    ) sub2
    WHERE sub2.myrow >= sub2.target_row
    AND sub2.hflag = 'true'
) rf
LEFT OUTER JOIN r_history@mydblink r_history
ON (r_history.lt = :lt
    AND r_history.pri = :lot_pri
    AND r_history.stage = rf.stage
    AND r_history.curp = rf.prid
)
ORDER BY myrow

public void runMyQuery(string lot_priprc, string lapp, string lt, int lot_pri) {
Dictionary<int, foo> bar = new Dictionary<int, foo>();
using(var con = new OracleConnection(connStr)) {
    con.Open();

    using(var cmd = new OracleCommand(sql.rtd_get_flow_for_lot, con)) { // Query stored in sql.resx
        try {
            cmd.BindByName = true;
            cmd.Prepare();
            cmd.Parameters.Add(new OracleParameter("lapp", OracleDbType.Varchar2)).Value = lapp;
            cmd.Parameters.Add(new OracleParameter("lot_priprc", OracleDbType.Varchar2)).Value = lot_priprc;
            cmd.Parameters.Add(new OracleParameter("lt", OracleDbType.Varchar2)).Value = lt;
            // Also tried OracleDbType.Varchar2 below, and tried passing lot_pri as an integer
            cmd.Parameters.Add(new OracleParameter("lot_pri", OracleDbType.Int32)).Value = lot_pri.ToString();
            /*********** Also tried the following, more explicit code rather than the 4 lines above: **
            OracleParameter param_lapp
                = cmd.Parameters.Add(new OracleParameter("lapp", OracleDbType.Varchar2));
            OracleParameter param_priprc
                = cmd.Parameters.Add(new OracleParameter("lot_priprc", OracleDbType.Varchar2));
            OracleParameter param_lt
                = cmd.Parameters.Add(new OracleParameter("lt", OracleDbType.Varchar2));
            OracleParameter param_lot_pri
                = cmd.Parameters.Add(new OracleParameter("lot_pri", OracleDbType.Varchar2));
            param_lapp.Value = lastProcedureStackProcedureId;
            param_priprc.Value = lotPrimaryProcedure;
            param_lt.Value = lotType;
            param_lot_pri.Value = lotPriority.ToString();
            //***************************************************************/
            var reader = cmd.ExecuteReader();
            while(reader.Read()) {
                // Get values from table (Never reached)
            }
        }
        catch(OracleException e) {
            //     ORA-01008: not all variables bound
        }
    }
}

为什么Oracle声称并非所有变量都受到约束?

8 个答案:

答案 0 :(得分:14)

我找到了如何毫无错误地运行查询,但我毫不犹豫地将其称为“解决方案”而没有真正了解其根本原因。

这更类似于我实际查询的开头:

-- Comment
-- More comment
SELECT rf.flowrow, rf.stage, rf.process,
rf.instr instnum, rf.procedure_id, rtd_history.runtime, rtd_history.waittime
FROM
(
    -- Comment at beginning of subquery
    -- These two comment lines are the problem
    SELECT sub2.flowrow, sub2.stage, sub2.process, sub2.instr, sub2.pid
    FROM ( ...

上面的第二组评论是在子查询的开头,是问题所在。删除后,将执行查询。其他评论很好。 这不是某个流氓或缺少换行的问题,导致以下行被注释,因为以下行是SELECT。丢失的选择将产生与“并非所有变量绑定”不同的错误。

我四处询问,发现有一个同事遇到了这个 - 导致查询失败的评论 - 多次。 有谁知道这可能是什么原因?我的理解是,DBMS对注释做的第一件事是查看它们是否包含提示,如果没有,则在解析期间删除它们。包含没有异常字符(只是字母和句点)的普通评论如何导致错误?奇异。

答案 1 :(得分:8)

我知道这是一个老问题,但它没有得到正确解决,因此我会为可能遇到此问题的其他人回答这个问题。

默认情况下,Oracle的ODP.net按位置绑定变量,并将每个位置视为新变量。

将每个副本视为一个不同的变量并多次设置它的值是一种变通方法和一种痛苦,正如furman87所提到的那样,如果你试图重写查询并移动一些东西,可能会导致错误。

正确的方法是将OracleCommand的BindByName属性设置为true,如下所示:

var cmd = new OracleCommand(cmdtxt, conn);
cmd.BindByName = true;

您还可以创建一个新类来封装OracleCommand,在实例化时将BindByName设置为true,因此您不必每次都设置该值。这在this帖子

中讨论

答案 2 :(得分:7)

你有两个引用:lot_priprc绑定变量 - 虽然它 要求你只设置变量的值一次并在两个地方绑定它,我有问题,这没有'工作,不得不将每个副本视为一个不同的变量。痛苦,但它奏效了。

答案 3 :(得分:1)

关于查尔斯的评论问题:更糟糕的是,让

:p1 = 'TRIALDEV'

通过命令参数,然后执行

select T.table_name as NAME, COALESCE(C.comments, '===') as DESCRIPTION
from all_all_tables T
Inner Join all_tab_comments C on T.owner = C.owner and T.table_name = C.table_name
where Upper(T.owner)=:p1
order by T.table_name

558 line(s) affected. Processing time: 00:00:00.6535711

并将文字字符串从===更改为---

select T.table_name as NAME, COALESCE(C.comments, '---') as DESCRIPTION
[...from...same-as-above...]

ORA-01008: not all variables bound

两个语句在SQL Developer中都可以正常运行。缩短的代码:

            Using con = New OracleConnection(cs)
                con.Open()
                Using cmd = con.CreateCommand()
                    cmd.CommandText = cmdText
                    cmd.Parameters.Add(pn, OracleDbType.NVarchar2, 250).Value = p
                    Dim tbl = New DataTable
                    Dim da = New OracleDataAdapter(cmd)
                    da.Fill(tbl)
                    Return tbl
                End Using
            End Using

在.Net 4.61平台上使用Oracle.ManagedDataAccess.dll版本4.121.2.0和VS2015中的默认设置。

所以在调用链的某个地方,可能会有一个解析器在commandText中有点过于积极地寻找由 - 启动的单行注释。但即使这是真的,错误信息“并非所有变量绑定”至少具有误导性。

答案 4 :(得分:1)

这是托管ODP.net中的一个错误 - 修补程序23530387中已修复'Bug 21113901 : MANAGED ODP.NET RAISE ORA-1008 USING SINGLE QUOTED CONST + BIND VAR IN SELECT'已被修补程序24591642取代

答案 5 :(得分:1)

来这里寻求帮助的原因是在进行Udemy课程时运行下面列出的语句时遇到相同的错误:

INSERT INTO departments (department_id, department_name)
                  values( &dpet_id, '&dname');  

我以前能够运行带有替换变量的语句。 Charles Burns关于重新创建变量时服务器达到某个阈值的可能性的评论促使我注销并重新启动SQL Developer。重新登录后,该语句运行良好。

我想和其他在这里遇到有限问题的人分享我的经验。

答案 6 :(得分:1)

我所处的解决方案与Charles Burns的答案相似;并且问题与SQL代码注释有关。

我正在使用Oracle数据源构建(或更新)已经运行的SSRS报告。我向报表添加了更多参数,并在Visual Studio中对其进行了测试,效果很好,因此我将其部署到了报表服务器,然后在报表上执行时,服务器上的报表出现错误消息:

  

“ ORA-01008:并非所有变量都已绑定”

我尝试了很多不同的操作(服务器上安装了TNSNames.ora文件,删除了单行注释,验证了数据集查询映射)。结果是我不得不 WHERE keyword之后直接删除评论块 。在 WHERE CLAUSE conditions之后移动注释块 后,错误消息已解决。我在代码中还有其他注释。它只是导致错误的WHERE关键字之后的那个。

SQL,错误:“ ORA-01008:并非所有变量都已绑定” ...

WHERE
/*
    OHH.SHIP_DATE BETWEEN TO_DATE('10/1/2018', 'MM/DD/YYYY') AND TO_DATE('10/31/2018', 'MM/DD/YYYY')
    AND OHH.STATUS_CODE<>'DL'
    AND OHH.BILL_COMP_CODE=100
    AND OHH.MASTER_ORDER_NBR IS NULL
*/

    OHH.SHIP_DATE BETWEEN :paramStartDate AND :paramEndDate
    AND OHH.STATUS_CODE<>'DL'
    AND OHH.BILL_COMP_CODE IN (:paramCompany)
    AND LOAD.DEPART_FROM_WHSE_CODE IN (:paramWarehouse) 
    AND OHH.MASTER_ORDER_NBR IS NULL
    AND LOAD.CLASS_CODE IN (:paramClassCode) 
    AND CUST.CUST_CODE || '-' || CUST.CUST_SHIPTO_CODE IN (:paramShipto) 

SQL在报表服务器上成功执行...

WHERE
    OHH.SHIP_DATE BETWEEN :paramStartDate AND :paramEndDate
    AND OHH.STATUS_CODE<>'DL'
    AND OHH.BILL_COMP_CODE IN (:paramCompany)
    AND LOAD.DEPART_FROM_WHSE_CODE IN (:paramWarehouse) 
    AND OHH.MASTER_ORDER_NBR IS NULL
    AND LOAD.CLASS_CODE IN (:paramClassCode) 
    AND CUST.CUST_CODE || '-' || CUST.CUST_SHIPTO_CODE IN (:paramShipto)   
/*
    OHH.SHIP_DATE BETWEEN TO_DATE('10/1/2018', 'MM/DD/YYYY') AND TO_DATE('10/31/2018', 'MM/DD/YYYY')
    AND OHH.STATUS_CODE<>'DL'
    AND OHH.BILL_COMP_CODE=100
    AND OHH.MASTER_ORDER_NBR IS NULL
*/

这是数据集参数映射屏幕的外观。

enter image description here

答案 7 :(得分:0)

我在传统应用程序中遇到了类似的问题,但de&#34; - &#34;是字符串参数。

例:

Dim cmd As New OracleCommand("INSERT INTO USER (name, address, photo) VALUES ('User1', '--', :photo)", oracleConnection)
Dim fs As IO.FileStream = New IO.FileStream("c:\img.jpg", IO.FileMode.Open)
Dim br As New IO.BinaryReader(fs)
cmd.Parameters.Add(New OracleParameter("photo", OracleDbType.Blob)).Value = br.ReadBytes(fs.Length)
cmd.ExecuteNonQuery() 'here throws ORA-01008

更改地址参数值&#39; - &#39;到&#39; 00&#39;或其他事情,工作。