一、简介
官方定义CASE是一种表达式,它基于某种格式,按照格式去编写表达式,其中表达式的逻辑是:指定特定的值与条件列表去匹配,返回对应的值。
CASE表达式类似我们编程语言中的 if else 和 switch 的逻辑,那么久代表我们可以拿一些值做判断,做出与之对应的处理。
CASE表达式的用途很广,在开发中使用率也很高,所以个人觉得有必要把这个基础的知识点吃透。CASE表达式用的最多的就是SELECT查询语句中,但也不局限于此。
实际上CASE表达式可以用于允许使用有效表达式的任意语句或子句中。例如SELECT、UPDATE、DELETE、和SET等语句以及select_list、IN、WHERE、ORDER BY、HAVING等子句中使用CASE。
CASE表达式有两种格式:
1.简单格式:用一个值或者属性或者表达式,去与一个条件列表做等值判断,匹配到相等的,则返回条件列表对应的结果。
2.搜索格式:像极了编程语言中if else 和 switch,在一个或多个布尔表达式中匹配一个结果为true的,然后返回对应的处理结果。
二、语法初探
--简单格式 CASE表达式
CASE input_expression
WHEN when_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END
--搜索模式
CASE
WHEN Boolean_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END
input_expression(简单格式):
指定一个有效的表达式(可以是常量、变量、列属性),只要表达式返回的是单个数据值。
when_expression(简单格式):
在简单格式中,此处填写的内容是用于和input_expression表达式进行等值比较的。when_expression的内容可以是任何有效的表达式,可以指定多个。
input_expression和when_expression的注意事项(简单格式):
在简单模式中,input_expression和when_expression表达式计算的结果值,要求数据类型必须相同,如果不满足则两个结果值必须满足隐式转换的条件。如果两个条件都不满足,则会提示“数据类型转换失败”。
result_expression:
CASE表达式匹配后返回的结果,结果可以指定任何有效的表达式。
简单格式:当 input_expression = when_expression的计算结果相等时,将其返回。
搜索格式:当Boolean_expression表达式计算结果为true时,将其返回。
else_result_expression:
一个可选的部分,可以指定有效的表达式,逻辑和编程语言中的ELSE是一个逻辑。当指定值和比较值列表没有一个匹配为true时,将其作为结果返回。
如果没有指定else_result_expression表达式并且匹配结果都不为true时,那么最终返回NULL。
Boolean_expression(搜索格式):
使用搜索格式时的写法,可以指定一个有效的布尔表达式,并且可以指定多个。例如,“age>18”、“score between 60 and 100”等。
三、关于CASE表达式返回值的数据类型
在编写CASE表达式的时候,往往我们要编写多个对比的条件列表,那么就意味着对应也有多个返回结果。
当CASE表达式匹配某个条件成功时,会返回相应的处理结果,那么在这个返回结果的数据类型上有一个细节。
这个细节的定论是:当CASE表达式有多个可能返回的结果列表时,匹配成功的这个结果的数据类型,会从结果列表中(包括else部分),参照SQL Server数据类型优先级的规则,选择一个优先级最高的作为返回结果的数据类型。正常的思维逻辑是返回的结果值和数据类型是对应的。例如,1代表int类型、'a'代表字符类型。但是实际结果往往让我们意外,示例图如下:
(如果CASE表达式匹配返的结果的数据类型)和(在所有结果中根据数据类型优先级规则确定了的数据类型)不相同,并且也不符合隐式转换,那么执行的时候就会出现错误。
示例图:
如果 返回结果'二'写成'2',那么就符合隐式转换,查询可以成功执行。
四、CASE表达式的运用示例
A.在SELECT语句中使用简单格式
简单格式的工作逻辑:根据CASE关键字后指定的表达式,去和一个或多个when子句中的表达式进行比较,这种比较是等值比较判断两者是否相等。
业务场景:某旅游网站想查询出其下合作的酒店信息,酒店信息来自主要酒店表,用户想要知道酒店的对应星级名称,因为星级就那么固定几个(1-5),所以在建的时候没有必要建立主外键关联表,
对应的数据列存储的1-5的数字。显然直接查询显示不太友好和明确,对于这种特定标识特定的语义化的情况,就是使用CASE表达式简单格式的最佳场景。
示例代码:
select hotelsName, address,phone,
case grade
when 1 then '一星级'
when 2 then '二星级'
when 3 then '三星级'
when 4 then '四星级'
when 5 then '五星级'
else '未知' end as grade
from Hotels
B.在SELECT语句中使用搜索格式
搜索格式的工作逻辑:指定一个或多个when子句,并在其指定布尔表达式,和对应的返回结果。
搜索格式和简单格式对比:书写结构上和简单格式相似,搜索格式在CASE关键字后没有指定表达式,而是在when子句中指定布尔表达式。
搜索格式显然在逻辑上更灵活,而且搜索格式显然可以兼容简单格式的判断逻辑,简单格式则只局限于等值判断。
业务场景:根据数值范围,作出逻辑的定义。某婚恋网站,想查询男性用户时根据年龄,然后根据特定逻辑的范围,对用户打上年龄化的标签。
示例代码:
select case
when Age>18 and Age <30 then '小鲜肉'
when Age>30 and Age <45 then '熟男'
when Age>45 and Age<50 then '大叔' end ageFlag
from Student
where Gender='男'
C.在ORDER BY子句中使用CASE
业务场景:老师想查询学生的成绩信息。对于及格的(passFlag=1)学生的成绩分数想看从高到底查看,以便更好的培养尖子生。对于不及格(passFlag=0)的学生的成绩分数想从底到高查看,以便不同情况对差生进行补习。
示例代码:
select b.passFlag,a.StudentId,a.StudentName,(b.CSharp+b.SQLServerDB) as score
from Student a
inner join ScoreList b on a.StudentId=b.StudentId
order by case passFlag when 0 then (b.CSharp+b.SQLServerDB) end asc,
case passFlag when 1 then (b.CSharp+b.SQLServerDB) end desc
D.CASE表达式实现数据行专列
在这里使用CASE表达式实现数据的行专列,并不是唯一可行的方法,而是通过此示例更好的融汇贯通CASE表达式的运用。对于行转列的这种特定的操作,SQL Server提供了PIVOT的方案来解决。
CASE表达式实现行转列的方式依赖于的表结关联系:
此关联中存在一个多对多的中间表,每行行会显示课程对应考的分数。观察这种关系结构和CASE表达式的特性,运用起来实现行转为列。在个示例图中,即课程转为列,列值显示分数。
实现代码:
select a.name ,
MAX(case c.cid when 1 then b.score end) as '语文',
MAX(case c.cid when 2 then b.score end) as '数学',
MAX(case c.cid when 3 then b.score end ) as '体育'
from StudentInfo a
inner join StuCourseGrade b on a.stuId=b.stuId
inner join Curriculum c on b.cid=c.cid
group by a.name
我们分析一下查询逻辑如何进行的处理: