2017-03-16 96 views
2

我有一個存儲過程,以根據傳入過濾器類型和過濾器值過濾表的結果。SQL更改WHERE列和值取決於傳入變量

目前這是一個非常大的if/else語句:

IF @FilterBy = 'CustomerName' 
    SELECT X, Y, Z 
    FROM @Table 
    WHERE CustomerName = @FilterValue 
    ORDER BY CustomerID 

ELSE IF @FilterBy = 'OrderID' 
    SELECT X, Y, Z 
    FROM @Table 
    WHERE OrderID = CAST(@FilterValue AS SMALLINT) 
    ORDER BY CustomerID 

我有5個否則,如果和我總是從同一個表中選擇相同的列。有沒有辦法使用像WHERE子句的CASE或switch語句來清理代碼?

+3

標籤您正在使用的數據庫管理系統。該代碼是特定於產品的。 – jarlh

+2

使用AND/OR代替這種if(或case)結構通常會更好。 – jarlh

+1

動態SQL可能是最好的方法。這將強制查詢被重新編譯,這將確保最佳的執行計劃,而不管WHERE條款如何。 –

回答

1

您認爲這對您有用嗎?

SELECT X, Y, Z 
    FROM @Table 
    WHERE CustomerName = @FilterValue AND @FilterBy = 'CustomerName' 
     OR 
     OrderID = CAST(@FilterValue AS SMALLINT) AND @FilterBy = 'OrderID' 
     OR 
     ... 
    ORDER BY CustomerID 
+0

不太可能工作得很好 - 對查詢內謂詞的執行順序沒有保證,所以即使設置了@ FilterBy,系統也可以很容易地決定嘗試將Smith先生轉換爲smallint。到'客戶名'併產生一個錯誤。 –

2

嘗試類似下面的查詢,

SELECT X, Y, Z 
    FROM @Table 
    WHERE CustomerName = (CASE WHEN @FilterBy = 'CustomerName' 
           THEN @FilterValue ELSE CustomerName END) 
    AND OrderID   = (CASE WHEN @FilterBy = 'OrderID' 
           THEN CAST(@FilterValue AS SMALLINT) ELSE OrderID END) 
    ORDER BY CustomerID 
+1

第二個變體應該可以正常工作,但第一個變體會遇到與我在etsa答案中指出的相同的問題 - 不能保證謂詞的評估順序,也不能保證短路,因此可以通過試圖將非orderID轉換爲'smallint'。如果查詢中不涉及聚合,'CASE'*應該*在這裏提供保護。 –

+0

@Damien_The_Unbeliever,修改,謝謝你。 –

0
Use CASE Statement in WHERE Clause to achieve your result easily : 

SELECT X, Y, Z FROM @Table 
WHERE CustomerName = CASE WHEN @FilterValue = 'CustomerName' THEN 
    @FilterValue ELSE CustomerName END AND 
    OrderID = CASE WHEN @FilterValue = 'OrderID' THEN CAST(@FilterValue AS   
    SMALLINT) ELSE OrderID END AND 
    --- Your another 3 case statements like above format---- 
ORDER BY CustomerID