楼梯T-SQL:超越基础6级:使用CASE表达式和IIF函数

时间:2023-03-09 07:50:01
楼梯T-SQL:超越基础6级:使用CASE表达式和IIF函数
 从他的楼梯到T-SQL DML,Gregory Larsen涵盖了更多的高级方面的T-SQL语言,如子查询。

有时您需要编写一个可以根据另一个表达式的评估返回不同的TSQL表达式的单个TSQL语句。当您需要这种功能时,您可以使用CASE表达式或IIF函数来满足此要求。在本文中,我将回顾CASE和IIF语法,并向您展示CASE表达式和IIF函数的示例。

了解CASE表达
Transact-SQL CASE表达式允许您在TSQL代码中放置条件逻辑。此条件逻辑为您提供了一种在TSQL语句中放置不同代码块的方法,该语句可以根据条件逻辑的TRUE或FALSE评估来执行。您可以在单个CASE表达式中放置多个条件表达式。当CASE子句中有多个条件表达式时,第一个计算结果为TRUE的表达式将是由TSQL语句评估的代码块。为了更好地了解CASE表达式的工作原理,我将回顾一下CASE表达式的语法,然后通过一些不同的例子。

CASE表达式语法
CASE表达式有两种不同的格式:简单和搜索。每种类型的格式略有不同,如图1所示。

Simple CASE expression:

CASE input_expression 
     WHEN when_expression THEN result_expression [ ...n ] 
     [ ELSE else_result_expression ] 
END

Searched CASE expression:

CASE
     WHEN Boolean_expression THEN result_expression [ ...n ] 
     [ ELSE else_result_expression ] 
END
2017/10/31 14:42:56

图1:CASE表达式语法

通过查看图1中CASE表达式的两种不同格式,您可以看到每种格式如何提供不同的方法来标识确定CASE表达式结果的多个表达式之一。对于两种类型的CASE,对每个WHEN子句执行布尔测试。使用简单CASE表达式,布尔测试的左侧出现在CASE单词之后,称为“input_expression”,右侧的“WHEN”表示右侧,称为“when expression”。使用简单CASE表达式,“input_expression”和“when_expression”之间的运算符始终是相等运算符。而搜索到的CASE表达式,每个WHEN子句将包含一个“Boolean_expression”。这个“Boolean_expression”可以是一个带有单个运算符的简单布尔表达式,也可以是具有许多不同条件的复杂布尔表达式。另外,搜索到的CASE表达式可以使用完整的布尔运算符集。

无论使用哪种CASE格式,每个WHEN子句按其出现顺序进行比较。 CASE表达式的结果将基于评估为TRUE的第一个WHEN子句。如果没有WHEN子句求值为TRUE,则返回ELSE表达式。当ELSE子句被省略且WHEN子句的计算结果为TRUE时,将返回NULL值。

示例数据样本
为了有一个表来演示使用CASE表达式,我将使用清单1中的脚本创建一个名为MyOrder的示例表。如果您想遵循我的示例并在SQL Server实例上运行它们,您可以在选择的数据库中创建此表。

CREATE TABLE MyOrder (
ID int identity, 
OrderDT date, 
OrderAmt decimal(10,2), 
Layaway char(1));
INSERT into MyOrder VALUES 
('12-11-2012', 10.59,NULL), 
('10-11-2012', 200.45,'Y'), 
('02-17-2014', 8.65,NULL), 
('01-01-2014', 75.38,NULL), 
('07-10-2013', 123.54,NULL), 
('08-23-2009', 99.99,NULL), 
('10-08-2013', 350.17,'N'), 
('04-05-2010', 180.76,NULL), 
('03-27-2011', 1.49, NULL);
2017/10/31 14:44:39

清单1:创建示例表MyOrder

使用简单的CASE表达式与WHEN和ELSE表达式
为了演示简单的CASE表达式格式如何工作,让我运行清单2中的代码。

SELECT YEAR(OrderDT) AS OrderYear, 
       CASE YEAR(OrderDT)
  WHEN 2014 THEN 'Year 1'
  WHEN 2013 THEN 'Year 2'
  WHEN 2012 THEN 'Year 3'
  ELSE 'Year 4 and beyond' END AS YearType
FROM MyOrder;

清单2:使用ELSE表达式的简单CASE表达式

让我先谈一谈为什么这是一个简单的CASE表达。如果您查看清单2中的代码,您可以看到紧跟在CASE字之后,我指定了表达式“YEAR(OrderDT)”,然后我按照三个不同的WHEN表达式,每个具有不同的年份指定,从2014开始。因为我指定CASE和第一个WHEN关键字之间的表达式告诉SQL Server这是一个简单的CASE表达式。

当我简单的CASE表达式被评估时,它使用“YEAR(OrderDate)”值和不同的WHEN表达式之间的等号运算符(“=”)。因此,清单1中的代码将为OrderType列显示“Year 1”,其中OrderDT年值为“2014”,否则对于OrderDT年份为“2013”​​的行将显示“Year 2”,或者将为OrderDT年份为“2012”的行显示“Year 3”。如果OrderDT的年份与WHEN表达式不匹配,则ELSE条件将显示“Year 4 and beyond”。

当我运行清单2中的代码时,我得到结果1中显示的输出。

OrderYear   YearType
----------- -----------------
2012        Year 3
2012        Year 3
2014        Year 1
2014        Year 1
2013        Year 2
2009        Year 4 and beyond
2013        Year 2
2010        Year 4 and beyond
2011        Year 4 and beyond
2017/10/31 14:46:16
结果1:运行清单2时的结果

使用没有ELSE表达式的简单CASE表达式
让我运行清单3中的代码,它将显示一个Simple CASE表达式没有ELSE子句时会发生什么。

SELECT YEAR(OrderDT) AS OrderYear, 
       CASE YEAR(OrderDT)
  WHEN 2014 THEN 'Year 1'
  WHEN 2013 THEN 'Year 2'
  WHEN 2012 THEN 'Year 3' END AS YearType
FROM MyOrder;。
2017/10/31 14:48:58

清单3:没有ELSE子句的简单CASE表达式

清单3中的代码就像清单2中的代码,但没有ELSE子句。 当我运行清单3中的代码时,会生成结果2中显示的结果。

OrderYear   YearType
----------- --------
2012        Year 3
2012        Year 3
2014        Year 1
2014        Year 1
2013        Year 2
2009        NULL
2013        Year 2
2010        NULL
2011        NULL
结果2:运行清单3时的结果

通过查看结果2中的输出,您可以看到,当MyOrder表中的OrderDT的年份不符合WHEN子句条件时,SQL Server将为该行的YearType值显示“NULL”。

使用搜索的CASE表达式
在简单的CASE表达式中,WHEN表达式基于等式运算符进行评估。 使用搜索到的CASE表达式,您可以使用其他运算符,CASE表达式语法有所不同。 为了演示这个,我们来看看清单4中的代码。

SELECT YEAR(OrderDT) AS OrderYear, 
       CASE 
  WHEN YEAR(OrderDT) = 2014 THEN 'Year 1'
  WHEN YEAR(OrderDT) = 2013 THEN 'Year 2'
  WHEN YEAR(OrderDT) = 2012 THEN 'Year 3'
  WHEN YEAR(OrderDT) < 2012 THEN 'Year 4 and beyond' 
                       END AS YearType
FROM MyOrder;

清单4:搜索CASE表达式

如果您查看清单4中的代码,您可以看到WHEN子句直接在CASE子句之后,两个子句之间没有文本。这告诉SQL Server这是一个搜索的CASE表达式。还要注意每个WHEN子句后面的布尔表达式。正如你可以看到并不是所有这些布尔表达式都使用等号运算符,最后一个WHEN表达式使用小于(“<”)运算符。清单4中的CASE表达式在逻辑上与清单2中的CASE表达式相同。因此,当我运行清单4中的代码时,会产生与结果1所示相同的结果。

如果多个WHEN表达式求值为TRUE,则返回什么表达式?
在单个CASE表达式中可能会有不同WHEN表达式求值为TRUE的情况。当这种情况发生时,SQL Server将返回与第一个WHEN表达式关联的结果表达式,该WHEN表达式计算结果为true。因此,如果多个WHEN子句评估为TRUE,则WHEN子句的顺序将控制从CASE表达式返回的结果。

为了证明这一点,当OrderAmt在$ 200范围内时,我们使用CASE表达式显示“200美元订单”,当OrderAmt在$ 100范围内时,“100美元订单”,当OrderAmt小于$ 100时,“100美元订单”当OrderAmt不属于这些类别时,将该订单分类为“300美元及以上订单”。我们来看看清单5中的代码,以演示当尝试将订单分类到其中一个OrderAmt_Category值时,当多个WHEN表达式求值为TRUE时会发生什么。

SELECT OrderAmt, 
       CASE 
  WHEN OrderAmt < 300 THEN '200 Dollar Order'
  WHEN OrderAmt < 200 THEN '100 Dollar Order'
  WHEN OrderAmt < 100 THEN '< 100 Dollar Order'
  ELSE  '300 Dollar and above Order' 
      END AS OrderAmt_Category
FROM MyOrder;

清单5:多个WHEN表达式求值为TRUE的示例

当我运行清单5中的代码时,我得到Result 3中的输出。
2017/10/31 14:51:01

OrderAmt                                OrderAmt_Category
--------------------------------------- --------------------------
10.59                                   200 Dollar Order
200.45                                  200 Dollar Order
8.65                                    200 Dollar Order
75.38                                   200 Dollar Order
123.54                                  200 Dollar Order
99.99                                   200 Dollar Order
350.17                                  300 Dollar and above Order
180.76                                  200 Dollar Order
1.49                                    200 Dollar Order

结果3:运行清单5时的结果

通过查看结果3中的结果,您可以看到每个订单都被报告为200或300及以上的订单,我们知道这是不正确的。 这是因为我仅使用少于(“<”)运算符来简单地对在CASE表达式中导致多个WHEN表达式求值为TRUE的Orders进行分类。 WHEN子句的排序不允许返回正确的表达式。

通过重新排序我的WHEN子句,我可以得到我想要的结果。 清单6中的代码与清单5相同,但是我重新命令WHEN子句正确地分类了我的订单。

SELECT OrderAmt, 
       CASE 
  WHEN OrderAmt < 100 THEN '< 100 Dollar Order'
  WHEN OrderAmt < 200 THEN '100 Dollar Order'
  WHEN OrderAmt < 300 THEN '200 Dollar Order'
  ELSE  '300 Dollar and above Order' 
      END AS OrderAmt_Category
FROM MyOrder;

清单6:与清单5类似的代码,但WHEN子句的顺序不同

当我运行清单5中的代码时,我得到结果4中的输出。

OrderAmt                                OrderAmt_Category
--------------------------------------- --------------------------
10.59                                   < 100 Dollar Order
200.45                                  200 Dollar Order
8.65                                    < 100 Dollar Order
75.38                                   < 100 Dollar Order
123.54                                  100 Dollar Order
99.99                                   < 100 Dollar Order
350.17                                  300 Dollar and above Order
180.76                                  100 Dollar Order
1.49                                    < 100 Dollar Order

结果4:运行清单6时的结果

通过查看结果4中的输出,您可以看到,通过更改WHEN表达式的顺序,我得到每个订单的正确结果。

嵌套CASE表达式
有时您可能需要进行其他测试,以使用CASE表达式进一步分类数据。 当这种情况发生时,您可以使用嵌套的CASE表达式。 清单7中的代码显示了嵌套CASE表达式以进一步分类MyOrder表中的订单的示例,以确定订单是否超过$ 200时是否使用Layaway值购买订单。

SELECT OrderAmt, 
       CASE 
  WHEN OrderAmt < 100 THEN '< 100 Dollar Order'
  WHEN OrderAmt < 200 THEN '100 Dollar Order'
  WHEN OrderAmt < 300 THEN 
 CASE 
WHEN Layaway = 'N' 
    THEN '200 Dollar Order without Layaway'
    ELSE '200 Dollar Order with Layaway' END
  ELSE  
 CASE 
WHEN Layaway = 'N' 
    THEN '300 Dollar Order without Layaway'
    ELSE '300 Dollar Order with Layaway' END 
      END AS OrderAmt_Category
FROM MyOrder;

清单7:嵌套CASE语句

清单7中的代码类似于清单6中的代码。唯一的区别是我添加了一个额外的CASE表达式,以查看MyOrder表中的订单是否使用Layaway选项购买,只能在超过$ 200的购买上购买。 嵌套CASE表达式时请牢记SQL Server只允许最多10个嵌套级别。

其他可以使用CASE表达式的地方
到目前为止,我的所有示例都使用CASE表达式通过将CASE表达式放在TSQL SELECT语句的选择列表中来创建结果字符串。 您还可以在UPDATE,DELETE和SET语句中使用CASE表达式。 另外,CASE表达式可以与IN,WHERE,ORDER BY和HAVING子句一起使用。 在清单8中,我使用了表示WHERE子句的CASE。

SELECT *
FROM MyOrder
WHERE CASE YEAR(OrderDT)
WHEN 2014 THEN 'Year 1'
WHEN 2013 THEN 'Year 2'
WHEN 2012 THEN 'Year 3'
ELSE 'Year 4 and beyond' END = 'Year 1';

清单8:在WHERE子句中使用CASE表达式

在清单8中,我只想从MyOrder表中的“Year 1”行返回一个订单。为了实现这一点,我将在WHERE子句中放置与清单2中所使用的相同的CASE表达式。我使用CASE表达式作为WHERE条件的左侧部分,因此它将根据OrderDT列生成不同的“Year ...”字符串。然后我测试了从CASE表达式生成的字符串,以查看它是否等于值“Year 1”,当它是从MyOrder表返回的行。请记住,当有其他更好的方法,如使用YEAR功能选择给定年份的行时,不建议使用CASE表达式从日期列中选择日期。我只在这里说明如何在WHERE子句中使用CASE语句。

使用IIF功能快速切换CASE表达式
随着SQL Server 2012的推出,微软增加了IIF功能。 IIF函数可以被认为是CASE语句的快捷方式。在图2中,您可以找到IIF函数的语法。

IIF ( boolean_expression, true_value, false_value )

图2:IIF功能的语法

“Boolean_expression”是一个有效的布尔表达式,相当于TRUE或FALSE。 当布尔表达式等于TRUE值时,执行“true_value”表达式。 如果布尔表达式等于FALSE,则执行“false_value”。 就像CASE表达式一样,IIF函数可以嵌套多达10个级别。

使用IIF的例子
为了演示如何使用IIF函数来替换CASE表达式,我们来看看使用清单9中搜索到的CASE表达式的代码。

SELECT OrderAmt,
       CASE 
  WHEN OrderAmt > 200 THEN 'High $ Order'
  ELSE 'Low $ Order' END AS OrderType
FROM MyOrder;

清单9:简单的CASE表达式示例

清单9中的代码只有一个WHEN表达式,用于确定OrderAmt是高或低美元订单。 如果WHEN表达式“OrderAMT> 200”计算结果为TRUE,则OrderType值设置为“High $ Order”。 如果WHEN表达式计算为FALSE,则为OrderType值设置“Low $ Order”。

使用IIF函数而不是CASE表达式的重写代码可以在清单10中找到。

SELECT OrderAmt,  
  IIF(OrderAmt > 200,
 'High $ Order',
 'Low $ Order') AS OrderType
FROM MyOrder;
2017/10/31 14:55:12

清单10:使用IIF函数的示例

通过查看清单10,您可以看到为什么IIF函数被认为是CASE表达式的简写版本。 CASE替换为“IIF(”字符串,“THEN”子句用逗号替换,“ELSE”子句用逗号替换,“END”替换为“)”。 当布尔表达式“OrderAmt> 200”为TRUE时,显示值“High $ Order”。 当布尔表达式“OrderAmt> 200”被评估为FALSE时,显示“低$订单”。 如果运行清单9和10中的代码,您将看到它们都产生完全相同的输出。

嵌套IIF功能的示例
就像CASE表达式一样,SQL Server允许您嵌套IIF函数。 清单11是嵌套IIF函数的示例。

SELECT OrderAmt, 
       IIF (OrderAmt < 100, 
        '< 100 Dollar Order',
        (IIF (OrderAmt < 200, 
         '100 Dollar Order',
              (IIF (OrderAmt < 300,
                     (IIF (Layaway = 'N', 
            '200 Dollar Order without Layaway',
            '200 Dollar Order with Layaway'
            )
       ),
       (IIF (Layaway = 'N', 
             '300 Dollar Order without Layaway',
             '300 Dollar Order with Layaway'
            )
                 )
      )
 )
          )
)
) AS OrderAmt_Category
FROM MyOrder;

清单11:IIF函数的嵌套示例

在这个例子中,您可以看到我已经使用了IIF多次功能。每个额外的一个用于IIF功能的“真实值”或“假值”。清单11中的代码相当于使用清单7中的嵌套CASE表达式的代码。

限制
与大多数TSQL功能一样,存在限制。以下是有关CASE和IIF结构的一些限制。

CASE表达限制:

•CASE表达式中最多只能有10个嵌套级别。
•CASE表达式不能用于控制TSQL语句的执行流程。
IIF功能限制:

•您只能拥有多达10级的嵌套IIF子句。
概要
CASE表达式和IIF函数允许您将表达式逻辑放在TSQL代码中,这将基于表达式的计算结果来更改代码的结果。通过使用IIF函数和CASE表达式支持的比较表达式,可以根据比较表达式的计算结果为TRUE还是FALSE,执行不同的代码块。 CASE表达式和IIF函数为您提供编程控制,以满足您可能没有的业务需求。

问题和答案
在本节中,您可以回答以下问题,了解如何使用CASE和IIF构造。

问题1:
CASE表达式有两种不同的语法变体:Simple和Searched。下面哪两个语句最好地描述了简单和搜索的CASE表达式(Pick 2)之间的区别。

a。简单CASE语法仅支持等式运算符,而Searched CASE语法支持多个运算符
b。简单CASE语法支持多个运算符,而Searched CASE语法仅支持等式运算符
c。简单CASE语法在WHEN子句之后指定了布尔表达式,而Searched CASE语法在CASE语句之后具有布尔表达式的左侧,WHEN子句后面的布尔表达式的右侧。
d。简单CASE语法在CASE语句之后具有布尔表达式的左侧,WHEN子句后面的布尔表达式的右侧,而Searched CASE表达式在WHEN子句之后具有其布尔表达式

问题2:
如果CASE表达式有多个WHEN子句评估为TRUE,执行THEN / ELSE子句?

执行评估为TRUE的最后一个WHEN子句的THEN表达式。
b。执行计算为TRUE的第一个WHEN子句的THEN表达式。
c。执行评估为TRUE的WHEN子句的所有THEN表达式。
执行d.THE ELSE表达式
问题3:
CASE表达式或IIF函数有多少嵌套级别?

A.8
B.10
C.16
草32
回答:
问题1:
答案是a和d。简单的CASE语句只能使用相等运算符,而Searched CASE表达式可以处理多个运算符以及复杂的布尔表达式。另外,简单CASE语法具有紧靠单词CASE之后的等式运算符的左手部分,并且等于WHEN之后的等式运算符的右手部分。搜索的CASE表达式必须在WHEN子句之后完成布尔运算(左手部分,运算符,右手部分)

问题2:
正确的答案是b。如果多个WHEN子句求值为TRUE,则SQL Server仅执行第一个WHEN子句的THEN部分,该WHEN子句的计算结果为TRUE。被评估为TRUE的任何其他WHEN子句的所有其他THEN子句将被跳过。
2017/10/31 14:57:31
我的小秘 2017/10/31 14:57:31

问题3:
正确的答案是b。 CASE表达式和IIF功能仅支持最多10个嵌套级别