Posted on 2006-08-15 17:06
大大毛 閱讀(1363)
評論(1) 編輯 收藏 所屬分類:
SQL
???起因:
??????在工作中經常都會用到根據一個參數的值來做不同的 Where 條件的情況,例如:
??????1.在提供給用戶的查詢界面上提供了多個篩選條件,如果用戶選了就使用條件,如果不選就放棄該條件;
??????2.存儲過程的預留擴充功能,如 當前要求返回條件為真的記錄,為了擴充,讓存儲過程根據參數可以返回條件為 真/假/全部 的記錄等。
??????在這些情況下,通常有3種實現方法:
?????????a.在外部(相對于數據庫)拼裝查詢語句,我稱它為外部動態SQL,嘻嘻;
?????????b.在內部(同上)拼裝查詢語句,我稱它為內部動態SQL;
?????????c.在存儲過程中使用大量的 IF 開關,搭配 ctrl+C,ctrl+V,edit操作,寫上N條的SQL語句。
???問題的分析:
??????a 方法,該方法最多見,因為這是非常easy的辦法,而且適用面最廣,干啥事都直接來個SQL語句發往連接對象即可。當然這種方法在實現時也是N多的 IF,同時這種方法也會遺留下隱患,稍不留神就會成為 SQL注入 的犧牲品。
??????b 方法,只是在存儲過程實現了 a 方法,在減少隱患的同時,縮小了適用面,比如低版本的 mysql 就不支持存儲過程。
??????c 方法,是 b 方法的變種,雖然代碼量非常的大,但是結構上很清晰,執行速度快。
???解決方法:
??????在工作中找到的一個方法,適用于一定的問題域,可以將N多的SQL合并。
??????為了能夠清楚的說明,舉個例子先。
??????例(特定值的條件查詢):
????????????現在提供一個查詢界面給管理員,讓他能夠對 log表 的查詢條件進行定制。
????????????查詢條件有:
???????????????1.組ID,對應字段gID
???????????????2.用戶ID,對應字段uID
???????????????3.記錄類型,對應字段logType
????????????條件的判斷為:
???????????????如果用戶選擇了條件,那么就在Where中進行篩選,否則就忽略該條件,例如用戶如果選擇了 gID=1,那么就只選擇組ID=1的用戶Log,否則就返回全部的用戶。通常是用上IF,這樣:
string
?sql?
=
?
"
select?*?from?log?
"
;
string
?where?
=
?
""
;
if
(gID?
!=
?
null
)?{
??where?
=
?where?
+
?
"
?gID=
"
?
+
?gID?
+
?
"
?and?
"
;
}
//
更多的IF
//
where字串還要處理一下
sql?
+=
?where;
??????現在使用MS SQL 的存儲過程可以這樣實現:
定值條件查詢
--
取得Log
--
gID(int):組ID
--
uID(int):用戶ID
--
logType(int):log類型
create
?
procedure
?p_getLog
??
@gID
?
int
?
=
?
null
,
??
@uID
?
int
?
=
?
null
,
??
@logType
?
int
?
=
?
null
as
begin
??
select
??????
*
????
from
??????
log
????
where
??????gID?
=
?
isNull
(
@gID
,gID)?
and
??????uID?
=
?
isNull
(
@uID
,uID)?
and
??????logType?
=
?
isNull
(
@logType
,logType)
end
??????仔細分析一下上面的存儲過程不難看出問題所在,實際上就是用了Ms SQL的 isNull系統函數,它在判斷特征值或列為空時,就用第2參數所示的值或列去取代,否則就取原值,就拿 gID = isNull ( @gID , gID ) 語句來說吧,
??????@gID?為一個非空值時,如?@gID = 1,那么表達式成為 where gID = 1
??????@gID的值為空 =null 時?,那么該表達式實現上就成了 where gID = gID,多了這個不用擔心會增加負荷,數據庫還是有點智能會忽略掉這個條件的,嘻。
??????上面的代碼是一個比較簡單的例子,可以在存儲過程的代碼區增加對輸入參數的過濾,如 if?not exists(select 1 from log where gID = @gID) set @gID=null 等。
??????這樣一來,既可以利用存儲過程帶來的好處,又利用了 isNull 帶來的實惠,一舉N得啊。
???后記:
??????這個解決方案是存在有局限性的,并不是什么地方都能適用,但是它也不失為一個解決問題的方法。
??????--是人總要有點自己的想法,呵呵。