首页 > 数据库 >关于SQL-case when最全面的学习笔记

关于SQL-case when最全面的学习笔记

时间:2024-01-20 16:44:06浏览次数:50  
标签:case CASE WHEN when ELSE score SQL id

原文zhuanlan.zhihu.com/p/110198759?from_voters_page=true

case when
推荐学习书籍:
1、SQL基础教程 6-3
2、SQL进阶教程 1-1

case when 是SQL语法中提供的标准的条件分支。
条件分支在MYSQL中即为IF函数,不同的数据库都会提供自己的一些函数,但是CASE WHEN 更加通用。

CASE语句的两种写法


1、搜索CASE表达式
(只会这一种方式即可)

CASE 
WHEN <求值表达式> THEN <表达式1>
WHEN <求值表达式> THEN <表达式2>
ELSE <表达式>
END
<求值表达式> :一般为字段 【=、>、<、in、等】如 字段 = "1"
<表达式1> : 一般为字段或者字符串或者数值等。



2、简单CASE表达式
CASE <表达式>
WHEN <表达式> THEN <表达式>
WHEN <表达式> THEN <表达式>
ELSE <表达式>
END
注:

ELSE 可以不写,默认返回null
end 不可以忘记
当一个case子句中有多个判断逻辑时、字段类型需要一致
当一个case子句中有多个判断逻辑时、第一个为真的结果会被输出
每一个case子句只输出一个结果
case 执行逻辑


case 应用


1、添加列
现有学生表一张




先在需要根据生日列 **生成新的一列 **:显示90后,00后,10后

代码:

SELECT 
s_name
,s_birthday 
,CASE 
        WHEN YEAR(s_birthday)>=1990 and YEAR(s_birthday)<2000 THEN "90后"
        WHEN YEAR(s_birthday)>=2000 and YEAR(s_birthday)<2010 THEN "00后"
        WHEN YEAR(s_birthday)>=2010 and YEAR(s_birthday)<2020 THEN "10后"
    ELSE "未知"
    END 
    AS "阶段"
from student ;
显示结果:


2、行转为列
现统计了学生的总成绩


。
先在想将赵雷和李云的总成绩展示成:




可以输入以下代码:

SELECT 
 SUM(CASE WHEN s_name = "李云" THEN score ELSE 0 END) as "李云"
,SUM(CASE   WHEN s_name = "赵雷" THEN score ELSE 0 END) as "赵雷"
FROM
 score a INNER JOIN student b   on a.s_id=b.s_id;


3、实现分组统计
一般我们都使用group by来实现分组统计,但是有的时候需要对字段先分组再统计。

比如我们想知道成绩表现为不及格、良、优秀的课程数分别是多少

3.1 实现人次的分组统计
SELECT 
CASE 
        WHEN score<60 THEN "不及格"
        WHEN score>=60 and score<85 THEN "良"
        WHEN score>=85 THEN "优秀"
    ELSE "未知"   END     AS "阶段"
  ,count(*) as "人次"
from  score a INNER JOIN student b  on a.s_id=b.s_id
GROUP BY CASE 
        WHEN score<60 THEN "不及格"
        WHEN score>=60 and score<85 THEN "良"
        WHEN score>=85 THEN "优秀"
    ELSE "未知"
    END ;


因为每个人会参加多门课程,所以当使用count(*)的时候,就是对于人次计算的,学生是没有去重的。


3.2 实现人数的分组统计
SELECT 
CASE 
        WHEN score<60 THEN "不及格"
        WHEN score>=60 and score<85 THEN "良"
        WHEN score>=85 THEN "优秀"
    ELSE "未知"
    END 
    AS "阶段"
,count(DISTINCT a.s_id) as "包含人数"

from  score a INNER JOIN student b  on a.s_id=b.s_id
GROUP BY CASE 
        WHEN score<60 THEN "不及格"
        WHEN score>=60 and score<85 THEN "良"
        WHEN score>=85 THEN "优秀"
    ELSE "未知"
    END ;


这里使用里count(DISTINCT a.s_id) 对学生进行了去重。

3.3 group by分组中使用别名
SELECT 
CASE 
        WHEN score<60 THEN "不及格"
        WHEN score>=60 and score<85 THEN "良"
        WHEN score>=85 THEN "优秀"
    ELSE "未知"
    END 
    AS type
,count(*)
from  score a INNER JOIN student b  on a.s_id=b.s_id
GROUP BY type;
更加SQL执行顺序,是不应该使用别名的,但是在某些,比如MYSQL中执行时会先扫描select后的字段,所以实际执行是可以实现的。


4、透视表方式展示
case 表达式可以实现sql像excel透视表类似的功能。

比如我想知道每门课程,学生成绩的分别情况


可以使用下方代码进行完成

SELECT 
c_id,
sum(CASE WHEN score<60 THEN 1   ELSE 0  END )   AS "不及格"
,sum(CASE WHEN score>=60 and score<85 THEN 1    ELSE 0 END) as "良"
,sum(CASE WHEN score>=85 THEN 1 ELSE 0 END) as "优秀"
from  score a LEFT JOIN student b   on a.s_id=b.s_id
where c_id is not null
GROUP BY a.c_id;


case 执行逻辑


1、没有group by 的聚合
上面知识点 行转为列。
代码如下:

SELECT 
 SUM(CASE WHEN s_name = "李云" THEN score ELSE 0 END) as "李云"
,SUM(CASE   WHEN s_name = "赵雷" THEN score ELSE 0 END) as "赵雷"
FROM
 score a INNER JOIN student b   on a.s_id=b.s_id;
结果为

我们在语句中使用了聚合函数,这个聚合函数使得数据展示为一行。如果不使用会如何?

数据会以每一行的形式展示。
因为SQL在执行完语句后会逐行对数据进行计算。



2、有group by 的汇总数据
接着上面来讲。
这里有个问题,既然用group by了,为何还要使用SUM.。(这里主要是在mysql5.7以下会遇到这样的问题)
我就在实际的统计中,遇到了这样的问题。
因为自己的库装的是mysql,5.8 所以这样不符合规范的代码是运行不了的,因为要修改配置比较麻烦,我这里就手动写出他的

| c_id | 不及格 | 良 | 优秀 | | --- | --- | --- | --- | | 01 | 1 | 0 | 0 | | 02 | 0 | 1 | 0 | | 03 | 1 | 0 | 0 |

这里就会出现每行只有一个结果。

SELECT 
c_id,
CASE WHEN score<60 THEN 1   ELSE 0  END     AS "不及格"
,CASE WHEN score>=60 and score<85 THEN 1    ELSE 0 END as "良"
,CASE WHEN score>=85 THEN 1 ELSE 0 END as "优秀"
from  score a LEFT JOIN student b   on a.s_id=b.s_id
where c_id is not null
GROUP BY a.c_id;
因为有groupby的存在,很容易导致计算错误还,看不错来,这为一个小坑。

这里关于SQL的执行顺序还需要单独再进行一章。

标签:case,CASE,WHEN,when,ELSE,score,SQL,id
From: https://www.cnblogs.com/liujiaping/p/17976710

相关文章

  • HDU2966 In case of failure 题解
    QuestionHDU2966Incaseoffailure给出平面上\(n\)个点坐标,求每个点最近的点的欧几里得距离的平方Solution算是一道K-D树的板子题维度\(K=2\)建立\(K-D\)树,在每一层更新当前最小答案\(now\_ans\),如果在然后继续遍历当前维度下距离\(\le\)的区块随机数据时间复......
  • 盘点编写 sql 上的那些骚操作(针对mysql而言)
    前言咋说呢,最近交接了一个XXX统计系统到我手上,点进去系统主页,看了下实现了哪些功能,页面看着很简单就那么几个统计模块,本来想着就那么几张报表的crud来着,看了下代码也还好体量也不大,于是乎美滋滋的随波逐流了,后来出现了一个bug说什么数据统计的不对,想着快速给他改掉,顺着控制层,一路摸......
  • 如何防护网站存在的sql注入攻击漏洞
    SQL注入攻击是最危险的Web漏洞之一,危害性极大,造成的后果不堪设想,因此受到了大家的高度重视。那么你知道SQL注入攻击防范方法有哪些吗?SQL注入是一种网站的攻击方法。它将SQL代码添加到网站前端GETPOST参数中,并将其传递给mysql数据库进行分析和执行语句攻击。它是一种利用应用程序......
  • MYSQL-数据表基本
    1、创建表createtable表名(列名类型是否可以为空,列名类型是否可以为空)ENGINE=InnoDBDEFAULTCHARSET=utf82、删除表droptable表名3、清空表deletefrom表名truncatetable表名4、修改表添加列:altertable表名add列名类型删除列:alter......
  • MySQL 视图
    视图(View)是一种虚拟存在的表,视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。创建CREATE[......
  • MYSQL自增步长
    1、对于自增列,必须是索引(含主键)。2、对于自增可以设置步长和起始值基于会话级别:showsessionvariableslike'auto_inc%';查看全局变量setsessionauto_increment_increment=2;设置会话步长#setsessio......
  • dotnet 多数据库 sqlite efcore model和entity区别 一对多 多对一 多对多
    efcore-multi-db/MultiDb.slnMicrosoftVisualStudioSolutionFile,FormatVersion12.00#VisualStudio15VisualStudioVersion=15.0.27130.2024MinimumVisualStudioVersion=10.0.40219.1Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}")="......
  • SQL优化
    1、Insert优化批量插入(一次也不宜太多,500~1000,根据业务情况决定),避免频繁开启、关闭事务手动提交事务主键顺序插入(性能高于乱序插入)大批量的数据插入如果一次性需要插入大批量数据,使用insert语句插入性能较低,此时可以使用MySQL数据库提供的load指令进行插入  2、主键优......
  • Hive SQL底层执行过程详细剖析
     本文结构采用宏观着眼,微观入手,从整体到细节的方式剖析HiveSQL底层原理。第一节先介绍Hive底层的整体执行流程,然后第二节介绍执行流程中的SQL编译成MapReduce的过程,第三节剖析SQL编译成MapReduce的具体实现原理。HiveHive是什么?Hive是数据仓库工具,再具体点就......
  • MySQL中的加密函数
    本文简单介绍MySQL中的加密函数。MySQL提供了多种加密函数,以下是一些常用的:PASSWORD(str):用于密码加密,通常用于创建用户时对密码进行加密。MD5(str):生成一个128位的加密串,返回一个32位的16进制数。SHA1(str):生成一个160位的加密串,返回一个40位的16进制数。ENCODE(str......