【问题标题】:Binding Variable For IN QueriesIN 查询的绑定变量
【发布时间】:2011-08-24 18:32:46
【问题描述】:

在使用绑定变量时,它没有得到值

eg,, SELECT * FROM EMP WHERE USER IN (:VALUES)

如果我使用上面的查询它没有执行

直接传递值

SELECT * FROM EMP WHERE USER IN (+ arraylist +) 工作正常

=========================================

这是示例代码

string[] Myarray = ListVal.split(','); Query = "SELECT * FROM EMP WHERE USER IN (:VALUES)"

OracleParameter Param = { new OracleParameter (":VALUES",OracleDBType.Array)

};

Param[0].value = Myarray;

using(dr = OracleFactory.ExecuteReader(CommandType.Text,Query,true,Param)) {

}

在执行此操作时,我得到一个异常,例如

无效的参数绑定 ParameterName VALUES

【问题讨论】:

  • “查询未执行”是什么意思?您收到错误消息吗?或者您的查询没有返回任何内容?你的绑定变量是什么类型的?
  • 我已将您的两个帐户合并在一起。 Please read this Faq entry about cookie-based accounts. 另外,StackOverflow 不是论坛;如果您有新问题,请提出新问题。如果您想在问题中包含更多信息,请edit it。如果您想与其中一位已回答的人互动,可以给他们留言。

标签: c# oracle


【解决方案1】:

(Also cross-posted to)

我知道这是一个老问题,但它是几个选择的答案没有解决我的问题的问题之一,我不想再开始关于这个主题的另一个话题,所以我会记下我发现的内容在我的旅行中,希望它可以帮助某人。这是一个重复的答案,因为如果有人正在寻找这样的解决方案,我不确定哪个更有可能出现。

我不太使用 Oracle,但是,就像在 SQL Server 中一样,似乎要传递一个表值参数,您需要有一个相应的 UDT(用户定义的表),您对其具有 EXECUTE 权限(我可能是错误的)。这意味着建议使用内置 SYS UDT 的其他答案会带来一些运费,我无法弄清楚是否真的可以将表传递给当前版本中不是 PL/SQL 存储过程的东西ODP.net.

其次,字符串解析解决方案由于所有明显的原因(无法缓存执行计划或 Oracle 所称的任何内容、无法很好地扩展等)都是一个杂项。

所以我花了相当多的时间尝试在数据集市上使用表值参数执行 IN 子句,在我被明显的闪光击中之前我只有 READ 权限(在 ASP.net论坛不少)。事实证明,Oracle '本机'支持 Xml 查询,因此您可以传递一个 xml 列表(如果您只需要这样的话),而不是传递一个值数组。同样,我可能错了,但它被当作合法的绑定参数处理,这是一个使用简单的示例(vb.net、ADO.net、ODP.net 使用 NuGet 包):

Dim xe As New XElement("l", New XElement("i", "ITEM-A"), New XElement("i", "ITEM-B"))
Using conn As New OracleConnection(myConnectionString)
    conn.Open()
    Using cmd As OracleCommand = conn.CreateCommand()
        cmd.CommandType = CommandType.Text
        Dim query As String
        query = "  SELECT s.FOO, q.BAR " & vbCrLf
        query &= " FROM TABLE1 s LEFT OUTER JOIN " & vbCrLf
        query &= "      TABLE2 q ON q.ID = s.ID " & vbCrLf
        query &= " WHERE (COALESCE(q.ID, 'NULL') NOT LIKE '%OPTIONAL%') AND "
        query &= "       (s.ID IN ("
        query &= "                      SELECT stid "
        query &= "                      FROM XMLTable('/l/i' PASSING XMLTYPE(:stid) COLUMNS stid VARCHAR(32) PATH '.')"
        query &= "                 )"
        query &= "        )"
        cmd.CommandText = query
        Dim parameter As OracleParameter = cmd.Parameters.Add("stid", OracleDbType.NVarchar2, 4000)
        parameter.Value = xe.ToString
        Using r As OracleDataReader = cmd.ExecuteReader
            While r.Read()
                //Do something
            End While
        End Using
    End Using
    conn.Close()

这更像是一种观察,而不是一个仔细研究的解决方案,所以如果这样做有什么不合适的地方,请发表评论。

编辑。使用这种方法显然有 4000 个字符的限制(如果是 NVARCHAR,则为 2000),所以我不得不观看我的分页。如果您检查,您会收到信息性错误消息“ORA-01460: unimplemented or unreasonable conversion requested”

【讨论】:

    【解决方案2】:

    您需要将值作为数组传递并稍微修改查询。以下代码适用于 ODP.NET。我不知道是否也可以使用 Microsoft 已弃用的 Oracle 驱动程序。

    首先,你需要定义一个表类型(例如对于VARCHAR):

    CREATE TYPE varchar_table AS TABLE OF VARCHAR2(2000); 
    

    为查询创建参数时,将其声明为关联 PL/SQL 数组:

    OracleParameter param1 = new OracleParameter(); 
    param1.OracleDbType = OracleDbType.Varchar2; 
    param1.CollectionType = OracleCollectionType.PLSQLAssociativeArray; 
    

    然后分配一些值:

    param1 = new string[2] { "johnp", "billt" }; 
    

    您的查询需要演员表:

    SELECT * FROM EMP WHERE USER IN (TABLE(CAST(:values AS varchar_table)))
    

    【讨论】:

    • 对我不起作用,我得到 ORA-00936: missing expression
    • 语法似乎不正确-我相信“TABLE”函数会返回一个表,因此它不能直接在列表中使用。您需要执行“select * from table(cast(:bind ...”
    • @Codo 你从 stackoverflow.com/questions/541466/… 获取的。你可以看到每个人都卡在 SELECT * FROM EMP WHERE USER IN (TABLE(CAST(:values AS varchar_table))) 你能写完整的查询没有错误 ORA-01484
    • 我无法再访问 Oracle 数据库了。所以我不能再测试它了。我很确定在发布之前我已经成功测试了它。可能语法是正确的,但其他地方发生了变化,比如 ODP.NET 驱动程序。
    【解决方案3】:

    首先,我严重怀疑查询没有被执行。

    或者更确切地说,如果它真的没有被执行,那么你会得到一个异常,你会问这个问题。

    我认为你的意思是你没有得到任何结果,这是不同的。

    原因是您无法在大多数数据库中对 IN 子句进行参数化。

    最终要做的是你正在做一个只有 1 个值的 IN 子句。该值究竟是什么取决于您传入的集合以及如何将其转换为查询引擎的适当类型。可能是您最终在集合上调用 .ToString() 并将其填充在那里。

    无论如何,都做不到。您必须使用字符串连接方式。

    或者,您可以通过在 IN 子句中添加足够的参数以使每个参数具有 1 个值的方式创建 SQL。

    换句话说,您可以为 4 元素集合执行此操作:

    SELECT * FROM EMP WHERE USER IN (:V1, :V2, :V3, :V4)
    

    然后将每个参数绑定到集合的元素之一。不过,您仍然必须动态构建 SQL。

    【讨论】:

      【解决方案4】:

      很遗憾,您不能将数组传递给绑定变量。

      你唯一的选择是直接在查询中插入一个逗号分隔的列表,或者编写你自己的帮助器/包装器来自动将你的语句重写为

      IN (:value1, :value2, :value3...)

      并自动填充这些值。这至少在某些情况下(如果您有大量具有相同参数数量的重复查询)可以简化 Oracle 解析器的工作。

      【讨论】:

      • 虽然经常选择您的方法,但可以将数组传递给绑定变量(请参阅我的回答)。
      猜你喜欢
      • 1970-01-01
      • 2013-09-07
      • 2015-10-06
      • 1970-01-01
      • 2021-03-14
      • 2019-01-18
      • 2021-08-02
      • 2015-08-15
      • 1970-01-01
      相关资源
      最近更新 更多