2009-12-28 11 views
6

Il progetto su cui sto lavorando ha un sacco di in-domande come:Passare un array come valore in un DbParameter ado.net

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

Questo è un esempio di una query con 3 parametri nel IN -part ma la stessa query potrebbe essere eseguita con 1 o 2 o 5 o 10 o ... parametri. Il problema è che ogni query ha un altro piano di esecuzione nel database con lo rende lento.

mi piacerebbe Hava una query come questa:

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

o questo:

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

ho compiuto la prima query con qualche funzione di supporto, ma ho ancora diverso piano di esecuzione per numero di parametri. Questo potrebbe essere risolto con il secondo.

Qual è il modo migliore per passare un array come parametro del database? Sto usando Oracle e SQL Server, le soluzioni per entrambi sono benvenute.

risposta

4

Per SQL-Server, ci sono due approcci comuni per questo. La terza opzione da evitare deve passare in un varchar e concatenarlo in un'istruzione SQL dinamica con IN - si tratta di una superficie di attacco di iniezione chiara.

opzioni ragionevoli:

  • passaggio in un varchar e utilizzare un UDF per dividere i dati su un delimitatore (like in this question), forse virgola, pipe, scheda, ecc Partecipa al risultato:

    SELECT something, anotherthing 
    FROM atable a 
    INNER JOIN dbo.SplitUDF(@values) udf 
         ON udf.Value = a.something 
    
  • uso un table-valued-parameter (SQL2008) e unirsi direttamente (evitare l'UDF)
+0

Sfortunatamente devo supportare SQL Server 2000 e 2005, nessun parametro con valori di tabella per me. – Jochen

1

Date un'occhiata questi articoli

Questo è un esempio di utilizzo del tipo XML per creare 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

Questo codice fa il trucco. Puoi creare la tua funzione 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."); 
      } 
     } 
    } 
Problemi correlati