2009-02-12 40 views
12

¿Hay alguna manera de agregar un parámetro a una cláusula IN utilizando System.Data.OracleClient?OracleParameter e IN Cláusula

Por ejemplo:

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

IMHO Cualquier solución donde un "," carácter codificado sea parte de la solución no es válida. Oracle debería estar generando esto, no la aplicación. Esto también se aplica a cualquier tipo de delimitador de cadena '' –

Respuesta

9

Puede hacerlo más fácilmente con ODP.NET:

  1. crear un tipo TABLE en su base de datos:

    CREATE TYPE t_varchar2 AS TABLE OF VARCHAR2(4000); 
    
  2. crear un parámetro de recogida:

    OracleParameter param = new OracleParameter(); 
    param.OracleDbType = OracleDbType.Varchar2; 
    param.CollectionType = OracleCollectionType.PLSQLAssociativeArray; 
    
  3. Llenar el parámetro:

    param = new string[2] {"Ben", "Sam" }; 
    
  4. enlazar el parámetro a la siguiente consulta:

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

No funciona para mí, sigo obteniendo ORA-00936: expresión faltante – surya

+4

Eso es porque necesita escribir "WHERE Nombre de usuario IN (SELECCIONAR valor_columna FROM TABLE (CAST (: param AS t_varchar2))) ", pero probablemente obtendrá" ORA-01484: las matrices solo pueden vincularse a sentencias PL/SQL ", lo que sugiere que dicho código se debe colocar en sentencias PL/SQL, no en el código C# –

+1

. Este enfoque requiere base de datos derechos para modificar el esquema, que no es mi caso. –

-2

En realidad, también me gustaría probar este código:

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; 
+0

Esta solución no funciona para mí. Es equivalente a: "SELECT * FROM TableName WHERE UserName IN (" Ben ")" - solo se toma el primer elemento en la tabla –

3

Sé que esto fue preguntado hace un tiempo, pero no un brillante nt respuesta.

me gustaría hacer algo como esto - disculpen el código psudo crudo

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

Entonces consulta termina teniendo en (1, 2) y cada uno de éstos están obligados por separado.

También hay una pregunta similar aquí: Oracle/c#: How do i use bind variables with select statements to return multiple records?

+0

I Creo que será inyección Sql –

+0

Creo que estás equivocado? ¿cómo se inyecta en este? –

8

se puede envolver en el método 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; 
    } 
} 
+1

En el año 2016, los clientes administrados .NET a Oracle todavía no pueden pasar matriz parámetro en 'in'. Solo el cliente nativo Oracle puede. –

+0

Esto agregará 'n' parámetros y cada aria diferente será una consulta diferente y no podrá usar los planes de consulta en caché. –

1

me encontré con él en la búsqueda de la misma pregunta, así que me gustaría añadir una respuesta que he encontrado muy útil, porque no creo que lo anterior realmente lograrlo:

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

voy a una dd la respuesta aquí, así en caso de que el enlace no es válida:

Re: Uso de variable de vinculación con una cláusula IN Dic 17 de, de 2007 18:56 | ENLACE

Debe añadir cada valor por separado. Algo como esto (escrito en un Mac, así que no podía probarlo)

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

vieja pregunta, pero me gustaría compartir mi código. Sólo un método sencillo para crear una cadena que puede concatenar a un SQL generado dinámica, sin perder el rendimiento y la seguridad de los parámetros bind:

/// <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; 
    } 

Y el uso de la siguiente manera:

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 + ") "; 
1

Es muy simple en ORACLE.

siguientes pasos:

1.Create tipo predeterminado en el oráculo

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

función 2.Crear en Oracle para seperating cadena dada como "a, b, c" en '' 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: a continuación, utilice siguiente consulta para extraer datos de tabla

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

parámetro 4.Input pasar de C# .NET para Oracle SP como

cmd.Parameters.Add("i_input1", OracleType.VarChar, 50).Value = "S1,S2"; 
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); 
-1

La solución no debe contener el carácter de coma ni comillas simples, comillas dobles. Sugiero que uses una tabla temporal y luego selecciones de eso. Llene la tabla temporal usando parámetros de comando regulares.

2

Se puede utilizar un tipo de datos personalizado Oracle similar al aquí:
http://www.c-sharpcorner.com/code/2191/pass-collection-to-oracle-stored-procedure-from-net-layer.aspx

y aquí:
https://stackoverflow.com/a/31466114/1867157

En primer lugar crear un tipo en Oracle y darle permisos:

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

A continuación, cree 2 clases:

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 
} 

A continuación, se puede añadir un parámetro de la siguiente manera:

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

Su consulta se vería así:

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

quizás utilizando un enfoque diferente

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

o

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

Donde el contenido de la XMLTABLE podrían ser un solo parámetro. Por lo tanto, debe ser utilizable desde cualquier idioma.

Cuestiones relacionadas