2009-12-28 16 views
6

El proyecto que estoy trabajando tiene una gran cantidad de in-consultas como:pasar un array como valor en un DbParameter ado.net

SELECT something, anotherthing 
FROM atable 
WHERE something IN (value1, value2, value3) 

Este es un ejemplo de una consulta con 3 parámetros de la EN -parte pero la misma consulta podría ejecutarse con 1 o 2 o 5 o 10 o ... parámetros. El problema es que cada consulta tiene otro plan de ejecución en la base de datos que lo hace lento.

me gustaría hava una consulta como esta:

SELECT something, anotherthing 
FROM atable 
WHERE something IN (@value1, @value2, @value3) 

o esto:

SELECT something, anotherthing 
FROM atable 
WHERE something IN (@values) 

que he logrado la primera consulta con un poco de función auxiliar, pero todavía tengo diferentes plan de ejecución por número de parámetros. Esto podría resolverse con el segundo.

¿Cuál es la mejor forma de pasar una matriz como parámetro de base de datos? Estoy usando Oracle y SQL Server, las soluciones para ambos son bienvenidas.

Respuesta

4

Para SQL-Server, hay dos enfoques comunes para esto. La tercera opción que debe evitarse es pasar un varchar y concatenarlo en una instrucción SQL dinámica con IN - esta es una superficie de ataque de inyección transparente.

opciones razonables:

  • pase en un varchar y utilizar una UDF para dividir los datos en un delimitador (like in this question), tal vez por comas, tubería, pestaña, etc. Únete al resultado:

    SELECT something, anotherthing 
    FROM atable a 
    INNER JOIN dbo.SplitUDF(@values) udf 
         ON udf.Value = a.something 
    
  • uso un (SQL2008) table-valued-parameter y unirse directamente (evitar la UDF)
+0

Desafortunadamente, tengo que soportar SQL Server 2000 y 2005, no hay tabla-valor-parámetro para mí. – Jochen

1

Tener una mirada en estos artículos

Este es un ejemplo del uso del tipo XML para crear una lista

--Split 
DECLARE @textXML XML 
DECLARE @data NVARCHAR(MAX), 
     @delimiter NVARCHAR(5) 

SELECT @data = 'A,B,C', 
     @delimiter = ',' 

SELECT @textXML = CAST('<d>' + REPLACE(@data, @delimiter, '</d><d>') + '</d>' AS XML) 
SELECT T.split.value('.', 'nvarchar(max)') AS data 
FROM @textXML.nodes('/d') T(split) 
0

Este código es el truco. Puede crear su propia función BuildQuery (???).

public void RemoveDependencies(int versionID, int[] deps) 
    { 
     if (versionID <= 0) 
      throw new ArgumentException(); 
     if (deps == null) 
      throw new ArgumentNullException(); 
     if (deps.Length <= 0) 
      throw new ArgumentException(); 

     SqlCommand cmd = new SqlCommand(); 
     string query = "DELETE FROM Dependencies WHERE version_id = @VersionId AND dep_version_id IN ("; 
     int n = deps.Length; 
     string key; 
     for (int i = 0; i < n; i++) 
     { 
      if (deps[i] <= 0) 
       throw new ArgumentException(); 
      key = String.Format("@dep{0}", i); 
      query += key; 
      cmd.Parameters.AddWithValue(key, deps[i]); 
      if (i < n - 1) 
      { 
       query += ", "; 
      } 
     } 
     query += ")"; 
     cmd.Parameters.AddWithValue("@VersionId", versionID); 
     cmd.CommandText = query; 
     using (SqlConnection con = GetSqlConnection()) 
     { 
      con.Open(); 
      cmd.Connection = con; 
      if (cmd.ExecuteNonQuery() <= 0) 
      { 
       throw new ArgumentException("No rows affected! Illegal id."); 
      } 
     } 
    } 
Cuestiones relacionadas