[英]T-SQL - Combine IN Clause and CASE statement
我需要做這樣的事情:
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)
因此,如果@ Param1為0,那么我希望某組值是一個匹配項(基於@ param2),如果其不為0,我只希望@ Param1進行匹配。 我嘗試了幾種語法變體,但無法正常工作。
我也看到過類似的問題,但這並沒有幫助我。
使用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) )
你可以試試這個嗎
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)
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
)
我將采用完全不同的方法,並使用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不知道@ Param1和@ Param2在編譯時將是什么,因此它不知道滿足哪個條件,因此無法相應地進行優化,因此為兩種情況創建相同的計划
EXECUTE dbo.Proc1 1, 1;
EXECUTE dbo.Proc1 0, 1;
而如果使用IF/ELSE
SQL Server可以為每種情況創建最佳計划:
EXECUTE dbo.Proc2 1, 1;
EXECUTE dbo.Proc2 0, 1;
在這種情況下,實際影響並不像查詢計划所建議的那樣糟糕,因為如果@Param1 = 0
,則SQL-Server在運行時足夠聰明,不會評估要從T2中選擇的子查詢,我並不是說永遠不會使用多個OR
條件的情況,但是通常當您有一個影響謂詞的常數時,最好使用IF / ELSE將其分隔,而不是將兩個謂詞混在一起。
有時更少的代碼並不總是更有效的查詢。
簡單有效:
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
我喜歡並使用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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.