SQL:WHERE子句中的IF子句


203

是否可以在MS SQL 的WHERE子句中使用IF子句?

例:

WHERE
    IF IsNumeric(@OrderNumber) = 1
        OrderNumber = @OrderNumber
    ELSE
        OrderNumber LIKE '%' + @OrderNumber + '%'

Answers:


212

使用CASE语句
UPDATE:先前的语法(如少数人指出的那样)不起作用。您可以按以下方式使用CASE:

WHERE OrderNumber LIKE
  CASE WHEN IsNumeric(@OrderNumber) = 1 THEN 
    @OrderNumber 
  ELSE
    '%' + @OrderNumber
  END

或者您可以使用@ NJ Reed指出的IF语句。


[作者更新后的注释]:应该可以,但是您应该在TRIM()的两面都确保找到匹配项。我有一种直觉,认为仍然有一些罕见的案例无法匹配。
Euro Micelli

1
CASE在大多数情况下,使用是合适的解决方案。就我而言,我想更改比较运算符,因此我使用了下一种方法。
Birla 2014年

142

您应该能够在没有任何IF或CASE的情况下执行此操作

 WHERE 
   (IsNumeric(@OrderNumber) AND
      (CAST OrderNumber AS VARCHAR) = (CAST @OrderNumber AS VARCHAR)
 OR
   (NOT IsNumeric(@OrderNumber) AND
       OrderNumber LIKE ('%' + @OrderNumber))

根据SQL的风格,您可能需要根据是否支持隐式强制转换将订单号的强制转换调整为INT或VARCHAR。

这是WHERE子句中非常常见的技术。如果要在WHERE子句中应用某些“ IF”逻辑,您需要做的就是将带有布尔AND的额外条件添加到需要应用它的部分。


2
我想您会在CASE解决方案上遇到一些性能下降的问题,但是,由于对所有这些条件都进行了评估,不是吗?
凯文·费尔柴尔德

我总是忘记在SQL中可以用这样的布尔逻辑替换条件语句。感谢您的提醒,这是一种非常有用的技术!
CodexArcanum 2010年

1
由于SQL Server如何处理布尔逻辑,因此该解决方案实际上是最佳解决方案。where子句中的CASE语句比布尔情况下的效率低,因为如果第一次检查失败,SQL将停止处理该行并继续。这样可以节省您的处理时间。另外,请始终在布尔支票的另一侧放置更昂贵的语句。
史蒂夫(Steve)2010年

感谢您提供非常优雅的解决方案。找到了有关您所使用的方法的指南,该指南可能会对人们有所帮助。 weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
丰富的

1
@Kash您提供的链接是可供阅读的寄存器,是否有公开的文档描述您在说什么?
史蒂夫(Steve)

29

您根本不需要IF语句。

WHERE
    (IsNumeric(@OrderNumber) = 1 AND OrderNumber = @OrderNumber)
OR (IsNumeric(@OrderNumber) = 0 AND OrderNumber LIKE '%' + @OrderNumber + '%')

2
我真的很喜欢这种方法。Alternativ使用:仅在AdmUseId具有值的情况where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId) 下进行过滤:或者仅在IncludeDeleted = 0时进行过滤: where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)
Kasper Halvas Jensen

在WHERE子句中使用IN过滤器时,此方法效果很好。使用CASE这样做很麻烦,因为您必须使用COALESCE,并且很难阅读,而这是易于理解的逻辑。WHERE子句中的NOT IN或IN过滤器中的TSQL CASE语句
pholcroft

14

在SQL中没有一个很好的方法来执行此操作。我见过一些方法:

1)结合使用CASE和布尔运算符:

WHERE
    OrderNumber = CASE 
        WHEN (IsNumeric(@OrderNumber) = 1)
        THEN CONVERT(INT, @OrderNumber)
        ELSE -9999 -- Some numeric value that just cannot exist in the column
    END
    OR 
    FirstName LIKE CASE
        WHEN (IsNumeric(@OrderNumber) = 0)
        THEN '%' + @OrderNumber
        ELSE ''
    END

2)在SELECT之外使用IF

IF (IsNumeric(@OrderNumber)) = 1
BEGIN
    SELECT * FROM Table
    WHERE @OrderNumber = OrderNumber
END ELSE BEGIN
    SELECT * FROM Table
    WHERE OrderNumber LIKE '%' + @OrderNumber
END

3)使用长字符串,有条件地编写SQL语句,然后使用EXEC

第三种方法令人毛骨悚然,但是如果您有许多类似的可变条件,它几乎是唯一可行的方法。


第四种方法是将所有IF...ELSE...条件转换为boolean ANDOR,就像上面的@ njr101答案中一样。不利的一面IF是,如果您有很多嵌套,或者嵌套的嵌套很多,则很难做到这一点
Don Cheadle 2015年


4

您需要CASE语句

WHERE OrderNumber LIKE
CASE WHEN IsNumeric(@OrderNumber)=1 THEN @OrderNumber ELSE '%' + @OrderNumber END

3

我认为在...喜欢/ = ...情况下...那么...可以使用布尔值。我正在使用T-SQL。

场景:假设如果bool为假,则要获得Person-30的爱好,如果bool为真,则要获得Person-42的爱好。(根据某些情况,爱好查找构成了业务计算周期的90%以上,因此请密切注意。)

CREATE PROCEDURE sp_Case
@bool   bit
AS
SELECT Person.Hobbies
FROM Person
WHERE Person.ID = 
    case @bool 
        when 0 
            then 30
        when 1
            then 42
    end;

2
在哪里(IsNumeric(@OrderNumber)<> 1 OR OrderNumber = @OrderNumber) 
             AND(IsNumber(@OrderNumber)= 1 OR OrderNumber像'%' 
                                              + @OrderNumber +'%')

IF P THEN Q ELSE R <=> ( ( NOT P ) OR Q ) AND ( P OR R )
合并


1
    WHERE OrderNumber LIKE CASE WHEN IsNumeric(@OrderNumber) = 1 THEN @OrderNumber ELSE  '%' + @OrderNumber END

在情况下,条件将正常工作。


0

下面的示例将查询作为布尔表达式的一部分执行,然后根据布尔表达式的结果执行稍有不同的语句块。每个语句块均以BEGIN开头,以END结束。

USE AdventureWorks2012;
GO
DECLARE @AvgWeight decimal(8,2), @BikeCount int
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
BEGIN
   SET @BikeCount = 
        (SELECT COUNT(*) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   SET @AvgWeight = 
        (SELECT AVG(Weight) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   PRINT 'There are ' + CAST(@BikeCount AS varchar(3)) + ' Touring-3000 bikes.'
   PRINT 'The average weight of the top 5 Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.';
END
ELSE 
BEGIN
SET @AvgWeight = 
        (SELECT AVG(Weight)
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%' );
   PRINT 'Average weight of the Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.' ;
END ;
GO

使用嵌套的IF ... ELSE语句以下示例说明如何将IF…ELSE语句嵌套在另一个语句中。将@Number变量设置为5、50和500以测试每个语句。

DECLARE @Number int
SET @Number = 50
IF @Number > 100
   PRINT 'The number is large.'
ELSE 
   BEGIN
      IF @Number < 10
      PRINT 'The number is small'
   ELSE
      PRINT 'The number is medium'
   END ;
GO

2
这似乎无关紧要。它不在WHERE子句中使用IF(或任何条件代码)。
文斯·鲍德伦

0

在sql server中,我有一个同样的问题,我只想在参数为false时使用and语句,并且在true时必须同时显示true和false值,因此我以这种方式使用它

(T.IsPublic = @ShowPublic or  @ShowPublic = 1)

-1
If @LstTransDt is Null
                begin
                    Set @OpenQty=0
                end
            else
                begin
                   Select   @OpenQty=IsNull(Sum(ClosingQty),0)  
                   From  ProductAndDepotWiseMonitoring  
                   Where   Pcd=@PCd And PtpCd=@PTpCd And TransDt=@LstTransDt      
                end 

看看是否有帮助。


-6
USE AdventureWorks2012;
GO
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
PRINT 'There are more than 5 Touring-3000 bicycles.'
ELSE PRINT 'There are 5 or less Touring-3000 bicycles.' ;
GO

这似乎无关紧要。它不在WHERE子句中使用IF(或任何条件代码)。
文斯·鲍德伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.