36

我遇到了一个 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 声称并非所有变量都是绑定的?

4

8 回答 8

22

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

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

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

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

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

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

于 2015-06-22T14:45:52.230 回答
19

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

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

-- 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 对注释所做的第一件事就是查看它们是否包含提示,如果没有,则在解析期间将其删除。不包含异常字符(只有字母和句点)的普通注释如何导致错误?奇怪。

于 2011-09-24T23:41:32.250 回答
8

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

于 2011-09-21T13:17:48.010 回答
2

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

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

于 2016-01-04T18:35:39.403 回答
2

在我的情况下,解决方案与查尔斯伯恩斯的答案相似;问题与 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
*/

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

在此处输入图像描述

于 2018-12-06T14:18:48.600 回答
1

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

于 2017-06-16T11:06:13.673 回答
1

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

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

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

以为我会与其他在我的范围有限的问题上冒险的人分享。

于 2018-10-01T02:17:23.033 回答
0

我在遗留应用程序中会遇到类似的问题,但 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' 或其他东西,有效。

于 2016-06-08T16:58:05.363 回答