2012-07-19 39 views
5

我有一個查詢,我想返回與值列表關聯的所有行。你可以這樣寫:通過參數列表篩選SQL查詢

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

我可以在C#中生成這個查詢並執行它。然而,這顯然不太理想,因爲它不使用參數,它會在嘗試緩存查詢計劃時受到影響,並且顯然很容易受到SQL注入攻擊。

另一種方法是寫爲:

select * from TableA where ColumnB = @value 

這可以通過C#來執行許多次,但是這將導致以N DB命中。

我能看到的唯一的另一種選擇是創建一個臨時表並加入它,但我沒有看到這一點,因爲它會更復雜,並受到與第一個選項相同的限制。

我正在使用SQL服務器和OLDB,創建查詢不是問題。我正在嘗試創建最高效的流程。

這三種方法哪一種更高效?我錯過了另一種選擇嗎?

+0

你想如何執行查詢? EF,LINQ,ADO,OLEDB? – paul 2012-07-19 13:05:33

+0

和哪個服務器? MySql,MsSql,其他? – mmdemirbas 2012-07-19 13:07:46

+0

OLDB和MsSQL,問題更新 – Liath 2012-07-19 13:19:33

回答

4

假設SQL Server 2008或更新的,在SQL Server,創建一個表型一次:

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

然後,存儲的過程,需要這樣一種類型的輸入:

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 

現在,在C# ,創建一個DataTable並將其作爲參數傳遞給存儲過程:

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

(您可能想要m使類型更通用,我特意將其命名爲清楚它在做什麼。)

0

您可以輕鬆地這樣寫:

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

通過這種方式,性能不降低,並且可以防止SQL注入只是逃避的輸入值,同時創造csvString

順便說一句,如果你使用MS SQL,而不是標準的SQL,你可以findalternativeways。在呼叫

​​

+0

是的,這是我目前正在做的。我的問題是,這將創建一個新的執行計劃,每次這個查詢執行,因爲命令是不同的,從而大大降低性能... – Liath 2012-07-19 13:23:07

+1

@Liath你可以通過使用[''優化專用工作負載']( http://msdn.microsoft.com/en-us/library/cc645587.aspx)設置。這種方式計劃不會被緩存,直到一個特定的查詢被執行兩次。您的查詢仍然會進行掃描,但它不會佔用計劃緩存中的空間,除非它應該(例如,它真的被重新使用)。 – 2012-07-19 14:20:42

2

您還可以使用multiple resultsets併發送查詢的bounch這樣。即使明顯違背直覺,它也會利用執行計劃並且在參數化方面是安全的。

+0

我很好奇我收到的-1 – 2012-07-19 13:54:59

+0

這不正是OP說他們不想做的事嗎? – 2012-07-19 13:55:01

+0

@AaronBertrand不完全是:他想要使用執行計劃,而這會。請注意,它們不是分開的往返,但是所有查詢都在一個到數據庫的單個循環中執行。作爲一個加號,查詢是正確的參數化,以避免注入。 – 2012-07-19 14:01:35