編程經(jīng)驗點滴----動態(tài) SQL 的拼接技巧
最近在博客園上,看到經(jīng)常有人誤解動態(tài) SQL 的拼接。比如我的一篇博客文章:
評“CPQuery, 解決拼接SQL的新方法”
http://www.rzrgm.cn/jacklondon/archive/2012/09/11/2679738.html?updated=1
眾多人在回復(fù),其中至少有三位老兄,誤解了動態(tài) SQL 的拼接。
特寫此文,闡述一下其中的技巧。希望能糾正初學(xué)者的錯誤。
常見的誤解有:
1. 只用 ado.net ,無法進(jìn)行動態(tài) SQL 拼接。
2. 有幾個動態(tài)參數(shù),代碼的重復(fù)量就成了這些參數(shù)的不同數(shù)量的組合數(shù),動態(tài)參數(shù)越多,重復(fù)量越大。
對于第二個問題,以下的錯誤代碼為其證據(jù):
if(id>0 && string.IsNullOrEmpty(name)) { command.CommandText = "select * from t1 where id=?"; command.Parameters.Add(id); } if(id<=0 && !string.IsNullOrEmpty(name)) { command.CommandText = "select * from t1 where name=?"; command.Parameters.Add(name); } if(id<=0 && !string.IsNullOrEmpty(name)) { command.CommandText = "select * from t1 where id=? and name=?"; command.Parameters.Add(id); command.Parameters.Add(name); }
這兩個問題都很好解決,給一個正確的代碼例子大家看看即可:
string sql ="select * from t1 where 1=1"; if(id != null) { sql += " and id=?"; addParameterValue(cmd,id); } if(!string.IsNullOrEmpty(name)) { sql += " and name=?"; addParameterValue(cmd,name); } command.CommandText = sql;
這里的技巧在于,使用了一個 "where 1=1", 巧妙解決了后續(xù) sql 拼接中,每行開頭是否要有 "and" 的問題。而這個 "where 1=1",并不會對數(shù)據(jù)庫的索引執(zhí)行,造成性能上的影響。
對參數(shù)進(jìn)行排列組合,然后寫各種組合的 SQL,這個思路很奇怪。問題是,很多初學(xué)者,都有這個思維習(xí)慣。本人不是計算機(jī)科班出身,不知道是否哪本教科書,就是如此教導(dǎo)的。但很不幸的是,這個錯誤思維習(xí)慣廣泛存在于很多人的心中。
"where 1=1" 雖是教科書中沒有的小技巧,卻很管用。
另外,在程序中,一般會在用戶界面上讓使用用戶錄入數(shù)字,這個數(shù)字的數(shù)值,在代碼中會自動變成 string,然后嘗試 string 轉(zhuǎn)換成 int/long,最后送到 sql 函數(shù)里。這里需要特別注意的是,很多人把某個特殊的數(shù)值,作為“用戶無錄入的默認(rèn)值”,正如本文開頭所寫的錯誤代碼那樣:
if(id>0 && string.IsNullOrEmpty(name))
問題在于,0 是否是不正常的業(yè)務(wù)數(shù)值,代碼中看不出來。不排除程序員隨意指定一個數(shù)值,作為“用戶無錄入的默認(rèn)值”,如果不巧這個默認(rèn)值,有其他意義的,那就造成問題。
在數(shù)據(jù)庫的理論中,沒有指定的數(shù)據(jù),是用 null 來表示的,不論是 string 還是 int/long。
這是一個很好的思路,同樣可以用在這里的 sql 拼接中。因此,我們在后面的代碼中,使用了這個:
if(id != null)
上述代碼中,
addParameterValue(cmd,name);
是一個簡單封裝的函數(shù),用來封裝如下一小段代碼,目的是讓最后的代碼,較為簡捷直觀:
DbParameter p = cmd.CreateParameter(); p.ParameterName = "@XXX"; p.Value = TTT; cmd.Parameters.Add(p);
當(dāng)然,這個 addParameterValue() 封裝函數(shù),是可有可無的。多寫幾個 DbParameter p = cmd.CreateParameter() 并沒有什么大問題。
-------------歡迎大家下載試用折桂單點登錄系統(tǒng), http://zheguisoft.com

浙公網(wǎng)安備 33010602011771號