Sql 使用CASE-in-WHERE子句计算空参数

Sql 使用CASE-in-WHERE子句计算空参数,sql,sql-server,tsql,case,sql-like,Sql,Sql Server,Tsql,Case,Sql Like,是否有更好的方法获得以下信息 DECLARE @Desc VARCHAR(200) = '' SELECT [id], [Desc], [Col1], [Col2] FROM [dbo].[tbl] WHERE [Desc] LIKE CASE WHEN @Desc LIKE '' THEN [Desc] ELSE '%'+ @Desc

是否有更好的方法获得以下信息

DECLARE @Desc VARCHAR(200) = ''

SELECT [id],
       [Desc],
       [Col1],
       [Col2]
FROM [dbo].[tbl]
WHERE [Desc] LIKE CASE
                WHEN @Desc LIKE ''
                     THEN [Desc]
                     ELSE '%'+ @Desc +'%'
                END

如果参数未定义@Desc=或返回值的子集@Desc='test',则允许返回所有值。

使用or运算符而不是大小写

DECLARE @Desc VARCHAR(200) = ''

SELECT [id],
       [Desc],
       [Col1],
       [Col2]
FROM [dbo].[tbl]
WHERE 
    (
        ISNULL(@Desc,'')=''
    )
    OR
    (
        ISNULL(@Desc,'')<>''
        AND
        [Desc] LIKE '%'+ @Desc +'%'
    )
使用两种逻辑的执行计划差异

用例

使用或


使用OR运算符代替Case

DECLARE @Desc VARCHAR(200) = ''

SELECT [id],
       [Desc],
       [Col1],
       [Col2]
FROM [dbo].[tbl]
WHERE 
    (
        ISNULL(@Desc,'')=''
    )
    OR
    (
        ISNULL(@Desc,'')<>''
        AND
        [Desc] LIKE '%'+ @Desc +'%'
    )
使用两种逻辑的执行计划差异

用例

使用或


执行引擎最好在查询之前进行尽可能多的参数处理

DECLARE @Desc VARCHAR(200) = '';
DECLARE @SelectAll bit;

SET @SelectAll = CASE WHEN @Desc = '' THEN 1 ELSE 0 END;
SET @Desc = CASE WHEN @Desc = '' THEN @Desc ELSE ('%' + @Desc + '%') END;


SELECT [id],
       [Desc],
       [Col1],
       [Col2]
FROM [dbo].[tbl]
WHERE 
    (@SelectAll = 1)
        OR
    (@SelectAll = 0 AND [Desc] LIKE @Desc);

如果您不介意代码重复,您可以更进一步,用If/ELSE分割两个单独的查询。

执行引擎最好在查询之前进行同样多的参数处理

DECLARE @Desc VARCHAR(200) = '';
DECLARE @SelectAll bit;

SET @SelectAll = CASE WHEN @Desc = '' THEN 1 ELSE 0 END;
SET @Desc = CASE WHEN @Desc = '' THEN @Desc ELSE ('%' + @Desc + '%') END;


SELECT [id],
       [Desc],
       [Col1],
       [Col2]
FROM [dbo].[tbl]
WHERE 
    (@SelectAll = 1)
        OR
    (@SelectAll = 0 AND [Desc] LIKE @Desc);

如果您不介意代码重复,您可以更进一步,使用If/ELSE进行两个单独的查询。

如果使用null,则可以保存一些步骤

declare @userId  int = null; 

SELECT TOP 1000 [AuctionId]
      ,[UserId]
      ,[BiddingPrice]
      ,[DateTime]
  FROM [Test].[dbo].[Bid] 
  WHERE isnull(@userId, [UserId]) = [UserId];

如果使用null,则保存一些步骤

declare @userId  int = null; 

SELECT TOP 1000 [AuctionId]
      ,[UserId]
      ,[BiddingPrice]
      ,[DateTime]
  FROM [Test].[dbo].[Bid] 
  WHERE isnull(@userId, [UserId]) = [UserId];

正如Aaron Bertrand所评论的,您当前的查询可以这样简单地编写:

DECLARE @Desc VARCHAR(200) = ''

SELECT [id],
       [Desc],
       [Col1],
       [Col2]
FROM [dbo].[tbl]
WHERE [Desc] LIKE '%'+ @Desc +'%' 
因为如果@Desc包含一个空字符串,它的结果将是类似“%”的[Desc]——因此所有[Desc]不为null的记录都将返回

如果@Desc可以作为null传递,请使用Coalesce将null转换为空字符串:

...WHERE [Desc] LIKE '%'+ COALESCE(@Desc, '') +'%' 
请注意,在这两个问题中,Desc列包含null的记录将不会被返回。如果这是一个可为null的列,并且您还希望返回该列为null且@Desc参数也为null或空的记录,则应使用或:


另外,请注意,这只是因为您使用了LIKE——如果您尝试使用其他运算符(如=,等)来计算条件,您应该在其他答案中使用OR语法LIKE。

正如Aaron Bertrand所评论的,您当前的查询可以简单地这样编写:

DECLARE @Desc VARCHAR(200) = ''

SELECT [id],
       [Desc],
       [Col1],
       [Col2]
FROM [dbo].[tbl]
WHERE [Desc] LIKE '%'+ @Desc +'%' 
因为如果@Desc包含一个空字符串,它的结果将是类似“%”的[Desc]——因此所有[Desc]不为null的记录都将返回

如果@Desc可以作为null传递,请使用Coalesce将null转换为空字符串:

...WHERE [Desc] LIKE '%'+ COALESCE(@Desc, '') +'%' 
请注意,在这两个问题中,Desc列包含null的记录将不会被返回。如果这是一个可为null的列,并且您还希望返回该列为null且@Desc参数也为null或空的记录,则应使用或:


另外,请注意,这只是因为您使用了LIKE—如果您尝试使用其他运算符(如=,等)来计算条件,则应使用其他答案中的OR语法LIKE。

如果您只传递空字符串或非空字符串且不为NULL,那么这不会做同样的事情:WHERE[Desc]像“%”++@Desc++“%”;?即使传递NULL,其中[Desc]与“%”类似COALESCE@Desc, + '%';可能是相关的。如果这是一个存储过程,并且更好意味着性能更高,那么最好使用动态SQL或ORM,它可以自定义SQL并完全删除可选谓词,而不是对分支运行不同的查询。原因查询计划。旁白:在where子句中添加通配符%会阻止使用@Desc搜索以模式开头或结尾的字符串,例如“Mac%”。它还禁止使用索引查找,尽管仍然可以进行索引扫描。@哈博一般来说,字符串末尾的通配符仍然允许使用索引“Mac%”将工作,但“%Mac”将不工作。此外,您可以使用反向值构建索引,以允许您查询“%Mac”。请参阅以获得一点讨论。如果只传递空字符串或非空字符串且不为NULL,那么这不是做了同样的事情吗:其中[Desc]像“%”++@Desc++“%”;?即使传递NULL,其中[Desc]与“%”类似COALESCE@Desc, + '%';可能是相关的。如果这是一个存储过程,并且更好意味着性能更高,那么最好使用动态SQL或ORM,它可以自定义SQL并完全删除可选谓词,而不是对分支运行不同的查询。原因查询计划。旁白:在where子句中添加通配符%会阻止使用@Desc搜索以模式开头或结尾的字符串,例如“Mac%”。它还禁止使用索引查找,尽管仍然可以进行索引扫描。@哈博一般来说,字符串末尾的通配符仍然允许使用索引“Mac%”将工作,但“%Mac”将不工作。此外,您可以使用反向值构建索引,以允许您查询“%Mac”。请参阅以了解一些讨论。您能否澄清这是一种更好的方法,还是一种替代方法?这是一种更好的方法,因为在Where子句中使用Case语句不是一种好的编程策略。为什么使用Case表达式是一种坏的编程策略?为什么使用非参数谓词更好?@RToyo不,没有新引入的非参数谓词。在函数中包装变量不是问题。@SeanLange我已经添加了dif
在执行计划中引用答案你能澄清这是一种更好的方式,还是仅仅是一种替代方式吗?这是一种更好的方式,因为在Where子句中使用Case语句不是一种好的编程策略为什么使用Case表达式是一种坏的编程策略?为什么使用非参数谓词更好?@RToyo不,没有新引入的非参数谓词。在函数中包装变量不是问题。@SeanLange我已将执行计划中的差异添加到OP使用的like和通配符的应答中。类似这样的内容可能更适合以下问题:像“%”这样的[UserId]在哪里isnull@userId,+“%”OP将like与通配符一起使用。类似这样的内容可能更适合以下问题:像“%”这样的[UserId]在哪里isnull@userId, + '%'