带有IN语句的Oracle参数?

Gar*_*eth 7 c# sql oracle parameters oracle10g

得到了我需要修改的#.net应用程序.此刻的查询有效地做到了这一点:

select * from contract where contractnum = :ContractNum
Run Code Online (Sandbox Code Playgroud)

(非常简化,只是为了表明我们正在使用=和一个参数)

该参数从C#app上的Settings.Settings文件中读取,并且其中包含一个字符串.我需要修改它以包含多个合同,所以我想我可以将SQL更改为:

select * from contract where contractnum in (:ContractNum)
Run Code Online (Sandbox Code Playgroud)

但无论我如何格式化参数中的字符串,都不会返回任何结果.

有没有办法让oracle用参数做一个IN?

任何帮助表示感谢,谢谢大家.

tui*_*oel 7

当您使用ODP.NET作为数据提供者时,可以使用Oracle数字集合作为参数(绑定变量).这适用于Oracle服务器9,10或11以及ODP.net版本> = 11.1.0.6.20.

当您使用适用于Oracle的Devart的.NET数据提供程序时,可以使用类似的解决方案.

让我们选择contractnum 3和4的合同.

我们必须使用Oracle类型将一组合同号转移到我们的查询中.

MDSYS.SDO_ELEM_INFO_ARRAY因为如果我们使用这个已经预定义的Oracle类型,我们就不必定义我们自己的Oracle类型.您最多可以填写MDSYS.SDO_ELEM_INFO_ARRAY1048576个号码.

using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;

[OracleCustomTypeMappingAttribute("MDSYS.SDO_ELEM_INFO_ARRAY")]
public class NumberArrayFactory : IOracleArrayTypeFactory
{
  public Array CreateArray(int numElems)
  {
    return new Decimal[numElems];
  }

  public Array CreateStatusArray(int numElems)
  {
    return null;
  }
}

private void Test()
{
  OracleConnectionStringBuilder b = new OracleConnectionStringBuilder();
  b.UserID = "sna";
  b.Password = "sna";
  b.DataSource = "ora11";
  using (OracleConnection conn = new OracleConnection(b.ToString()))
  {
    conn.Open();
    using (OracleCommand comm = conn.CreateCommand())
    {
      comm.CommandText =
      @" select  /*+ cardinality(tab 10) */ c.*  " +
      @" from contract c, table(:1) tab " +
      @" where c.contractnum = tab.column_value";

      OracleParameter p = new OracleParameter();
      p.OracleDbType = OracleDbType.Array;
      p.Direction = ParameterDirection.Input;
      p.UdtTypeName = "MDSYS.SDO_ELEM_INFO_ARRAY";
      //select contract 3 and 4
      p.Value = new Decimal[] { 3, 4 };
      comm.Parameters.Add(p);

      int numContracts = 0;
      using (OracleDataReader reader = comm.ExecuteReader())
      {
        while (reader.Read())
        {
           numContracts++;
        }
      }
      conn.Close();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

如果省略提示/*+基数(选项卡10)*/,则不使用contract.contractnum上的索引.我假设contractnum是主键,因此该列将被索引.

另见:http : //forums.oracle.com/forums/thread.jspa?messageID=3869879#3869879


Vin*_*rat 6

您可以使用流水线函数将字符串转换为可与IN操作员一起使用的表.例如(使用10gR2测试):

SQL> select * from table(demo_pkg.string_to_tab('i,j,k'));

COLUMN_VALUE
-----------------
i
j
k
Run Code Online (Sandbox Code Playgroud)

使用以下包:

SQL> CREATE OR REPLACE PACKAGE demo_pkg IS
  2     TYPE varchar_tab IS TABLE OF VARCHAR2(4000);
  3     FUNCTION string_to_tab(p_string VARCHAR2,
  4                            p_delimiter VARCHAR2 DEFAULT ',')
  5        RETURN varchar_tab PIPELINED;
  6  END demo_pkg;
  7  /

Package created
SQL> CREATE OR REPLACE PACKAGE BODY demo_pkg IS
  2     FUNCTION string_to_tab(p_string VARCHAR2,
  3                            p_delimiter VARCHAR2 DEFAULT ',')
  4        RETURN varchar_tab PIPELINED IS
  5        l_string          VARCHAR2(4000) := p_string;
  6        l_first_delimiter NUMBER := instr(p_string, p_delimiter);
  7     BEGIN
  8        LOOP
  9           IF nvl(l_first_delimiter,0) = 0 THEN
 10              PIPE ROW(l_string);
 11              RETURN;
 12           END IF;
 13           PIPE ROW(substr(l_string, 1, l_first_delimiter - 1));
 14           l_string          := substr(l_string, l_first_delimiter + 1);
 15           l_first_delimiter := instr(l_string, p_delimiter);
 16        END LOOP;
 17     END;
 18  END demo_pkg;
 19  /

Package body created
Run Code Online (Sandbox Code Playgroud)

您的查询将如下所示:

select * 
  from contract 
 where contractnum in (select column_value
                         from table(demo_pkg.string_to_tab(:ContractNum)))
Run Code Online (Sandbox Code Playgroud)


OMG*_*ies 2

尚未找到一个支持评估包含逗号作为唯一IN子句分隔的单个字符串变量的数据库。

您的选择是对变量进行子字符串化,以便逗号分隔的变量内容转换为行,这样您就可以加入到此变量中。或者使用动态 SQL,这是在执行语句之前在存储过程中构造为字符串的 SQL 语句。

  • & 符号是 SQL*Plus 中表示替换变量的默认字符。TOAD(和其他 IDE)支持某些 SQL*Plus 语法。 (2认同)
  • & 符号可能不适用于 C#。即使它确实有效,它也无法绑定(性能问题),并且会对 SQL 注入开放,因为它将动态构建查询(安全问题)。 (2认同)