2013-09-27 39 views
0

我需要做這樣的事情:
T-SQL - 結合IN子句和CASE語句

select * 
from Table 
     inner join Few more tables 
where t2.ID IN(case when @Param1 = 0 then 
         (select ID FROM tbl10 WHERE ForeignKey = @param2) 
       else @Param1 end) 

所以如果@參數1是0的話,我想要一些設定值是一個匹配(基於@ param2),如果它不是0,我只需要@Param1匹配。 我已經嘗試了幾個語法變體,但它不會工作。

我也見過類似的問題,但它並沒有幫助我。

回答

1

你可以試試這個

select * from Table 
inner join Few more tables 
where t2.ID IN(select case when @Param1 = 0 then ID else @Param1 end FROM tbl10 WHERE ForeignKey = @param2) 
+0

這個查詢將無法正常工作。如果tabl10不返回@ param2的任何行怎麼辦? –

+0

如果'@Param2'沒有返回行,那麼除了不工作,即使您不關心結果,當@Param1爲0時,您也會在tbl10上強制進行表掃描。這不是一個有效的解決方案。 – GarethD

4

使用OR

SELECT * 
FROM table1 t1 
     INNER JOIN table2 t2 
       ON t1.t1col = t2.t1col 
WHERE (@param1 <> 0 AND t2.id = @Param1) 
    OR (@param1 = 0 AND t2.id IN (SELECT id 
          FROM tbl10 
          WHERE foreignkey = @param2)) 
0

簡單有效:

select * from Table 
inner join Few more tables 
where 

    -- IF 
    @Param1 = 0 
     and t2.id in (select ID FROM tbl10 WHERE ForeignKey = @param2) 

    -- ELSE 
    or t2.id = @Param1 
+0

這仍然會處理't2.id = @ Param1'爲0'@ param1'值 –

+0

@rs。如果AND IN變爲假,也可以評估't2.id = @ Param1'。只要利用沒有ID爲0的事實。身份從1開始,因此't2.id = 0'將始終爲假。然而,懇求承認,這個簡單的答案在Steve Jobs(他是[Employee Number 0](http://www.dazeinfo.com/2011/01/19/10-amazing-facts-about) -steve-jobs /))的工作,在這種情況下,我會和@ TimSchmelter的答案一起去。否則,這個答案就足夠了 –

+0

我同意你所說的,我指的是你的IF,ELSE評論說它實際上不是一個IF ELSE,因爲兩者都得到評估 –

1
SELECT * 
FROM Table 
     JOIN Few more tables 
WHERE t2.ID IN (
    SELECT @Param1 WHERE @Param1 <> 0 
    UNION ALL 
    SELECT ID FROM tbl10 WHERE ForeignKey = @param2 AND ISNULL(@Param1, 0) = 0 
    ) 
1

我會完全不同處理這和使用IF/ELSE。通過將不同基數與不同基數混合在一起,可以降低優化者選擇最佳查詢計劃的機率。你會得到更好的表現使用這樣的事情:

IF @Param = 0 
    BEGIN 
     SELECT * 
     FROM T 
     WHERE A IN (SELECT TID FROM T2 WHERE ID = 1 @param2); 
    END 
ELSE 
    BEGIN 
     SELECT * 
     FROM T 
     WHERE ID = @Param1; 
    END 

它看起來像更多的代碼,所以應該效率較低,但實際上不是。使用這個測試場景:

CREATE TABLE T (ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, A INT NOT NULL, B INT NULL); 
INSERT T (A, B) 
SELECT A, Number 
FROM ( SELECT TOP 1000 A = RANK() OVER(ORDER BY a.object_id) 
      FROM sys.all_objects a 
     ) a 
     CROSS JOIN (VALUES (1), (2), (3)) n (Number); 

CREATE TABLE T2 (ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, TID INT NOT NULL); 
INSERT T2 (TID) 
SELECT T.ID 
FROM T 
     CROSS JOIN (VALUES (1), (2), (3)) n (Number); 

CREATE NONCLUSTERED INDEX IX_T_A ON T (A); 
CREATE NONCLUSTERED INDEX IX_T2_TID ON T2 (TID); 
GO 
CREATE PROCEDURE dbo.Proc1 @Param1 INT, @Param2 INT 
AS 
    SELECT ID, A, B 
    FROM T 
    WHERE (@param1 <> 0 AND t.A = @Param1) 
     OR (@param1 = 0 AND t.A IN(SELECT TID FROM T2 WHERE ID = @param2)); 

-- (SORRY TIM, BUT YOURS WAS THE BEST OF THE REST) 
GO 

CREATE PROCEDURE dbo.Proc2 @Param1 INT, @Param2 INT 
AS 
    IF @Param1 = 0 
     BEGIN 
      SELECT ID, A, B 
      FROM T 
      WHERE A IN (SELECT TID FROM T2 WHERE ID = @param2); 
     END 
    ELSE 
     BEGIN 
      SELECT ID, A, B 
      FROM T 
      WHERE A = @Param1; 
     END 

GO 

如果運行的第一個程序(不帶IF),因爲SQL-Server不知道什麼@參數1和@參數2將在編譯的時候,它不知道哪些條件見面會,所以不能相應地優化,所以創造了兩個條件

EXECUTE dbo.Proc1 1, 1; 
EXECUTE dbo.Proc1 0, 1; 

enter image description here

同樣的計劃反之,如果你使用SQL IF/ELSE - 服務器可以爲每個條件下的最優方案:

EXECUTE dbo.Proc2 1, 1; 
EXECUTE dbo.Proc2 0, 1; 

enter image description here

在這種情況下的實際影響並不如查詢計劃建議的那樣糟糕,因爲SQL-Server是運行時不夠聰明,不評估subuqery如果@Param1 = 0從T2選擇,並我並不是說永遠不會有使用多個條件的情況,但通常情況下,當您有一個影響所需謂詞的常量時,最好將它與IF/ELSE分開,而不是將兩個謂詞混合在一起。

有時較少的代碼並不總是更高效的查詢。

DDL and queries on SQL-Fiddle

0

我喜歡與IF語句的方法,但是如果你不喜歡它,試試這個,與UNION ALL

SELECT * 
FROM table1 t1 
    INNER JOIN table2 t2 
      ON t1.t1col = t2.t1col 
WHERE @param1 <> 0 AND t2.id = @Param1 
UNION ALL 
SELECT * 
FROM table1 t1 
    INNER JOIN table2 t2 
      ON t1.t1col = t2.t1col 
    INNER JOIN tbl10 
      ON t2.ID =tbl10.ID 
      AND foreignkey = @param2 
WHERE @param1 = 0