带有IN语句的Oracle参数?

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

select * from contract where contractnum = :ContractNum 

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

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

 select * from contract where contractnum in (:ContractNum) 

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

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

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

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

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

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

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

使用以下包:

 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 

您的查询将如下所示:

 select * from contract where contractnum in (select column_value from table(demo_pkg.string_to_tab(:ContractNum))) 

当您使用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类型。 您可以使用最大1048576个数字填写MDSYS.SDO_ELEM_INFO_ARRAY

 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(); } } } 

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

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

对于在IN语句中使用参数,您可以使用此构造:

 select * from contract where contractnum in (select column_value from table (:ContractNum)) 

其中ContractNum是自定义数组类型。