四巨头第八周作业翻译
系列
这篇文章是阶梯系列的一部分:T-SQL的阶梯:超越基础
从他的阶梯到T-SQL DML,格雷戈里·拉森涵盖了T-SQL语言的更高级的方面,比如子查询。
有时需要编写一个TSQL语句,该语句可以根据另一个表达式的值返回不同的TSQL表达式。当你需要这种功能时,你可以使用CASE表达式或IIF函数来满足这一需求。在本文中,我将要回顾这个案例和IIF语法,并向你展示CASE表达式和IIF函数的示例。
理解案例的表达
Transact-SQL CASE表达式允许在TSQL代码中放置条件逻辑。这个条件逻辑为你提供了一种方法,可以将不同的代码块放置在你的TSQL语句中,这些代码块可以根据条件逻辑的真实或错误的评估来执行。你可以将多个条件表达式放在一个单独的CASE表达式中。当你的CASE子句中有多个条件表达式时,计算为TRUE的第一个表达式将是由TSQL语句计算的代码块。为了更好地理解CASE表达式的工作方式,我将要回顾这个CASE表达式的语法,然后浏览一些不同的例子。
案例表达式语法
CASE表达式有两种不同的格式:Simple和search。每种类型的格式都略有不同,如图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
图1:案例表达式语法
通过查看图1中CASE表达式的两种不同格式,你可以看到每种格式提供了一种不同的方式来确定多个表达式中的一个,这些表达式决定了CASE表达式的结果。对于这两种类型的情况,每个WHEN子句都执行一个布尔测试。在简单的CASE表达式中,布尔测试的左手边出现在CASE单词后面,被称为“input_expression”,而布尔测试的右手边则是“WHEN”,被称为“WHEN expression”。使用简单的CASE表达式,在“input_expression”和“when_expression”之间的操作符始终是相等的运算符。而在搜索的CASE表达式中,每个WHEN子句将包含一个“Boolean_expression”。这个“Boolean_expression”可以是一个简单的布尔表达式,一个操作符,或者一个复杂的布尔表达式,有许多不同的条件。此外,搜索的CASE表达式可以使用完整的布尔运算符集。
不管使用哪种情况的格式,每个WHEN子句都按照它出现的顺序进行比较。这个CASE表达式的结果将基于对TRUE进行计算的第一个WHEN子句。如果没有WHEN子句计算为TRUE,则返回ELSE表达式。当ELSE子句被省略,而子句计算为TRUE时,则返回空值。
样本数据的例子
为了有一个表来演示使用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);
清单1:创建示例表MyOrder
使用一个简单的CASE表达式和其他表达式
为了演示简单的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表达式
让我先谈谈为什么这是一个简单的案例表达。如果你回顾一下清单2中的代码,你可以看到,在单词CASE之后,我指定了表达式“YEAR(OrderDT)”,然后我遵循了3个不同的表达式,每个表达式都指定了不同的年份,从2014开始。因为我在CASE和第一个关键字之间指定了这个表达式,这告诉SQL Server这是一个简单的CASE表达式。
当我的简单的CASE表达式被求值时,它使用“YEAR(OrderDate)”值和不同的表达式之间的相等运算符(“=”)。因此,清单1中的代码将显示为YearType列的“1年”行OrderDT年值“2014”,或者将要显示“2年”行OrderDT一年的将显示“2013”或者“三年级”行OrderDT年的“2012”。如果OrderDT的年份不匹配任何表达式,那么ELSE条件将显示“year 4和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
结果1:运行清单2时的结果
使用一个无其他表达式的简单CASE语句
让我运行清单3中的代码,它将显示一个简单的没有ELSE子句的CASE表达式。
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;
清单3:没有ELSE子句的简单CASE表达式
清单3中的代码类似于清单2中的代码,但没有其他子句。当我运行清单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表达式语法也略有不同。为了展现这一点,我们来看看清单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中的代码,可以发现在CASE子句之后,在两个子句之间没有文本的情况下,WHEN子句直接跟随。这告诉SQL Server这个CASE表达式可以搜索。还要注意每个WHEN子句后面的布尔表达式。正如我们所看到的,并不是所有的布尔表达式都使用相等运算符,最后一个表达式使用小于(“<”)运算符。清单4中的CASE表达式在逻辑上与清单2中的CASE表达式相同。因此,当我运行清单4中的代码时,它产生的结果与结果1中的结果相同。
当表达式值为TRUE时,返回的表达式是多少?
当表达式在单个表达式中值为TRUE时,可能会出现不同的情况。当这种情况发生时,SQL Server将返回与第一个计算值为true的表达式相关联的结果表达式。因此,当子句中的多个子句的值为TRUE时,子句的顺序将会控制您从CASE表达式中返回的结果。
我们用来显示“200美元的秩序”OrderAmt 200美元的范围内时,“100美元的秩序”OrderAmt时100美元的范围内和“< 100美元订单“当OrderAmt小于100美元当一个OrderAmt不属于任何这些类别的分类顺序为“300美元以上的秩序”。让我们回顾一下清单5中的代码,来看看当在尝试将订单分类为这些OrderAmt_Category值之一时,多个表达式计算为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;
清单6:与清单5类似的代码,但子句顺序不同
当我运行清单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中的输出,我们可以看到,通过改变表达式的顺序,能得到每个订单的正确结果。
嵌套情况下表达式
有时候,我们可能需要做一些额外的测试,以便使用CASE表达式进一步对数据进行分类。当出现这种情况时,可以使用嵌套的CASE表达式。清单7中的代码展示了一个嵌套案例表达式的示例,以便进一步对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语句的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”中的行。为了实现这一点,我将相同的CASE表达式放在WHERE子句中使用的清单2中。我使用CASE表达式放在WHERE条件的左边,因此它将根据OrderDT列产生不同的“Year…”字符串。然后,我测试了从CASE表达式生成的字符串,看看它是否等于“Year 1”的值,当它是一行时,将从MyOrder表返回。请记住,我不建议使用一个CASE表达式来从日期列中选择date,使用like“Year 1”,如果有其他更好的方法,比如使用Year函数来选择给定年份的行。我只是在这里演示了如何在WHERE子句中使用CASE语句。
利用IIF函数缩短案例表达式
随着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,则执行“伪值”。就像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:简单表达式的例子
清单9中的代码只有一个表达式,用于确定OrderAmt是高还是低的美元订单。如果“OrderAMT > 200”的表达式计算为TRUE,那么OrderType值将被设置为“高$ Order”。如果当表达式计算为FALSE时,则为OrderType值设置“低$ Order”。
使用IIF函数而不是CASE表达式的重新写的代码可以在清单10中找到。
SELECT OrderAmt,
IIF(OrderAmt > 200,
'High $ Order',
'Low $ Order') AS OrderType
FROM MyOrder;
清单10:使用IIF函数的示例
通过查看清单10,您可以看到为什么IIF函数被认为是CASE表达式的简写版本。单词CASE被替换为“IIF(”字符串,“THEN”子句用逗号替换,“ELSE”子句用逗号替换,“END”替换为“)”。当布尔表达式“OrderAmt > 200”为TRUE时,将显示“高$ Order”的值。当布尔表达式“OrderAmt > 200”被评估为FALSE时,将显示“低$ Order”。如果您运行清单9和10中的代码,您将看到它们都输出了完全相同的结果。
示例嵌套IIF函数。
就像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功能一样,也存在一些限制。下面是关于案例和IIF构造的一些限制。
案例表达的局限性:
您只能有多达10个级别的嵌套在CASE表达式中。
CASE表达式不能用于控制TSQL语句的执行流。
IIF功能限制:
您只能有多达10层的IIF子句嵌套。
总结
CASE表达式和IIF函数允许您在TSQL代码中放置表达式逻辑,这将根据表达式的计算结果更改代码的结果。通过使用IIF函数和CASE表达式支持的比较表达式,您可以使用不同的代码块执行,这取决于比较表达式的计算结果为真还是假。案例表达式和IIF函数为您提供编程控制,以满足您可能不具备的业务需求。
问题和答案
在本节中,您可以通过回答下列问题来回顾您如何理解使用这个案例和IIF结构。
问题1:
案例表达式有两种不同的语法变体:简单和搜索。下面的两个语句最好地描述了简单和搜索的CASE表达式之间的区别(选择2)。
简单的CASE语法只支持相等运算符,而搜索的CASE语法支持多个运算符。
简单的CASE语法支持多个操作符,而搜索的CASE语法只支持相等运算符。
简单的CASE语法有它在WHEN子句之后指定的布尔表达式,而搜索的CASE语法在CASE语句后面有布尔表达式的左边,在WHEN子句后面的布尔表达式的右边。
简单的CASE语法在CASE语句后面的布尔表达式的左边,在WHEN子句后面的布尔表达式的右边,而搜索的CASE表达式在WHEN子句后面有它的布尔表达式。
问题2:
如果CASE表达式有多个WHEN子句的值为TRUE,那么/ELSE子句是否被执行?
最后一个计算为TRUE的子句的表达式被执行。
然后执行计算为TRUE的第一个WHEN子句的表达式。
所有计算结果为TRUE的子句的表达式都被执行。
其他表达式执行。
问题3:
一个CASE表达式或IIF函数有多少个嵌套级别?
8
10
16
32
答案:
问题1:
答案是a和d。一个简单的CASE语句只能使用相等运算符,而搜索的CASE表达式可以处理多个运算符,以及复杂的布尔表达式。另外,简单的CASE句法在单词CASE后面还有等式运算符的左边部分,在单词后面有等号右边的右边部分。搜索的CASE表达式必须在WHEN子句之后完成布尔操作(左手部分,操作符,右边部分)。
问题2:
正确的答案是b。如果多个WHEN子句计算为TRUE,那么SQL Server只执行第一个WHEN子句的then部分。当被评估为真的子句被跳过时,所有其他的子句都被省略了。
问题3:
正确的答案是b. CASE表达式和IIF函数只支持多达10个嵌套级别。