OracleParameter和IN子句

有没有办法使用System.Data.OracleClient将参数添加到IN子句。

例如:

string query = "SELECT * FROM TableName WHERE UserName IN (:Pram)"; OracleCommand command = new OracleCommand(query, conn); command.Parameters.Add(":Pram", OracleType.VarChar).Value = "'Ben', 'Sam'"; 

您可以使用ODP.NET更轻松地完成此操作:

  1. 在数据库中创建TABLE类型:

     CREATE TYPE t_varchar2 AS TABLE OF VARCHAR2(4000); 
  2. 创建一个集合参数:

     OracleParameter param = new OracleParameter(); param.OracleDbType = OracleDbType.Varchar2; param.CollectionType = OracleCollectionType.PLSQLAssociativeArray; 
  3. 填写参数:

     param = new string[2] {"Ben", "Sam" }; 
  4. 将参数绑定到以下查询:

     SELECT * FROM TableName WHERE UserName IN (TABLE(CAST(:param AS t_varchar2))); 

您可以将其包装在OracleCommandExtension方法中:

 public static class OracleCommandExtension { public static OracleCommand AddParameterCollection(this OracleCommand command, string name, OracleType type, IEnumerable collection) { var oraParams = new List(); var counter = 0; var collectionParams = new StringBuilder(":"); foreach (var obj in collection) { var param = name + counter; collectionParams.Append(param); collectionParams.Append(", :"); oraParams.Add(new OracleParameter(param, type) { Value = obj }); counter++; } collectionParams.Remove(collectionParams.Length - 3, 3); command.CommandText = command.CommandText.Replace(":" + name, collectionParams.ToString()); command.Parameters.AddRange(oraParams.ToArray()); return command; } } 

我知道这是前一段时间被问到的,但不是一个很好的答案。

我会做这样的事情 – 请原谅粗糙的psudo代码

 string args[] = {'Ben', 'Sam'}; string bindList = ""; for(int ii=0;ii 

因此,查询最终得到(:1,:2),并且每个都分别绑定。

这里也有一个类似的问题: Oracle / c#:我如何使用绑定变量和select语句来返回多个记录?

老问题,但我想分享我的代码。 只是一个简单的方法来创建一个可以连接到动态生成的sql的字符串,而不会失去绑定参数的性能和安全性:

  ///  /// 1 - Given an array of int, create one OracleParameter for each one and assigin value, unique named using uniqueParName /// 2 - Insert the OracleParameter created into the ref list. /// 3 - Return a string to be used to concatenate to the main SQL ///  ///  ///  ///  ///  private static string InsertParameters(ref List orclParameters, int[] lsIds, string uniqueParName) { string strParametros = string.Empty; for (int i = 0; i <= lsIds.Length -1; i++) { strParametros += i == 0 ? ":" + uniqueParName + i : ", :" + uniqueParName + i; OracleParameter param = new OracleParameter(uniqueParName + i.ToString(), OracleType.Number); param.Value = lsIds[i]; orclParameters.Add(param); } return strParametros; } 

并使用这样的:

 List parameterList = new List(); int[] idAr = new int[] { 1, 2, 3, 4}; string idStr = InsertParameters(ref parameterList, idAr, "idTest"); string SQL = " SELECT name FROM tblTest WHERE idTest in ( " + idStr + " ) "; 

您可以使用类似于此处的Oracle自定义数据类型:
http://www.c-sharpcorner.com/code/2191/pass-collection-to-oracle-stored-procedure-from-net-layer.aspx

和这里:
https://stackoverflow.com/a/31466114/1867157

首先在Oracle中创建一个类型并赋予其权限:

 CREATE TYPE MYSCHEMA.VARCHAR2_TAB_T AS TABLE OF VARCHAR2(4000); GRANT EXECUTE ON MYSCHEMA.VARCHAR2_TAB_T TO MYROLE 

然后创建2个类:

StringListCustomType.cs

 public class StringListCustomType : IOracleCustomType, INullable { public const string Name = "MYSCHEMA.VARCHAR2_TAB_T"; [OracleArrayMapping()] public string[] Array; #region IOracleCustomType public OracleUdtStatus[] StatusArray { get; set; } public void ToCustomObject(OracleConnection con, IntPtr pUdt) { object objectStatusArray = null; Array = (string[])OracleUdt.GetValue(con, pUdt, 0, out objectStatusArray); StatusArray = (OracleUdtStatus[])objectStatusArray; } public void FromCustomObject(OracleConnection con, IntPtr pUdt) { OracleUdt.SetValue(con, pUdt, 0, Array, StatusArray); } #endregion #region INullable public bool IsNull { get; set; } public static StringListCustomType Null { get { StringListCustomType obj = new StringListCustomType(); obj.IsNull = true; return obj; } } #endregion } 

StringListCustomTypeFactory.cs

 [OracleCustomTypeMapping(StringListCustomType.Name)] public class StringListCustomTypeFactory : IOracleCustomTypeFactory, IOracleArrayTypeFactory { #region IOracleCustomTypeFactory IOracleCustomType IOracleCustomTypeFactory.CreateObject() { return new StringListCustomType(); } #endregion #region IOracleArrayTypeFactory Array IOracleArrayTypeFactory.CreateArray(int numElems) { return new string[numElems]; } Array IOracleArrayTypeFactory.CreateStatusArray(int numElems) { return new OracleUdtStatus[numElems]; } #endregion } 

然后你可以添加这样的参数:

 dbParameter = new OracleParameter(); dbParameter.ParameterName = "myparamname"; dbParameter.UdtTypeName = StringListCustomType.Name; dbParameter.OracleDbType = OracleDbType.Array; if (myarray != null) { StringListCustomType newArray = new StringListCustomType(); newArray.Array = myarray; dbParameter.Value } else { dbParameter.Value = StringListCustomType.Null; } 

您的查询将如下所示:

 SELECT * FROM MYSCHEMA.MYTABLE WHERE MYVARCHARFIELD IN (SELECT COLUMN_VALUE FROM TABLE(CAST(:myparamname AS MYSCHEMA.VARCHAR2_TAB_T))) 

那样你的查询将是:

  SELECT * FROM TableName WHERE UserName IN('''Ben'',''Sam'''); 

这两个名称将作为单个值输入。

看看asktom.oracle.com上的这个post,了解如何获得动态列表。

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:210612357425

它在ORACLE中非常简单。

以下步骤:

1.在oracle中创建默认类型

 CREATE OR REPLACE TYPE t_varchar_tab AS TABLE OF VARCHAR2(4000); 

2.在oracle中创建函数,将“a,b,c”之类的字符串分隔为”a’,’b’,’c”

 CREATE OR REPLACE FUNCTION in_list(p_in_list IN VARCHAR2)ETURNt_varchar_tab AS l_tab t_varchar_tab := t_varchar_tab(); l_text VARCHAR2(32767) := p_in_list || ',' ; l_idx NUMBER; BEGIN LOOP l_idx := INSTR(l_text, ','); EXIT WHEN NVL(l_idx, 0) = 0; l_tab.extend; l_tab(l_tab.last) := TRIM(SUBSTR(l_text, 1, l_idx - 1)); l_text := SUBSTR(l_text, l_idx + 1); END LOOP; RETURN l_tab; END; 

3:然后使用以下查询从表中提取数据

 SELECT * FROM TABLE_NAME EMP WHERE IN (SELECT * FROM TABLE(in_list(i_input1))); 

4.输入参数从c#.net传递到oracle SP之类的

  cmd.Parameters.Add("i_input1", OracleType.VarChar, 50).Value = "S1,S2"; 

我在搜索同样的问题时遇到过它,所以我想添加一个我觉得有帮助的答案,因为我不相信上面真的实现了它:

http://forums.asp.net/t/1195359.aspx/1?Using%20bind%20variable%20with%20an%20IN%20clause

我会在这里添加答案,以防链接失效:

Re:将bind变量与IN子句一起使用2007年12月17日下午06:56 | LINK

您必须单独添加每个值。 这样的事情(在Mac上写,所以我无法测试)

 string sql = "select id, client_id as ClientID, acct_nbr as AcctNbr from acct where acct_nbr in ( %params% )"; OracleConnection conn = new OracleConnection(DBConnection); OracleCommand cmd = new OracleCommand(); List params=new List(); foreach(string acctNbr in AcctNbrs.Split(',')) { string paramName=":acctNbr" + params.Count.Tostring(); params.Add(paramName) OracleParameter parms = new OracleParameter(paramName, OracleType.VarChar); parms.Value = acctNbr; cmd.Parameters.Add(parms); } cmd.CommandType = CommandType.Text; cmd.CommandText = sql.Replace("%params%",params.ToArray().Join(",")); cmd.Connection = conn; OracleDataAdapter da = new OracleDataAdapter(cmd); da.Fill(ds); 
 SELECT * FROM Clients WHERE id IN ( SELECT trim(regexp_substr(str, '[^,]+', 1, level)) strRows FROM (SELECT :Pram as str from dual ) t CONNECT BY instr(str, ',', 1, level -1) >0); 

也许使用不同的方法

 SELECT * FROM SCOTT.EMP WHERE EMPNO IN (SELECT TO_NUMBER(X.COLUMN_VALUE) FROM XMLTABLE('7788,7900') X); 

要么

 SELECT * FROM SCOTT.EMP WHERE ENAME IN (SELECT X.COLUMN_VALUE.GETSTRINGVAL() FROM XMLTABLE('"SCOTT", "JAMES"') X); 

其中XMLTABLE的内容可以是单个参数。 因此它应该可以从任何语言使用。

解决方案不应包含逗号字符,也不应包含单引号,双引号。 我建议您使用临时表,然后从中进行选择。 使用常规命令参数填充临时表。

实际上,我也会尝试这段代码:

 string query = "SELECT * FROM TableName WHERE UserName IN (:Pram)"; param = new string[2] {"Ben", "Sam" }; OracleCommand command = new OracleCommand(query, conn); command.ArrayBindCount = param.Length; command.Parameters.Add(":Pram", OracleType.VarChar).Value = param;