所謂的動態sql,就是在t-sql字符串內的sql,而靜態sql就是直接寫在t-sql 存儲過程內的。動態sql的好處是可以寫出非常複雜的,表達能力很強的sql,並且,因爲某些條件下sql更簡單,因此號稱效率更好。而靜態sql的好處在於可以調試,可以代碼提示。不管怎樣,我發現我們的sql很多都是動態的。尤其是在sqlserver缺乏分頁支持的sql2000,很多需要分頁的存儲過程都是這樣的。動態sql的強大能力來自於字符串的拼接,因此,如何改善字符串拼接就是對代碼可讀性進行優化的關鍵。如果能夠改成靜態sql而不必犧牲性能就更好了。
1. 加號拼接
這是最常見的拼接,特點是好寫,缺點是難讀。很多時候容易寫的代碼往往不容易閱讀——因爲不需要爲變量取名字,完全就是具體數值的思維就可以。而需要參數化的sql語句,需要的是稍微抽象的參數化的思維。不過參數化的思維也不難,畢竟我們從初一就開始學習參數化的數學了。
Sql = "select top 1 typeid,sonnum,deleted from ptype where (usercode='" + pFullName + "' or fullname='" + pFullName + "') and typeid ='" + ptypeid + "'";
代碼表示更加usercode,fullname,typeid的條件,列出 ptype表的第一行。這裏面的“+”的引入,導致整個sql在閱讀角度看起來是支離破碎,難以一目瞭然的瞭解代碼的意圖。其中的涉及到sql字符串定界符的“’”的處理也讓人覺得很傷心。
儘管以c#代碼爲例,但是在t-sql內利用“+”來拼接也不在少數,表現的問題也差不多一樣。
2. format拼接
還是以同樣的代碼爲案例,以格式化函數的方式來看:
Sql = "select top 1 typeid,sonnum,deleted from ptype where (usercode='{0}'' or fullname='{0}') and typeid ='{1}'";
Sql=string.format(sql,fullname,typeid);
儘管增加了一個函數,但是sql顯然變得比較完整,sql本身不完整的信息,以參數的方式提出來,“'”帶來的閱讀干擾也不像“加號拼接”那麼礙眼。當然問題也是存在的:首先因爲參數採用數字,因此當sql大些,參數多些的時候,找到參數對應關係會變得很麻煩。其次,依然存在sql injection(sql注入)的問題。
3. AddParameter拼接
還是以同樣的代碼爲案例,以格式化函數的方式來看:
Sql = "select top 1 typeid,sonnum,deleted from ptype where (usercode=@fullname or fullname=@fullname) and typeid =@typeid";
db.AddParameter("@fullname", fullname);
db.AddParameter("@typeid",typeid);
我個人認爲,這個方式的拼接sql方法是最好的。不但sql可以完整的閱讀,參數還是有名稱的——這樣即使參數很多,sql很長,對閱讀的額外障礙也不多。也不存在sql injection問題。至於"'"也無需考慮了。 但是需要爲變參想名字,這是寫起來要麻煩的一個原因吧。
這三種sql拼接的風格,都是以c#爲例的,但是對存儲過程也是一樣的效果。僅僅是換門語言而已。
側寫:我看過的克服“‘”閱讀干擾的方法:
採用 CHAR(10)來替代"'"
SET @strSQL=@strSQL+' LEFT JOIN SCM_BillType t ON a.BillType = t.BillType '+CHAR(10)
SET @strSQL=@strSQL+' LEFT JOIN Pub_DType d ON a.DID = d._ID '+CHAR(10)
這段代碼還表明,作者希望通過left join前面加入很多空格來對齊,一邊可以print來查看最後的sql是什麼。看來,這個sql的作者寫代碼的時候也是希望看到完整的sql的。
改善sql字符串的可讀性 - sql字符串常見編寫風格
2010年5月18日
10:31