之前項目有一放行的功能,對某界面維護時(數據的增刪改),先將數據保存到臨時表中,放行后再真正的寫入到庫中。由於設計到主從表多中約束關系,所以當時我采用的是寫一個存儲過程來對某個界面的操作進行統一處理,具體參見關於MVC項目中的主管放行。現在sa 說不得使用存儲過程為由讓更改(開發文檔中寫明: 盡量少用存儲過程),自以為僅僅是將sql 挪一個位置,實際在修改中 在 in 這個地方還是費了不少時間。
在談及 in 之前,先說下參數傳遞的三種方式
1. 字符串拼接 ' "+str+" ' ,很容易理解,好用,所謂的字符串拼接,對於非前台界面傳入的參數可以直接這樣寫,可避免sql 注入,前台輸入的參數若直接用此方法,則可被sql注入
2. Parameter ,也常見,常規的操作直接傳入參數即可 如update: set A.name = @name 此處name經過sql 編譯后 自動會加入單引號 ' '
3. 占位符 {0},用String.Format 拼接,當某段sql中存在出現多次相同的參數時,用此方法比較方便,如果用2,則要寫para1,para2 ,para3,若用3,只需要寫一個 ‘{0}’
上面的搞清楚了,現在來看一看 in 這個比較特殊的問題,當傳遞的參數本身就包含逗號時,就比較攪了,如 'a1,b1','a2,b2','a3,b3'
諸如: 用到IN的存儲過程,需要轉兩個彎彎,先用EXEC( ' ' ) 包裹一遍,然后里面所用到的值都要加一個單引號,如 '' D'' , 對於IN后帶@的參數,為 '+@str+',普通的參數加兩對單引號
'''+@appuserid+'''
EXEC(' --刪除 DELETE FROM A WHERE TableKey IN (SELECT TableKey FROM tempA WHERE sFlag = ''D'' AND ApplyUserID = '''+@appuserid+''' AND TableKey IN('+@str+')) --清空臨時資源表 DELETE FROM tempZT_SysConfig_Master WHERE TableKey IN ('+@str+'); ')
諸如:一般不需要用到存儲過程、事務和IN關鍵字的SQl 而言,直接寫入即可(成功)
SELECT * FROM A WHERE ApplyUserID = @ApplyUserID
諸如:帶 IN 關鍵字的SQl,單個參數中不含逗號,如: 'A,B,C',或者參數含逗號,如 'a1,b1','a2,b2','a3,b3',采用如下方式去執行Sql,則為失敗;若采用Trim('\'') 去掉首尾單引號,仍然失敗。(采用 ExecuteScalar 去獲取值,不報錯,單結果為 0,正常應該為2)
SELECT COUNT(*) FROM A WHERE ApplyUserID IN(@ApplyUserID)
嘗試了許久,最終改用占位符 { 0 } 解決,注: 普通占位符加單引號,IN 后面則不需要
SELECT COUNT(*) FROM A WHERE ApplyUserID IN({0}) AND NAME = '{1}'
其實占位符還有一個好處,由於之前寫的儲存過程中涉及的參數 @ApplyUserID 和 @Name 用到了多次,若使用字符串拼接覺得比較丑(小小的強迫症),若采用@Parameter 則需要定義很多變量,因為SQL中 Parameter 變量不能重復,而且碰到 IN 這種彎彎,繞起來又比較麻煩,故用占位符 {0} ,實際上操作起來很方便,對於sql中出現多次 @ApplyUserID 用 {0} 代替,@Name用 {1} 代替即可。占位符無關次數。