国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > SQL Server > 正文

SqlServer參數化查詢之where in和like實現詳解

2024-08-31 00:45:13
字體:
來源:轉載
供稿:網友
身為一名小小的程序猿,在日常開發中不可以避免的要和where in和like打交道,在大多數情況下我們傳的參數不多簡單做下單引號、敏感字符轉義之后就直接拼進了SQL,執行查詢,搞定。若有一天你不可避免的需要提高SQL的查詢性能,需要一次性where in 幾百、上千、甚至上萬條數據時,參數化查詢將是必然進行的選擇。然而如何實現where in和like的參數化查詢,是個讓不少人頭疼的問題。

where in 的參數化查詢實現

首先說一下我們常用的辦法,直接拼SQL實現,一般情況下都能滿足需要

復制代碼 代碼如下:


string userIds = "1,2,3,4";
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = string.Format("select * from Users(nolock) where UserID in({0})", userIds);
comm.ExecuteNonQuery();
}


需要參數化查詢時進行的嘗試,很顯然如下這樣執行SQL會報錯錯誤

復制代碼 代碼如下:


using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users(nolock) where UserID in(@UserID)";
comm.Parameters.Add(new SqlParameter("@UserID", SqlDbType.VarChar, -1) { Value = "1,2,3,4" });
comm.ExecuteNonQuery();
}


很顯然這樣會報錯誤:在將 varchar 值 '1,2,3,4' 轉換成數據類型 int 時失敗,因為參數類型為字符串,where in時會把@UserID當做一個字符串來處理,相當于實際執行了如下語句

復制代碼 代碼如下:


select * from Users(nolock) where UserID in('1,2,3,4')


若執行的語句為字符串類型的,SQL執行不會報錯,當然也不會查詢出任何結果

復制代碼 代碼如下:


using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users(nolock) where UserName in(@UserName)";
comm.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar, -1) { Value = "'john','dudu','rabbit'" });
comm.ExecuteNonQuery();
}


這樣不會抱任何錯誤,也查不出想要的結果,因為這個@UserName被當做一個字符串來處理,實際相當于執行如下語句

復制代碼 代碼如下:


select * from Users(nolock) where UserName in('''john'',''dudu'',''rabbit''')


由此相信大家對于為何簡單的where in 傳參無法得到正確的結果知道為什么了吧,下面我們來看一看如何實現正確的參數化執行where in,為了真正實現參數化where in 傳參,很多淫才想到了各種替代方案

方案1,使用CHARINDEX或like 方法實現參數化查詢,毫無疑問,這種方法成功了,而且成功的復用了查詢計劃,但同時也徹底的讓查詢索引失效(在此不探討索引話題),造成的后果是全表掃描,如果表里數據量很大,百萬級、千萬級甚至更多,這樣的寫法將造成災難性后果;如果數據量比較小、只想借助參數化實現防止SQL注入的話這樣寫也無可厚非,還是得看具體需求。(不推薦)

復制代碼 代碼如下:


using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
//使用CHARINDEX,實現參數化查詢,可以復用查詢計劃,同時會使索引失效
comm.CommandText = "select * from Users(nolock) where CHARINDEX(','+ltrim(str(UserID))+',',','+@UserID+',')>0";
comm.Parameters.Add(new SqlParameter("@UserID", SqlDbType.VarChar, -1) { Value = "1,2,3,4" });
comm.ExecuteNonQuery();
}

using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
//使用like,實現參數化查詢,可以復用查詢計劃,同時會使索引失效
comm.CommandText = "select * from Users(nolock) where ','+@UserID+',' like '%,'+ltrim(str(UserID))+',%' ";
comm.Parameters.Add(new SqlParameter("@UserID", SqlDbType.VarChar, -1) { Value = "1,2,3,4" });
comm.ExecuteNonQuery();
}


方案2 使用exec動態執行SQL,這樣的寫法毫無疑問是很成功的,而且代碼也比較優雅,也起到了防止SQL注入的作用,看上去很完美,不過這種寫法和直接拼SQL執行沒啥實質性的區別,查詢計劃沒有得到復用,對于性能提升沒任何幫助,頗有種脫了褲子放屁的感覺,但也不失為一種解決方案。(不推薦)

復制代碼 代碼如下:


using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
//使用exec動態執行SQL
  //實際執行的查詢計劃為(@UserID varchar(max))select * from Users(nolock) where UserID in (1,2,3,4)
  //不是預期的(@UserID varchar(max))exec('select * from Users(nolock) where UserID in ('+@UserID+')')
comm.CommandText = "exec('select * from Users(nolock) where UserID in ('+@UserID+')')";
comm.Parameters.Add(new SqlParameter("@UserID", SqlDbType.VarChar, -1) { Value = "1,2,3,4" });
comm.ExecuteNonQuery();
}


方案3 為where in的每一個參數生成一個參數,寫法上比較麻煩些,傳輸的參數個數有限制,最多2100個,可以根據需要使用此方案(推薦)

復制代碼 代碼如下:

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 郴州市| 山阴县| 灵石县| 新河县| 曲麻莱县| 怀安县| 广水市| 石楼县| 丹江口市| 环江| 温州市| 罗平县| 温州市| 漾濞| 涟水县| 东光县| 弋阳县| 九江县| 天峨县| 灵川县| 喜德县| 耒阳市| 志丹县| 广昌县| 汾阳市| 慈利县| 环江| 漠河县| 萝北县| 安康市| 尼勒克县| 延寿县| 南京市| 莱州市| 犍为县| 安塞县| 文成县| 普格县| 嘉鱼县| 徐汇区| 百色市|