0

在我的 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 吗?那么如果没有匹配,所有的名字都会被返回?

4

5 回答 5

2

也许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)) 
于 2013-09-05T18:52:58.330 回答
1

也许是这样的?

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

@Name_这将仅在提供 null 或空白参数时使用模式 '%' (它将匹配所有内容) ,否则它将使用@Name_.

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

AND
Name IN (Select Names FROM Person Where Names LIKE 
         ISNULL( NULLIF( @Name_, '' ), '%' ))
AND 
于 2013-09-05T18:52:09.183 回答
1

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

AND (   Name IN (Select Names FROM Person Where Names like @Name_)
    OR
        @Name_ IS NULL 
    )
AND
于 2013-09-05T18:52:50.063 回答
1

这有效

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 )
于 2013-09-05T18:55:36.637 回答
1

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

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

注意我已经改变了 like to equals 因为LIKE 没有通配符它与 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-09-06T10:25:41.203 回答