SQL CASE 表达式的具体使用
作者:黄子毅 发布时间:2024-01-28 09:57:29
CASE 表达式分为简单表达式与搜索表达式,其中搜索表达式可以覆盖简单表达式的全部能力,我也建议只写搜索表达式,而不要写简单表达式。
简单表达式:
SELECT CASE city
WHEN '北京' THEN 1
WHEN '天津' THEN 2
ELSE 0
END AS abc
FROM test
搜索表达式:
SELECT CASE
WHEN city = '北京' THEN 1
WHEN city = '天津' THEN 2
ELSE 0
END AS abc
FROM test
明显可以看出,简单表达式只是搜索表达式 a = b
的特例,因为无法书写任何符号,只要条件换成 a > b
就无法胜任了,而搜索表达式不但可以轻松胜任,甚至可以写聚合函数。
CASE 表达式里的聚合函数
为什么 CASE 表达式里可以写聚合函数?
因为本身表达式就支持聚合函数,比如下面的语法,我们不会觉得奇怪:
SELECT sum(pv), avg(uv) from test
本身 SQL 就支持多种不同的聚合方式同时计算,所以将其用在 CASE 表达式里,也是顺其自然的:
SELECT CASE
WHEN count(city) = 100 THEN 1
WHEN sum(dau) > 200 THEN 2
ELSE 0
END AS abc
FROM test
只要 SQL 表达式中存在聚合函数,那么整个表达式都聚合了,此时访问非聚合变量没有任何意义。所以上面的例子,即便在 CASE 表达式中使用了聚合,其实也不过是聚合了一次后,按照条件进行判断罢了。
这个特性可以解决很多实际问题,比如将一些复杂聚合判断条件的结果用 SQL 结构输出,那么很可能是下面这种写法:
SELECT CASE
WHEN 聚合函数(字段) 符合什么条件 THEN xxx
... 可能有 N 个
ELSE NULL
END AS abc
FROM test
这也可以认为是一种行转列的过程,即 把行聚合后的结果通过一条条 CASE 表达式形成一个个新的列。
聚合与非聚合不能混用
我们希望利用 CASE 表达式找出那些 pv 大于平均值的行,以下这种想当然的写法是错误的:
SELECT CASE
WHEN pv > avg(pv) THEN 'yes'
ELSE 'no'
END AS abc
FROM test
原因是,只要 SQL 中存在聚合表达式,那么整条 SQL 就都是聚合的,所以返回的结果只有一条,而我们期望查询结果不聚合,只是判断条件用到了聚合结果,那么就要使用子查询。
为什么子查询可以解决问题?因为子查询的聚合发生在子查询,而不影响当前父查询,理解了这一点,就知道为什么下面的写法才是正确的了:
SELECT CASE
WHEN pv > ( SELECT avg(pv) from test ) THEN 'yes'
ELSE 'no'
END AS abc
FROM test
这个例子也说明了 CASE 表达式里可以使用子查询,因为子查询是先计算的,所以查询结果在哪儿都能用,CASE 表达式也不例外。
WHERE 中的 CASE
WHERE 后面也可以跟 CASE 表达式的,用来做一些需要特殊枚举处理的筛选。
比如下面的例子:
SELECT * FROM demo WHERE
CASE
WHEN city = '北京' THEN true
ELSE ID > 5
END
本来我们要查询 ID 大于 5 的数据,但我想对北京这个城市特别对待,那么就可以在判断条件中再进行 CASE 分支判断。
这个场景在 BI 工具里等价于,创建一个 CASE 表达式字段,可以拖入筛选条件生效。
GROUP BY 中的 CASE
想不到吧,GROUP BY 里都可以写 CASE 表达式:
SELECT isPower, sum(gdp) FROM test GROUP BY CASE
WHEN isPower = 1 THEN city, area
ELSE city
END
上面例子表示,计算 GDP 时,对于非常发达的城市,按照每个区粒度查看聚合结果,也就是看的粒度更细一些,而对于欠发达地区,本身 gdp 也不高,直接按照城市粒度看聚合结果。
这样,就按照不同的条件对数据进行了分组聚合。由于返回行结果是混在一起的,像这个例子,可以根据 isPower 字段是否为 1 判断,是否按照城市、区域进行了聚合,如果没有其他更显著的标识,可能导致无法区分不同行的聚合粒度,因此谨慎使用。
ORDER BY 中的 CASE
同样,ORDER BY 使用 CASE 表达式,会将排序结果按照 CASE 分类进行分组,每组按照自己的规则排序,比如:
SELECT * FROM test ORDER BY CASE
WHEN isPower = 1 THEN gdp
ELSE people
END
上面的例子,对发达地区采用 gdp 排序,否则采用人口数量排序。
支持简单与搜索两种写法,推荐搜索写法。
支持聚合与子查询,需要注意不同情况的特点。
可以写在 SQL 查询的几乎任何地方,只要是可以写字段的地方,基本上就可以替换为 CASE 表达式。
除了 SELECT 外,CASE 表达式还广泛应用在 INSERT 与 UPDATE,其中 UPDATE 的妙用是不用将 SQL 拆分为多条,所以不用担心数据变更后对判断条件的二次影响。
来源:https://juejin.cn/post/7077358417643307039


猜你喜欢
- 前言因为Python的水平目前一直是处于能用阶段,平时写的脚本使用的Python的写法也比较的简单,没有写过稍微大一点的项目。对Python
- 方式1.打开Windows的cmd,在cmd中输入jupyter notebook --generate-config如下图:
- matlab中的filter函数:y = filter(b,a,x)python实现matlab中的filter函数def filter_m
- 本文实例为大家分享了Django下完成文件上传和下载功能的具体代码,供大家参考,具体内容如下一、文件上传Views.pydef upload
- JS中作用域的概念: 表示变量或函数起作用的区域,指代了它们在什么样的上下文中执行,亦即上下文执行环境。Javascript的作用域只有两种
- 我们可以通过mysql命令查看mysql的安装路径:# 以下两个sql任意一个可查询select @@basedir as basePath
- 几个利用背景结合a:hover做的小东东,希望对大家有所帮助。<!DOCTYPE html PUBLIC "-//W3C//
- 前言事务性数据字典与原子DDL,是MySQL 8.0推出的两个非常重要的新特性,之所以将这两个新特性放在一起,是因为两者密切相关,事务性数据
- 前言之前在csdn上看见用python写春联的,这次突发奇想用python制作一张壁纸,其元素包括背景、文字、图片。知识点 用PIL创建一张
- Pytest和Unittest测试框架的区别?如何区分这两者,很简单unittest作为官方的测试框架,在测试方面更加基础,并且可以再次基础
- 在进行文本分析、提取关键词时,新闻评论等文本通常是中英文及其他语言的混杂,若不加处理直接分析,结果往往差强人意。下面对中英文文本进行分离做一
- 在开发的过程中,几乎不可能一次性就能写出毫无破绽的程序,断点调试代码是一个普遍的需求。作为前端开发工程师,以往我们开发的JavaScript
- 首先是下载图解1、首先卸载centos7中自带的mariadbrpm -qa|grep mariadb //查询出来已安装的mariadbr
- webpack代码拆分webpack有两种组织模块依赖的方式,同步和异步。异步依赖作为分割点,形成一个新的块,在优化了依赖树后,每一个异步区
- 1. 算法描述二分法是一种效率比较高的搜索方法回忆之前做过的猜数字的小游戏,预先给定一个小于100的正整数x,让你猜猜测过程中给予大小判断的
- 新年钟声刚过,淘宝新版首页全“心”上线了,这次设计大胆的将布局从 960px 伸展至 1000px,页面更通透,新首页更大范围的实践了 HT
- 一、原理如题,我有一个模板课件.pptx:其内容:我想复制模板中间的某一页多次,比如复制第1页,然后复制3次,prs = Presentat
- <table border="1" cellpadding="0&quo
- 本文主要介绍了OpenCV 图像对比度,具有一定的参考价值,感兴趣的可以了解一下实现原理图像对比度指的是一幅图像中明暗区域最亮的白和最暗的黑
- 因为有把python程序打包成exe的需求,所以,有了如下的代码import timeclass LoopOver(Exception):