2008-11-19 67 views
45

參數化查詢在.net總是像這樣的例子:與LIKE和IN條件參數化查詢

SqlCommand comm = new SqlCommand(@" 
    SELECT * 
    FROM Products 
    WHERE Category_ID = @categoryid 
", 
    conn); 
comm.Parameters.Add("@categoryid", SqlDbType.Int); 
comm.Parameters["@categoryid"].Value = CategoryID; 

但我遇到一個磚牆努力做到以下幾點:

SqlCommand comm = new SqlCommand(@" 
    SELECT * 
    FROM Products 
    WHERE Category_ID IN (@categoryids) 
     OR name LIKE '%@name%' 
", 
    conn); 
comm.Parameters.Add("@categoryids", SqlDbType.Int); 
comm.Parameters["@categoryids"].Value = CategoryIDs; 
comm.Parameters.Add("@name", SqlDbType.Int); 
comm.Parameters["@name"].Value = Name; 

  • CategoryIDs是用逗號分隔的數字列表 「123,456,789」(不帶引號)
  • 名稱是一個字符串,可能帶有單引號和其他錯誤字符

什麼是正確的語法?

+0

在「IN」clasule中,您必須在SQL命令中指定每個值。 Evenry值添加到「Parameters」集合中。 如果您通過參數值將字符串值傳遞給SQL,那麼您一定不要害怕sql注入。 – TcKs 2008-11-19 20:08:06

+0

您可以編寫您的查詢,如`WHERE name LIKE CONCAT('%',?,'%')` – 2017-10-12 09:49:22

回答

56

假設您的類別ID位於一個整數數組中,並且Name是一個字符串。訣竅是創建命令文本以允許您輸入所有類別標識作爲單獨參數並構建名稱的模糊匹配。爲了實現前者,我們使用循環來構造一系列參數名稱@ p0到@ pN-1,其中N是數組中的分類id的數量。然後我們構造一個參數並將其添加到命令中,並將關聯的類別id作爲每個命名參數的值。然後,我們在查詢本身的名稱上使用連接,以允許對名稱進行模糊搜索。

string Name = "someone"; 
int[] categoryIDs = new int[] { 238, 1138, 1615, 1616, 1617, 
           1618, 1619, 1620, 1951, 1952, 
           1953, 1954, 1955, 1972, 2022 }; 

SqlCommand comm = conn.CreateCommand(); 

string[] parameters = new string[categoryIDs.Length]; 
for(int i=0;i<categoryIDs.Length;i++) 
{ 
    parameters[i] = "@p"+i; 
    comm.Parameters.AddWithValue(parameters[i], categoryIDs[i]); 
} 
comm.Parameters.AddWithValue("@name",$"%{Name}%"); 
comm.CommandText = "SELECT * FROM Products WHERE Category_ID IN ("; 
comm.CommandText += string.Join(",", parameters) + ")"; 
comm.CommandText += " OR name LIKE @name"; 

這是一個完全參數化的查詢,應該讓您的DBA高興。我懷疑由於這些是整數,儘管直接使用值構造命令文本並不會帶來太大的安全風險,但仍然參數化名稱。如果您的類別ID位於字符串數組中,只需以逗號分割數組,將其轉換爲整數,然後將其存儲在整數數組中。

注意:我說數組並在示例中使用它,但它應該適用於任何集合,儘管您的迭代可能會有所不同。

想法來自http://www.tek-tips.com/viewthread.cfm?qid=1502614&page=9

10

您需要sql參數值的「%」。

SqlCommand comm = new SqlCommand("SELECT * FROM Products WHERE Category_ID IN (@categoryid1, @categoryid2) OR name LIKE @name", conn); 
comm.Parameters.Add("@categoryid1", SqlDbType.Int); 
comm.Parameters["@categoryid1"].Value = CategoryID[0]; 
comm.Parameters.Add("@categoryid2", SqlDbType.Int); 
comm.Parameters["@categoryid2"].Value = CategoryID[1]; 
comm.Parameters.Add("@name", SqlDbType.Int); 
comm.Parameters["@name"].Value = "%" + Name + "%"; 
-2

不知道這是正確的做法,但它是一種方法,我已經做到了在之前

列表templist =新名單

comm.Parameters.Add(「@ categoryids」 ,SqlDbType.varchar); comm.Parameters [「@ categoryids」]。value = string.join(「,」,templist.toarray())

+1

不可以。您不能參數化值列表。那麼你可以,但它會將Category_ID與單個*字符串*值'1,2,3'進行比較,而不是與列表中的每個整數值進行比較。這會產生意想不到的結果。 :-) – 2008-11-19 21:30:57

6

此方法不起作用。期。

IN子句的預期本身的參數列表,所以當你綁定一個參數給它,你必須在一個值傳遞的機會。

動態構建您的語句字符串,使用您打算傳入的各個IN子句佔位符的確切數量,然後在循環中添加參數並將值綁定到它們。

+0

另一個訣竅是在SQL中創建大量參數並重復綁定值。這是不雅的,但它的工作原理是因爲IN(1,2,3)和IN(1,2,3,1,2,3,1,2)是等價的謂詞。 – 2008-11-19 21:26:14