暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SQL笔记| case表达式

chkl 2025-05-29
30

在SQL里表达条件分支-CASE

CASE表达式是从SQL-92标准开始被引入的。在CASE 表达式里,可以使用 BETWEEN 、LIKE和 < 、> 等便利的谓词组合,以及能嵌套子查询的IN 和 EXISTS谓词。可以实现行列转换、已有数据重分组(分类)、与约束的结合使用、针对聚合结果的条件分支等功能。
简化版:DECODE(Oracle)、IF(Mysql)

1、CASE 表达式写法

简单CASE表达式

CASE sex
	when '1' then '男'
  	when '2' then '女'
  ELSE '其他' END

搜索CASE表达式

CASE
	when  sex = '1' then '男'
  	when  sex = '2' then '女'
  ELSE '其他' END

这两种写法的执行结果是相同的,sex 列(字段)如果是 ‘1’ ,那么结果为男;如果是 ‘2’ ,那么结果为女。
CASE在匹配给定条件时,发现为真的 WHEN 子句时,CASE 表达式的真假值判断就会中止,而剩余的 WHEN 子句会被忽略。为了避免引起不必要的混乱,使用 WHEN 子句时要注意条件的排他性。
需注意事项:
1)统一各分支返回的数据类型:一定要注意 CASE 表达式里各个分支返回的数据类型是否一致。某个分支返回字符型,而其他分支返回数值型的写法是不正确的。
2)不要忘了写 END:不写END是语法错误,这是不允许的。
3)养成写 ELSE 子句的习惯:与 END 不同,ELSE 子句是可选的,不写也不会出错。不写 ELSE 子句时,CASE 表达式的执行结果是 NULL 。

2、将已有编号方式转换为新的方式并统计(合并统计)

SELECT 
    CASE pref_name 
        WHEN '德岛' THEN '四国'
        WHEN '香川' THEN '四国'
        WHEN '爱媛' THEN '四国'
        WHEN '高知' THEN '四国'
        WHEN '福冈' THEN '九州'
        WHEN '佐贺' THEN '九州'
        WHEN '长崎' THEN '九州'
    ELSE '其他' END AS district,
    SUM(population) 
FROM poptbl
GROUP BY 
    CASE pref_name 
        WHEN '德岛' THEN '四国'
        WHEN '香川' THEN '四国'
        WHEN '爱媛' THEN '四国'
        WHEN '高知' THEN '四国'
        WHEN '福冈' THEN '九州'
        WHEN '佐贺' THEN '九州'
        WHEN '长崎' THEN '九州'
    ELSE '其他' END;
-- 使用select中的别名,pg、mysql中支持以下写法,Oracle、DB2、SQL Server可能会报错。
SELECT 
    CASE pref_name 
        WHEN '德岛' THEN '四国'
        WHEN '香川' THEN '四国'
        WHEN '爱媛' THEN '四国'
        WHEN '高知' THEN '四国'
        WHEN '福冈' THEN '九州'
        WHEN '佐贺' THEN '九州'
        WHEN '长崎' THEN '九州'
    ELSE '其他' END AS district,
    SUM(population) 
FROM poptbl
GROUP BY district;

3、用一条SQL语句进行多条件统计

SELECT
    pref_name,
	-- 男性人口
    SUM( CASE WHEN sex=1 THEN population ELSE 0 END ) AS '男' 
	-- 女性人口
    SUM( CASE WHEN sex=2 THEN population ELSE 0 END ) AS '女' 
FROM poptlb
GROUP By pref_name;

上面代码所做的是,分别统计每个县的男性(即’1’)人口和女性(即’2’)人口。也就是说,这里是将“行结构”的数据转换成了“列结构”的数据。除了SUM,COUNT、AVG等聚合韩素也都可以用于将行结构的数据转换成列结构的数据。

4、用CHECK约束定义多个列的条件关系

假设某公司规定“女性员工的工资必须在 20 万日元以下”,而在这个公司的人事表中,这条无理的规定是使用 CHECK 约束来描述的,代码如下所示:

CONSTRAINT check_salary CHECK ( 
    CASE WHEN sex = '2' THEN 
        CASE WHEN salary <= 200000
            THEN 1 ELSE 0 END
        ELSE 1 END = 1 
)

这段代码里,CASE表达式被嵌入CHECK约束里,描述了“如果是女性员工则工资必须在 20 万日元以下”这个命题(判断事情的语句)。

5、在UPDATE语句中进行条件分支

条件:
对当前工资为 30 万日元以上的员工,降薪 10%。
对当前工资为 25 万日元以上且不满 28 万日元的员工,加薪 20%。

UPDATE Salaries
	SET salary = CASE WHEN salary>300000 THEN salary*0.9
                  WHEN salary>=250000 AND salary <280000 THEN salary * 1.2
                  ELSE salary
             END;

6、表之间的数据匹配

与DECODE函数等相比,CASE的一大优势在于能判断表达式。在CASE表达式里,我们可以使用 BETWEEN 、LIKE和 < 、> 等便利的谓词组合,以及能嵌套子查询的IN 和 EXISTS谓词。

--- 使用EXIST谓词
SELECT CM.course_name,
    CASE WHEN EXISTS (SELECT course_id FROM OpenCourses OC WHERE month = 200706 AND OC.course_id = CM.course_id) 
        THEN '○' ELSE '×' 
    END AS "6 月",
    CASE WHEN EXISTS (SELECT course_id FROM OpenCourses OC WHERE month = 200707 AND OC.course_id = CM.course_id) 
        THEN '○' ELSE '×' 
    END AS "7 月",
    CASE WHEN EXISTS (SELECT course_id FROM OpenCourses OC WHERE month = 200708 AND OC.course_id = CM.course_id) 
        THEN '○' ELSE '×' 
    END AS "8 月"
FROM CourseMaster CM;

无论使用IN还是EXISTS,得到的结果是一样的,但从性能方面来说,EXISTS更好。通过EXISTS进行的子查询能够用到主键索引,因此当表中数据多时,使用EXISTS的优势会更大。

7、在CASE表达式中使用聚合函数

对于加入了多个社团的学生,通过将其“主社团标志”列设置为 Y 或者 N 来表明哪一个社团是他的主社团;对于只加入了一个社团的学生,将其“主社团标志”列设置为 N。
现需要查询出所有学生加入的社团,若加入了多个则显示主社团

SELECT 
    std_id,
    CASE WHEN COUNT(*) = 1 THEN MAX(club_id) 
         ELSE MAX(CASE WHEN main_club_flg = 'Y' THEN club_id ELSE NULL END)
    END AS 'main_club'
FROM student_club
GROUP BY std_id

8、练习

多列数据的最大值

--求x和y和z三者中的最大值
select key,
	case when case when x<y then y else x end <z
		then z
		else case when x<y then y else x end
	end as agreatest
from greatests;
--转换成行格式后使用MAX函数
select key,max(col) as greatest
 from (select key,x as col from greatests 
	union all
	select key,y as col form greatests
	union all
	select key,z as col from greatests)tmp
group by key;
-- 使用函数
select key,greatest(greatest(x,y),z) as greatest from greatests;

转换行列-在表头里加入汇总

select sex,sum(population) as total,
	sum(case when pref_name = '德岛' then population else 0 end ) as col_1,
	sum(case when pref_name = '香川' then population else 0 end ) as col_2,
	sum(case when pref_name = '爱媛' then population else 0 end ) as col_3,
	sum(case when pref_name = '高知' then population else 0 end ) as col_4,
	sum(case when pref_name in('德岛','香川' ,'爱媛','高知') then population else 0 end ) as col_5
from poptb12 
group by sex;

用order by生成“排序”列

select key from greatests
order by case key
	when 'B' then 1
	when 'A' then 2
	when 'D' then 3
	when 'C' then 4
	else null end ;

select key from greatests
order by case 
	when key like 'B%' then 1
	when key like 'A%' then 2
	when key like 'D%' then 3
	when key like 'C%' then 4
	else null end ;
最后修改时间:2025-05-29 15:05:42
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论