OracleParameter和IN子句

时间:2009-02-12 14:25:21

标签: c# .net oracle

是否可以使用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'";

13 个答案:

答案 0 :(得分:12)

您可以使用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)));
    

答案 1 :(得分:10)

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

public static class OracleCommandExtension
{
    public static OracleCommand AddParameterCollection<TValue>(this OracleCommand command, string name, OracleType type, IEnumerable<TValue> collection)
    {
        var oraParams = new List<OracleParameter>();
        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;
    }
}

答案 2 :(得分:3)

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

我会这样做 - 请原谅粗糙的psudo代码

string args[] = {'Ben', 'Sam'};
string bindList = "";
for(int ii=0;ii<args.count;++ii)
{
  if(ii == 0)
  {
   bindList += ":" + ii;
  }
  else
  {
   bindList += ",:" + ii;
  }
  OracleParameter param = new OracleParameter();
  param.dbType = types.varchar;
  param.value = args[ii];
  command.Parameters.Add(param);
}

query = "select * from TableName where username in(" + bindList + ")";

然后查询最终得到(:1,:2),并且每个都是单独绑定的。

这里也有类似的问题:Oracle/c#: How do i use bind variables with select statements to return multiple records?

答案 3 :(得分:3)

您可以使用类似于此处的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)))

答案 4 :(得分:2)

也许使用不同的方法

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的内容可以是单个参数。 因此它应该可以从任何语言使用。

答案 5 :(得分:1)

这样您的查询将是:

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

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

从asktom.oracle.com查看这个帖子,了解如何获得动态列表。

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

答案 6 :(得分:1)

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

    /// <summary>
    /// 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
    /// </summary>
    /// <param name="orclParameters"></param>
    /// <param name="lsIds"></param>
    /// <param name="uniqueParName"></param>
    /// <returns></returns>
    private static string InsertParameters(ref List<OracleParameter> 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<OracleParameter> parameterList = new List<OracleParameter>();
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 + " )  ";

答案 7 :(得分:0)

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

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

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

  

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

     

您必须单独添加每个值。像这样的东西(写在   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<string> params=new List<string>();

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

答案 8 :(得分:0)

在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";

答案 9 :(得分:0)

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

答案 10 :(得分:0)

尽管这个问题很老,但我还是以自己的情况来说明解决问题的方法。 该示例在Vb.NET中进行,但我认为也可以理解。 总的来说,解决方案是将IN语句转换为一系列具有各自参数的OR条件,所有这些条件都可以通过程序实现。

从拥有一个带有搜索值的字符串开始,并以逗号分隔,不使用Oracle会使用的字符串引号,并假设您有一个已定义的OracleCommand,在示例中我将其称为oraCommando。 我所做的是通过拆分具有搜索值的字符串来组装查询字符串,根据需要创建尽可能多的OR比较,并将它们的值分配给它们各自的参数。 在查询字符串程序集中分配参数的名称时应特别注意,以免在名称和末尾的数字之间留空格,以使它们都是不同的名称。

strCommand & = " UserName = :userName" & puntParam & " "

示例代码为:

dim param as string = "Ben, Sam"
dim strCommand as string = "SELECT * FROM TableName WHERE"
dim puntParam as integer = 0
for each paramAnali as string in split (param, ",")
    puntParam + = 1
    if puntParam> 1 then
        strCommand & = "or"
    end if
    strCommand & = "UserName =: userName" & puntParam.ToString () & ""

    Dim paramNew As New OracleParameter With {
      .ParameterName = "userName" & puntParam.ToString (),
      .OracleDbType = OracleDbType.Varchar2,
      .Direction = ParameterDirection.Input,
      .Value = Trim (paramAnali)}

    oraCommando.Parameters.Add (paramNew)

next

此外,为了使参数绑定没有问题,必须指示Oracle命令按名称进行“绑定”。

oraCommando.BindByName = True

这样,查询将自动调整为接收到的值的数量,而无需调整代码。

答案 11 :(得分:-1)

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

答案 12 :(得分:-2)

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

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;