2014-03-19 30 views
1

我創建的SQL Server 2008的存儲過程中的主要查詢的WHERE條款可能是要麼T-SQL:決定2之間WHERE子句

WHERE (MyTable.Code = 'A') 

WHERE (MyTable.Code <> 'A') 

問題:處理這個最簡單的方法是什麼?有一個輸入參數,告訴哪個條件使用,然後使用一個if語句使用第一個SQL語句,否則第二個?似乎不是最有效的方式。

此外,有沒有辦法將整個WHERE子句作爲輸入參數傳遞?

實例參數

@WHERE: "WHERE (MyTable.Code='A') 

,這樣就可以做...

SELECT * FROM TABLE @WHERE 
+0

動態SQL,等於或也不是參數相同。 – Mihai

+2

這聽起來像你可能會走下去的路線,文章[T-SQL中的動態搜索條件](http://www.sommarskog.se/dyn-search.html)將是最好的閱讀。 –

回答

1

有一個,如果在存儲過程中聲明這兩個查詢之間的決定優於(在我看來)將where子句作爲參數傳遞。如果您將where子句作爲參數傳遞,那麼數據庫的邏輯將泄漏到上面的圖層中。另外,根據你如何構建你的圖層,你可以打開自己的SQL注入攻擊。

它會出現,雖然他們是兩個不同的查詢,所以也許這將更適合作爲兩個存儲過程,然後決定在你的調用代碼中調用哪一個。

+0

其實並非如此。 SQL Server將在第一次運行時緩存存儲過程的執行計劃,這將導致僅適用於兩個選項之一的計劃 –

+0

執行計劃不會相同嗎?它只是在同一列上做不同的查詢? –

+0

對此答案+1。 @PanagiotisKanav這兩個查詢將有不同的where子句,不同的查詢計劃和bit參數不是查詢的一部分。這意味着每個查詢都針對其作業進行了優化,並且該參數的值不會影響創建的查詢計劃。所有其他(到目前爲止)構建一個合併where子句的答案最終會按照您的建議結束。 SQL Server將構建與位列值最匹配的where子句,在另一種情況下,該子句可能非常糟糕。動態SQL將工作或查詢提示'選項recompile'在組合where子句。 –

3

最簡單的路線是有額外的參數,將決定哪一個使用以下方式。唯一的問題是,當你開始這樣做時,最終可能會導致錯誤的執行計劃。

DECLARE @Bit BIT = 0; 

SELECT * 
FROM dbo.MyTable AS m 
WHERE (m.Code <> 'A' AND @Bit = 0) 
    OR (m.Code = 'A' AND @Bit = 1) 

爲了避免錯誤的執行計劃,您有幾個不同的選項。

  • OPTION(RECOMPILE)
  • OPTION(OPTIMIZE FOR(@變量= VALUE))
  • OPTION(OPTIMIZE FOR(@VARIABLE未知))
  • 使用局部變量

你可以閱讀更多關於它的地方Parameter Sniffing Problem and Possible Workarounds

在你的情況下,最簡單的就是使用局部變量。

例如:

CREATE PROC dbo.GetSomeData (@pBit BIT) 
AS 
BEGIN 
    DECLARE @Bit BIT = @pBit; 

    SELECT * 
    FROM dbo.MyTable AS m 
    WHERE (m.Code <> 'A' AND @Bit = 0) 
     OR (m.Code = 'A' AND @Bit = 1) 
END 
0

可以使用動態SQL,但在這種情況下,它是沒有必要的。只需使用條件WHERE子句:

CREATE PROCEDURE ... 
(@IsA bit) 
AS 

SELECT ... 
WHERE (@IsA = 1 AND MyTable.Code='A') 
    OR (@IsA = 0 AND MyTable.Code<>'A') 

有沒有辦法通過整個WHERE子句中作爲輸入參數?

哦,當然,你可以在把它作爲一個字符串,但也有很多風險與這樣做:

  1. 該程序可以;噸被預編譯,因爲你的SQL將是動態。
  2. 您增加SQL注入攻擊的風險
  3. 客戶端必須深入瞭解底層SQL的結構以提供適當的WHERE子句。
0

如果你的輸入參數是一個布爾值,或任何爲此事,你可以做這樣的事情:

SELECT * 
FROM MyTable 
WHERE (MyTable.Code='A' AND MyParameter='Equals') 
    OR (My.Table.Code <> 'A' AND MyParementer='NotEqual') 

我用類似這樣的事情在過去做到這一點。

0

我建議使用參數來決定使用哪個WHERE子句。

假設您有一個名爲@WhereClauseToUse的參數。

你可能有這樣的事情:

select * 
from table 
where (@WhereClauseToUse = 1 and Code = 'A') 
    or (@WhereClauseToUse = 2 and Code <> 'A') 
1

如果你正在尋找的東西快速和容易的作品,你可以使用標誌(或任何條件決定WHERE子句中使用它),兩者結合成一個單個WHERE子句。

WHERE (@flag = 1 AND code = 'A') OR (@flag = 0 AND code <> 'A')

在飛行更高級的SQL,您可以使用dynamic sql。在WHERE子句中

0

我使用的條件,像

-- @A = 1/true, then WHERE (MyTable.Code = 'A') 
-- @A = 0/false, then WHERE (MyTable.Code <> 'A') 
declare @A bit 

WHERE ((MyTable.Code = 'A' and @A = 1) OR (MyTable.Code <> 'A' and @A = 0))