【问题标题】:Using a CASE with the IN clause in T-SQL在 T-SQL 中使用带有 IN 子句的 CASE
【发布时间】:2023-03-19 00:16:01
【问题描述】:

在我的 WHERE 子句中,我使用了一个 CASE,如果参数为空或 null,它将返回所有行。这适用于单个值。但是,在使用 IN 子句时不太好。例如:

这很好用,如果不匹配则返回所有记录!

AND 
Name = CASE WHEN @Name_ != '' THEN @Name_ ELSE Name END
AND

这也有效,但没有办法使用 CASE 表达式,所以如果我不提供一些值,我将看不到任何记录:

AND
Name IN (Select Names FROM Person Where Names like @Name_)
AND 

我可以在第二个示例中使用 CASE 吗?那么如果不匹配,所有的 Names 都会被返回?

【问题讨论】:

    标签: asp.net sql tsql case where


    【解决方案1】:

    也许coalesce 会解决你的问题

    AND
    Name IN (Select Names FROM Person Where Names like coalesce(@Name,Name))
    AND 
    

    正如Mattfew Lake所说和使用的,你也可以使用isnull函数

    Name IN (Select Names FROM Person Where Names like isnull(@Name,Name)) 
    

    【讨论】:

    • 这是个好建议,我不知道为什么会有人反对
    • @RedSoxFred 我也不知道,也许我有= 而不是like,但我改变了它。谢谢!
    • @RedSoxFred 你也很有礼貌。帕拉多这给了我很好的结果。我也可以在哪里学习这样的 T-SQL 知识?然后是你。
    • 再次感谢@Parado。非常有用的教程,我一定会完整阅读!
    • ****我必须为其他人更新这个,我最终使用了 isnull 因为 colesce 的性质在第一个 null 表达式处停止。这只是给了我部分结果****
    【解决方案2】:

    不需要 CASE 语句,只需使用嵌套的 OR 条件即可。

    AND (   Name IN (Select Names FROM Person Where Names like @Name_)
        OR
            @Name_ IS NULL 
        )
    AND
    

    【讨论】:

      【解决方案3】:

      也许是这样的?

      AND
      Name IN (Select Names FROM Person Where Names LIKE 
               CASE WHEN @Name_ = '' OR @Name_ IS NULL THEN '%' ELSE @Name_ END)
      AND 
      

      仅当提供空或空白@Name_ 参数时,这将使用模式'%'(将匹配所有内容),否则它将使用@Name_ 指定的模式。

      或者,这样的事情应该可以工作:

      AND
      Name IN (Select Names FROM Person Where Names LIKE 
               ISNULL( NULLIF( @Name_, '' ), '%' ))
      AND 
      

      【讨论】:

        【解决方案4】:

        这行得通

        DECLARE @Name NVARCHAR(100)
        
        SET @Name = ''
        
        DECLARE @Person TABLE ( NAME NVARCHAR(100) )
        
        INSERT  INTO @Person VALUES  ( 'fred' )
        INSERT  INTO @Person VALUES  ( 'jo' )
        
        DECLARE @Temp TABLE
            (
              id INT ,
              NAME NVARCHAR(100)
            )
        
        INSERT  INTO @Temp ( id, NAME ) VALUES  ( 1, N'' )
        INSERT  INTO @Temp ( id, NAME ) VALUES  ( 5, N'jo' )
        INSERT  INTO @Temp ( id, NAME ) VALUES  ( 2, N'fred' )
        INSERT  INTO @Temp ( id, NAME ) VALUES  ( 3, N'bob' )
        INSERT  INTO @Temp ( id, NAME ) VALUES  ( 4, N'' )
        
        SELECT  * FROM    @Temp
        WHERE   name IN ( SELECT    name
                          FROM      @Person
                          WHERE     name = CASE WHEN @name != '' THEN @Name
                                                ELSE name
                                           END )
        

        【讨论】:

        • 虽然我和下一个人一样感谢投反对票,但我特别感谢无缘无故投反对票,它的信息量更大,也更重要。
        【解决方案5】:

        您几乎绝对应该使用带有两个选择的 IF 语句。例如

        IF @Name IS NULL
            BEGIN
                SELECT  *
                FROM    Person
            END
        ELSE
            BEGIN
                SELECT  *
                FROM    Person
                --WHERE Name LIKE '%' + @Name + '%'
                WHERE   Name = @Name
            END
        

        注意自从LIKE without wildcards it is no different to equals 以来,我已经改变了like to equals, ,它不应该在性能方面产生任何影响,但它可以避免下一个将阅读您的查询的人产生歧义。如果你确实想要不准确 匹配然后使用注释掉的WHERE 并根据需要删除通配符。

        IF 的原因是这两个查询可能有非常不同的执行计划,但是通过将它们组合到一个查询中,您会迫使优化器选择一个或另一个计划。想象一下这个架构:

        CREATE TABLE Person
        (       PersonID        INT IDENTITY(1, 1) NOT NULL,
                Name            VARCHAR(255) NOT NULL,
                DateOfBirth     DATE NULL
            CONSTRAINT PK_Person_PersonID PRIMARY KEY (PersonID)
        );
        GO
        CREATE NONCLUSTERED INDEX IX_Person_Name ON Person (Name) INCLUDE (DateOfBirth);
        GO
        INSERT Person (Name)
        SELECT  DISTINCT LEFT(Name, 50)
        FROM    sys.all_objects;
        GO
        
        CREATE PROCEDURE GetPeopleByName1 @Name VARCHAR(50)
        AS
            SELECT  PersonID, Name, DateOfBirth
            FROM    Person
            WHERE   Name IN (SELECT Name FROM Person WHERE Name LIKE ISNULL(@Name, Name));
        GO
        
        CREATE PROCEDURE GetPeopleByName2 @Name VARCHAR(50)
        AS
            IF @Name IS NULL
                SELECT  PersonID, Name, DateOfBirth
                FROM    Person
            ELSE
                SELECT  PersonID, Name, DateOfBirth
                FROM    Person
                WHERE   Name = @Name;
        GO
        

        现在,如果我运行这两个过程都带有值和不带有值:

        EXECUTE GetPeopleByName1 'asymmetric_keys';
        EXECUTE GetPeopleByName1 NULL;
        
        EXECUTE GetPeopleByName2 'asymmetric_keys';
        EXECUTE GetPeopleByName2 NULL;
        

        两个程序的结果是相同的,但是,我每次第一个程序都得到相同的计划,但第二个程序有两个不同的计划,这两个程序都比第一个更有效率。

        如果您不能使用 IF(例如,如果您使用的是内联表值函数),那么您可以使用 UNION ALL 获得类似的结果:

        SELECT  PersonID, Name, DateOfBirth
        FROM    Person
        WHERE   @Name IS NULL
        UNION ALL
        SELECT  PersonID, Name, DateOfBirth
        FROM    Person
        WHERE   Name = @Name;
        

        这不如使用 IF 有效,但仍比您的第一个查询更有效。最重要的是,少并不总是多,是的,使用IF 更冗长,可能看起来它做了更多的工作,但实际上它做的工作少了很多,而且效率更高。

        【讨论】:

          猜你喜欢
          • 2013-10-03
          • 1970-01-01
          • 1970-01-01
          • 2013-10-16
          • 1970-01-01
          • 1970-01-01
          • 2014-12-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多