2010-05-09 130 views
3

我試圖在SQL Server 2008數據庫的表上執行查詢。我有一個使用五個int參數的存儲過程。目前,我的參數定義如下:SQL Server 2008中的條件WHERE子句

@memberType int, 
@color int, 
@preference int, 
@groupNumber int, 
@departmentNumber int 

此過程將通過-1或更高的每個參數。值爲-1意味着WHERE子句不應該在join /子句中考慮該參數。如果參數的值大於-1,我需要考慮我的WHERE子句中的值。我寧願不使用IF-ELSE語句,因爲這種情況似乎很sl sl。我看到這個問題here。但是,它並不適合我。我認爲原因是因爲我的表中的每個列都可以有一個NULL值。有人在第五個答案中指出了這種情況。這似乎正在發生在我身上。

對我的問題有沒有一個流暢的方法?還是我只是需要蠻力(我希望不會:()

謝謝

回答

4

我做了這樣的事情在過去的:!

SELECT 
    ..... 
FROM 
    dbo.SOMETABLE AS T 
WHERE 
    (T.memberType = @memberType OR @memberType = -1) 
    AND (T.color = @color OR @color = -1) 
    AND (T.preference = @preference OR @preference = -1) 
    AND (T.groupNumber = @groupNumber OR @groupNumber = -1) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber = -1) 

但一般來說, 。我說我不關心參數爲NULL,則查詢變爲:

SELECT 
    ..... 
    FROM 
    dbo.SOMETABLE AS T 
    WHERE 
    (T.memberType = @memberType OR @memberType IS NULL) 
    AND (T.color = @color OR @color IS NULL) 
    AND (T.preference = @preference OR @preference IS NULL) 
    AND (T.groupNumber = @groupNumber OR @groupNumber IS NULL) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber IS NULL) 
+0

這比使用'COALESCE'(對於NULL情況下)更快嗎? – crush 2016-05-09 21:00:08

1

我建議動態SQL - 根據收到的參數生成查詢作爲字符串(VARCHAR)僅添加項目Ť o你真正需要的where子句。然後使用sp_executesql來運行它。動態SQL通常比預編譯的SQL效率低,但在你的情況下,這聽起來像是正確的路要走。請務必參數化查詢,爲優化程序提供重用查詢計劃時的最佳選擇。

+0

我一直在存儲過程中發現動態SQL有點奇怪。關於我曾經使用過的唯一時間是在某些公開的情況下。 – BradBrening 2010-05-09 20:33:13

+0

我通常在搜索頁面等用戶有許多不同的過濾選項的地方使用它。很多時候,這不是'where'子句中的一些額外'或'的簡單問題 - 它還可能需要'from'子句中的附加表。在這些情況下使用動態sql可能會比試圖覆蓋所有基礎的單個巨大查詢更有效。 – Ray 2010-05-09 20:49:37

3

我意識到線程是舊的,但這裏有一些額外的細節可能有助於作出適當的決定。有多種解決方案:

1)

SELECT ... 
FROM ... 
WHERE 
    (T.memberType = @memberType OR @memberType = -1) 
    AND (T.color = @color OR @color = -1) 
    AND (T.preference = @preference OR @preference = -1) 
    AND (T.groupNumber = @groupNumber OR @groupNumber = -1) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber = -1) 

2)

SELECT ... 
FROM ... 
WHERE 
    (T.memberType = @memberType OR @memberType IS NULL) 
    AND (T.color = @color OR @color IS NULL) 
    AND (T.preference = @preference OR @preference IS NULL) 
    AND (T.groupNumber = @groupNumber OR @groupNumber IS NULL) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber IS NULL) 

3)動態生成的DML和使用EXECUTE語句

4)動態生成的DML和使用sp_executesql的

選項1和2幾乎是一樣的......我會傾向於使用IS NULL而不是-1,但是與大多數情況一樣,這取決於情況。這些選項的缺點之一是存儲過程的第一次執行將產生一個查詢計劃,這個查詢計劃將在隨後的所有調用中重用...隨着參數值的變化(具體而言,您想忽略哪些),最初的查詢計劃可能不再是最佳計劃......要解決此問題,請使用WITH RECOMPILE選項(注意每次調用該過程時都會重新編譯該過程)。

隨着向表中添加更多數據和/或將更多條件添加到WHERE子句中,選項3和4的性能會更好。但是,這些選項需要更多努力來編寫存儲過程,並需要對輸入參數進行更多驗證,以最大限度地減少潛在的SQL注入漏洞。選項4比選項3更好,從某種意義上講更簡單一些,因爲動態生成的SQL包含參數名稱,從而導致更有效的查詢計劃重用。動態生成的SQL的另一個缺點是調用存儲過程的用戶必須擁有對基礎表/視圖的所有必要權限,除非該過程是使用WITH EXECUTE AS ...子句定義的。

最後,我通常使用動態生成的SQL和sp_executesql來產生性能最好的查詢。