Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
T-SQL-组合IN子句和CASE语句_Sql_Tsql_Sql Server 2008 R2_Case - Fatal编程技术网

T-SQL-组合IN子句和CASE语句

T-SQL-组合IN子句和CASE语句,sql,tsql,sql-server-2008-r2,case,Sql,Tsql,Sql Server 2008 R2,Case,我需要这样做: 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 因此,如果@Param1是0,那么我希望

我需要这样做:

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
因此,如果@Param1是0,那么我希望一些值集是基于@param2的匹配,如果不是0,我只希望@Param1匹配。 我尝试了一些语法变体,但不起作用

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

你能试试这个吗

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 
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/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/ELSE,SQL Server可以为每个条件创建最佳计划:

EXECUTE dbo.Proc2 1, 1;
EXECUTE dbo.Proc2 0, 1;
在本例中,实际影响并不像查询计划所建议的那样严重,因为SQL Server在运行时足够聪明,不会在@Param1=0时评估从T2中选择的子uqery,我并不是说永远不存在使用多个OR条件的情况,但通常当您有一个影响您想要的谓词的常量时,最好用IF/ELSE将其分开,而不是将两个谓词混在一起

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


我喜欢并接近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

此查询将不起作用。如果tabl10没有为@param2返回任何行,该怎么办?除了在@param2没有返回任何行时不工作之外,当@Param1为0时,您还强制tbl10上的表扫描,即使您不关心结果。这不是一个有效的解决方案。这仍将为0@Param1处理t2.id=@Param1value@rs.是t2.id=@Param1也可以在AND IN变为false时进行计算。只是利用了没有ID 0的事实。标识以1开头,因此t2.id=0将始终为false。然而,我不得不承认,这个简单的答案在史蒂夫·乔布斯所在的系统中是行不通的,在这种情况下,我将采用@TimSchmelter的答案。否则,这个答案就足够了我同意你说的,我指的是你的IF,ELSE评论,它实际上不是IF-ELSE,因为两者都得到了评估
EXECUTE dbo.Proc1 1, 1;
EXECUTE dbo.Proc1 0, 1;
EXECUTE dbo.Proc2 1, 1;
EXECUTE dbo.Proc2 0, 1;
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