ORA-01008: 并非所有变量都绑定。他们被束缚

Posted

技术标签:

【中文标题】ORA-01008: 并非所有变量都绑定。他们被束缚【英文标题】:ORA-01008: not all variables bound. They are bound 【发布时间】:2011-11-21 12:34:11 【问题描述】:

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

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

我试过了:

更改 lot_priority 的 Oracle 数据类型(Varchar2 或 int32)。 更改 lot_priority 的 .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 声称并非所有变量都是绑定的?

【问题讨论】:

您是否尝试过以下清单? collecteddotnet.wordpress.com/2009/05/10/… 您使用的是什么版本的 Oracle 客户端? Oracle ODP.Net 11.1.x 版存在绑定参数问题,已通过 Oracle 11.2.x 解决。 NullUserException:感谢您的链接。我在谷歌搜索中遇到过,但没有应用。 tsells:我会检查版本。感谢您的建议。 一些 Oracle 文档将 Prepare() 描述为无操作。但是,如果不是,那就是在错误的地方。只有在知道所有参数名称和类型之后,语句准备才有意义。这些值可以稍后提供。 tsells:我使用的是最新的 ODP.NET。太糟糕了——这看起来很有希望。 【参考方案1】:

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

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

正如 furman87 所提到的,将每个副本视为不同的变量并多次设置它的值是一种解决方法和痛苦,如果您尝试重写查询并四处移动,可能会导致错误。

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

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

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

【讨论】:

BindByName 在我遇到此 Oracle 缺陷的所有情况下都已设置为 true。除了最琐碎的查询之外,Oracle 的默认设置使其几乎无法使用,要求每次更改查询时都更新代码。 哇,这很奇怪,因为这对我来说很好用。您是否安装了最新的 ODP 客户端驱动程序?如果是这样,您可能需要向 Oracle 开票并根据您的特定场景和设置报告错误。 我们也不会每次都出现这个问题。在一个案例中,我们有一个运行良好多年的查询,然后突然出现了这个问题,没有对软件或数据库进行任何更改。必须达到优化器中设置的某种阈值。至于 Oracle 的支持,使用 Itanium 汇编语言修补内存中的 bug 比处理它们更容易。 :) +1 到您的解决方案@VijayJagdale - 我没有在其他任何地方遇到过这些信息,它解决了我遇到的严重、令人困惑的问题,即使它与 OP 的不同。干杯^_^ 感谢 Curmudgeon。你是对的,这是非常混乱和严重的。当 Oracle 尝试以不同的顺序绑定变量时,它会给出奇怪的错误(如 ORA1722-invalid number),或者更糟的是,它返回错误的选择结果,或者插入/更新/删除的值错误,这很难弄清楚,如果您不知道绑定变量不同步。【参考方案2】:

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

这更接近于我实际查询的开头:

-- 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 ( ...

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

我四处打听,发现一位同事多次遇到这种情况——cmets 导致查询失败。 有谁知道这可能是原因吗?据我了解,DBMS 对 cme​​ts 所做的第一件事就是查看它们是否包含提示,如果没有,则在解析期间将其删除。不包含异常字符(只有字母和句点)的普通注释如何导致错误?奇怪。

【讨论】:

您在 Oracle 支持网站上搜索过这个吗?我感觉这与绑定错误有关。您使用的是哪个版本的 11(包括补丁版本)? 我在 VS2010 SP1 的 .NET 4 中使用 32 位 ODAC 11.2 Release 3 (11.2.0.2.1)。服务器本身如下:Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production PL/SQL Release 9.2.0.4.0 - Production TNS for Solaris: Version 9.2.0.4.0 - Production NLSRTL Version 9.2.0.4.0 -生产 遇到此问题的同事不以任何方式使用 .NET(他仅在 Toad 中使用 Oracle)。我没有搜索过 Oracle 支持站点。一旦这个项目接近完成,我就必须这样做。据我所知,这是相当典型的 Oracle 体验。 这是 R9 中的一个错误。当新版本的 oracle (odp) 出现时,我们的应用程序也遇到了同样的问题,我们不得不放弃对它的支持。 Oracle 不会承认这是一个官方错误。他们告诉我们必须“更改”查询。 我遇到了同样的问题,这对我有用。我的评论在最外层查询的 select 子句中。非常感谢发帖。 在 NuGet 上使用 Oracle.ManagedDataAccess 12.1.2400(文件产品版本 4.121.2.20150926)时,我们没有该错误,但是对于当前 12.2.1100 的较新版本,我们现在有了它。 . 多么蹩脚。【参考方案3】:

你有两个对 :lot_priprc 绑定变量的引用——虽然它应该要求你只设置一次变量的值并在两个地方绑定它,但我遇到了这个没有的问题t 工作并且必须将每个副本视为不同的变量。很痛苦,但它奏效了。

【讨论】:

非常敏锐,当使用查询文本中按位置绑定的疯狂默认设置时,这通常是 Oracle 的问题。不幸的是,我已经尝试过使用两个变量::lot_priprc 和 :lot_priprc2,并分别绑定它们。 太糟糕了,这并不容易,我很想知道解决方案是什么,我会继续思考。听起来你现在已经尝试了几乎所有的东西。我不确定您是否在原始帖子中引用了这一点——我并不总是阅读全文:) 这对我来说是个问题。将 .NET 与最新的 ODP 一起使用,仍然需要这样做,但现在一切都很好。真的很痛苦,因为我在 Insert 中使用了 Case,我不想插入与被评估变量不同的变量。【参考方案4】:

关于查尔斯的评论问题:让事情变得更糟,让

: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 中开始的单行 cmets。但即使这是真的,“并非所有变量都绑定”的错误消息至少具有误导性。

【讨论】:

朋友不要让朋友使用Oracle。【参考方案5】:

在我的情况下,解决方案与 Charles Burns 的答案类似;问题与 SQL 代码 cmets 有关。

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

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

我尝试了很多不同的方法(安装在服务器上的 TNSNames.ora 文件、删除了单行 cmets、验证数据集查询映射)。结果是我必须WHERE keyword 之后直接删除评论块。在将评论块移到WHERE CLAUSE conditions 之后,错误消息得到解决。我的代码中还有其他 cmets。它只是导致错误的 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
*/

这是数据集参数映射屏幕的样子。

【讨论】:

看起来像 s-s-rS?【参考方案6】:

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

【讨论】:

我们在 Java 应用程序中也看到了这个问题。【参考方案7】:

来到这里寻求帮助,因为在学习 Udemy 课程时运行下面列出的语句时遇到了同样的错误:

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

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

我想我会分享给其他人在这里冒险,因为我的范围有限。

【讨论】:

【参考方案8】:

我在旧版应用程序中遇到了类似的问题,但 de "--" 是字符串参数。

例如:

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 作为新的 IO.BinaryReader(fs) cmd.Parameters.Add(New OracleParameter("photo", OracleDbType.Blob)).Value = br.ReadBytes(fs.Length) cmd.ExecuteNonQuery() '这里抛出 ORA-01008

将地址参数值 '--' 更改为 '00' 或其他东西,可以。

【讨论】:

-- 可能被 SQL 解析器解释为注释行

以上是关于ORA-01008: 并非所有变量都绑定。他们被束缚的主要内容,如果未能解决你的问题,请参考以下文章

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

将参数传递给 callableSatament - ORA-01008: 并非所有变量都绑定

Oracle“ORA-01008:并非所有变量都绑定”错误带参数

OracleCommand 查询其中的空参数 - ORA-01008:并非所有变量都绑定

java.sql.SQLException: ORA-01008: 并非所有变量都使用 Mybatis 3 绑定

MyBatis 整合Oracle 报错:java.sql.SQLException: ORA-01008: 并非所有变量都已绑定