2012-07-19 21 views
5

Ho una query in cui voglio restituire tutte le righe associate a un elenco di valori. Potresti scrivere questo semplicemente come:Filtro query SQL per elenco di parametri

select * from TableA where ColumnB in (1, 2, 3, 5) 

Potrei generare questa query in C# ed eseguirla. Tuttavia questo è ovviamente meno che ideale in quanto non utilizza i parametri, ne risentirà quando si tenta di memorizzare nella cache i piani di query ed è ovviamente vulnerabile a un attacco di SQL injection.

Un'alternativa è quella di scrivere questo come:

select * from TableA where ColumnB = @value 

Questo potrebbe essere eseguito più volte da C#, ma questo si tradurrà in N DB colpisce.

L'unica altra alternativa che posso vedere è creare una tabella temporanea e unirla in questo modo, tuttavia non vedo questo punto come sarebbe più complesso e risentire delle stesse limitazioni della prima opzione.

Sto usando SQL server e OLDB, la creazione della query non è il problema. Sto cercando di creare il processo più efficiente.

Quale di questi tre metodi è più efficiente? Ho perso un'alternativa?

+0

come si desidera eseguire la query? EF, LINQ, ADO, OLEDB? – paul

+0

E quale server? MySql, MsSql, altro? – mmdemirbas

+0

OLDB e MsSQL, domanda aggiornata – Liath

risposta

4

Supponendo di SQL Server 2008 o più recente, in SQL Server, creare un tipo di tabella una volta:

CREATE TYPE dbo.ColumnBValues AS TABLE 
(
    ColumnB INT 
); 

Poi una stored procedure che accetta un tale tipo come input:

CREATE PROCEDURE dbo.whatever 
    @ColumnBValues dbo.ColumnBValues READONLY 
AS 
BEGIN 
    SET NOCOUNT ON; 

    SELECT A.* FROM dbo.TableA AS A 
    INNER JOIN @ColumnBValues AS c 
    ON A.ColumnB = c.ColumnB; 
END 
GO 

Ora in C# , creare un DataTable e passarlo come parametro alla stored procedure:

DataTable cbv = new DataTable(); 
cbv.Columns.Add(new DataColumn("ColumnB")); 

// in a loop from a collection, presumably: 
cbv.Rows.Add(someThing.someValue); 

using (connectionObject) 
{ 
    SqlCommand cmd  = new SqlCommand("dbo.whatever", connectionObject); 
    cmd.CommandType  = CommandType.StoredProcedure; 
    SqlParameter cbvParam = cmd.Parameters.AddWithValue("@ColumnBValues", cbv); 
    cbvParam.SqlDbType = SqlDbType.Structured; 
    //cmd.Execute...; 
} 

(Si consiglia di m ake il tipo molto più generico, l'ho chiamato specificatamente per chiarire che cosa sta facendo.)

0

Si può facilmente scrivere questo:

String csvString = "1, 2, 3, 5"; // Built the list somehow, don't forget escaping 
String query = "select * from TableA where ColumnB in (" + csvString + ")"; 

In questo modo, le prestazioni non è diminuita, e si può prevenire iniezione valori di input semplicemente in fuga SQL durante la creazione di csvString.

A proposito, se si utilizza MS SQL invece di SQL standard, è possibile findalternativeways.

+0

Sì, questo è come lo sto facendo attualmente. Il mio problema è che questo creerà un nuovo piano di esecuzione ogni volta che questa query viene eseguita poiché il comando è diverso, rallentando considerevolmente le prestazioni ... – Liath

+1

@Liath è possibile evitare un po 'di ciò utilizzando ['ottimizzare per carichi di lavoro ad hoc'] (http://msdn.microsoft.com/en-us/library/cc645587.aspx) impostazione. In questo modo i piani non vengono memorizzati nella cache fino a quando non è stata eseguita una query specifica due volte. La tua query produrrà comunque una scansione, ma non occuperà spazio nella cache del piano a meno che non debba (ad esempio, viene realmente riutilizzata). –

2

È anche possibile utilizzare multiple resultsets e inviare un bounch di query come questa:

select * from TableA where ColumnB = @value0 
select * from TableA where ColumnB = @value1 
select * from TableA where ColumnB = @value2 
... 
select * from TableA where ColumnB = @valuen 

in una singola chiamata. anche se apparentemente contro intuitivo sfrutta il piano di esecuzione ed è sicuro in termini di parametrizzazione.

+0

Sono curioso di sapere che -1 ho ricevuto –

+0

Non è esattamente questo che l'OP ha detto che non volevano fare? –

+0

@AaronBertrand non esattamente: vuole usare il piano di esecuzione, e così sarà. Nota che non sono separati roundtrip, ma tutte le query vengono eseguite in un singolo rountrip sul DB. Inoltre, la query viene parametrizzata correttamente per evitare l'iniezione. –

Problemi correlati