0

我需要做这样的事情:

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 匹配。我尝试了一些语法变化,但它不会工作。

我也看到了一个类似的问题,但它对我没有帮助。

4

6 回答 6

5

利用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) ) 
于 2013-09-27T14:35:09.623 回答
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)
于 2013-09-27T14:29:42.287 回答
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 在编译时不知道@Param1 和@Param2 会是什么,所以它不知道会满足哪个条件,所以无法进行相应的优化,所以为两种情况创建相同的计划

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

在此处输入图像描述

然而,如果您使用IF/ELSESQL-Server 可以为每个条件创建最佳计划:

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

在此处输入图像描述

在这种情况下,实际影响并不像查询计划所建议的那么糟糕,因为 SQL-Server 在运行时足够聪明,不会评估 subuqery 以从 T2 if 中选择@Param1 = 0,而且我并不是说永远不会使用多个OR条件,但通常当您有一个影响您想要的谓词的常量时,最好用 IF/ELSE 将其分开,而不是将两个谓词混在一起。

有时更少的代码并不总是更有效的查询。

SQL-Fiddle 上的 DDL 和查询

于 2013-09-27T15:39:42.887 回答
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
   )
于 2013-09-27T15:02:07.177 回答
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
于 2013-09-27T14:39:44.597 回答
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
于 2013-09-28T04:10:29.180 回答