数据库的高阶知识

目录

  • 一、case when
  • 二、几种常见的嵌套查询
    • 2.1 比较运算符
    • 2.2 ANY/ALL 关键词
    • 2.3 in 关键词
    • 2.4 EXISTS关键词
    • 2.5 in和exists的异同点
  • 三、开窗函数

数据库的基本知识
数据库的高阶知识

一、case when

  在实际工作中,经常会涉及以下两类问题:

  • 数据的映射处理:比如将离散的数字变成有意义的业务说明,或是将连续的数值映射到离散的区间带
  • 有针对性的筛选计算:将细颗粒单位转换为粗颗粒单位的聚合运算

  这两类问题,我们通常使用case when语句来解决,case语句其实就是mysql中的控制流语句,类似于其他很多编程工具中的if …then…的分支判断逻辑。
  关于case when的表达方式有两种:“简单case函数法”和“case搜索函数法”。这两种方法各有优点,比如“简单case函数法”的语法更加简洁,但是只能处理等式的问题,“case搜索函数法”更加灵活好用,可以处理等式问题也可以处理不等式问题。

# 简单case函数法
case <name>when <when_condition> then <result>[when <when_condition> then <result>][......][else <else_result>]
end
#case搜索函数法
case when <bool_condition> then <result>[when <bool_condition> then <result>][.......][else <else_result>]
end

  下面以电商数据为例学习CASE WHEN语法在数据查询中几种常见用法,该数据一共包含7个字段和1000条样本,7个字段分别是用户ID,用户出生日期、下单时间、订单ID、支付方式、支付金额和是否享受折扣。数据链接:https://pan.quark.cn/s/af980c28a2d0

-- 离散数值与实际业务含义一一对应
select *,case when is_discount = 1 then "享受折扣"else "无折扣"end discount_new,casewhen pay_type = 1 then "支付宝支付"when pay_type = 2 then "微信支付"else "银行卡支付"end pay_type_new
from goods_orders#根据用户的出生日期将用户分为70后,80后,90后,00后
select *,casewhen year(birthday) between 1970 and 1979 then '70后'when year(birthday) between 1980 and 1989 then '80后'when year(birthday) between 1990 and 1999 then '90后'else '00后'end AGE_GROUP
from goods_orders#长形统计表转换成宽形统计表
select month(order_date) as imonth,sum(case when pay_type = 1 then pay_amt end) as 'ali_pay',sum(case when pay_type = 2 then pay_amt end) as 'wechat',sum(case when pay_type = 3 then pay_amt end) as 'bank_card'
from goods_orders		
where year(order_date) = 2023
group by imonth
order by imonth

在这里插入图片描述

二、几种常见的嵌套查询

  嵌套查询,也称为子查询,是实际工作中经常用到的一种查询方式。子查询其实就是在已有的查询语句中的where后面再嵌套一层查询语句,也就是把内层查询结果当做外层查询参照的数据表来使用。
  在工作中,经常会遇见4种子查询,即含有比较运算符(>、>=、<、<=、=、!=)、ANY/ALL关键词IN关键词以及EXISTS关键词的嵌套查询。数据链接 :https://pan.quark.cn/s/223ade8607a3

2.1 比较运算符

  比较运算符用于比较两个值,返回布尔值(TRUE 或 FALSE)。

#创建学生信息表
CREATE TABLE stu_info (id INT AUTO_INCREMENT PRIMARY KEY, -- 学生ID,自增主键iname VARCHAR(20),                 -- 学生姓名gender CHAR(1),                    -- 性别(M: 男, F: 女)department VARCHAR(10),            -- 所属院系age INT,                           -- 年龄province VARCHAR(10),              -- 省份email VARCHAR(50),                 -- 邮箱mobilephone CHAR(11)               -- 手机号(11位)
);INSERT INTO stu_info (iname, gender, department, age, province, email, mobilephone)
VALUES
('张三', 'M', '计算机', 20, '北京', 'zhangsan@example.com', '13800138000'),
('李四', 'M', '数学', 21, '上海', 'lisi@example.com', '13800138001'),
('王五', 'F', '物理', 22, '广东', 'wangwu@example.com', '13800138002'),
('赵六', 'M', '化学', 19, '江苏', 'zhaoliu@example.com', '13800138003'),
('孙七', 'F', '生物', 20, '浙江', 'sunqi@example.com', '13800138004'),
('周八', 'M', '计算机', 21, '北京', 'zhouba@example.com', '13800138005'),
......
('武勇', 'M', '生物', 21, '浙江', 'wuyong@example.com', '13800138049');#学生成绩表
CREATE TABLE stu_score (id INT,          -- 学生IDChinese TINYINT, -- 语文成绩(0-100)Math TINYINT,    -- 数学成绩(0-100)English TINYINT  -- 英语成绩(0-100)
);INSERT INTO stu_score (id, Chinese, Math, English)
VALUES
(1, 87, 90, 83),
(2, 78, 85, 88),
(3, 92, 76, 81),
......
(50, 87, 80, 83);# 1.查询年龄超过所有学员平均年龄的学员信息
#第一步先计算学员平均年龄
select avg(age) from stu_info#筛选超过平均年龄的学员信息
select * from stu_info
where age >= 20.5#子查询
select * from stu_info
where age >= (select avg(age) from stu_info)# 2.查询年龄不低于所属系平均年龄的学员信息
select * from stu_info as t1
where age >=(
select avg(age) from stu_info as t2
where t1.department = t2.department)

2.2 ANY/ALL 关键词

  对于含比较运算符的嵌套查询来说,嵌套部分的查询语句只能返回一个值。那如果子查询返回多个值,就需要用到ANY或者ALL关键词了。通常,ANY/ALL关键词经常和比较运算符连用,下面是6种比较运算符与ANY/ALL 关键词的搭配结果:

组合含义组合含义
>ANY大于子查询结果中的某个值>ALL大于子查询结果中的所有值
>=ANY大于等于子查询结果中的某个值>=ALL大于等于子查询结果中的所有值
<ANY小于子查询结果中的某个值<ALL小于子查询结果中的所有值
<=ANY小于等于子查询结果中的某个值<=ALL小于等于子查询结果中的所有值
=ANY等于子查询结果中的某个值=ALL等于子查询结果中的所有值
!=ANY不等于子查询结果中的某个值!=ALL不等于子查询结果中的所有值
# 2.查询非物理系中比物理系任意一个学员年龄小的学员信息
select * from stu_info 
where department != '物理' and
age < any(
select distinct age 
from stu_info
where department = '物理'
)#3.查询非物理系中比物理系所有学员年龄大的学员信息
select * from stu_info 
where department != '物理' and
age > all(
select distinct age 
from stu_info
where department = '物理'
)

2.3 in 关键词

  IN 用于判断某个值是否在指定的值列表中。它可以替代多个 OR 条件,使查询更简洁。

# 查询计算机和物理系的学员信息
select * from stu_info
where department in ("计算机","物理")#查询和张三、王五同一个系的学员信息
select * from stu_info
where department in (
select department from stu_info
where iname in("张三","王五"))#查询语文成绩大于85分的学员信息
select * from stu_info where id in (select id from stu_score
where Chinese >85)

2.4 EXISTS关键词

  EXISTS 用于检查子查询是否返回任何行。如果子查询返回至少一行,则 EXISTS 返回 TRUE,否则返回 FALSE。

#查询语文成绩大于85分的学员信息
select * from stu_info where exists (select * from stu_score
where stu_score.id = stu_info.id and Chinese >85)

2.5 in和exists的异同点

  • 使用场景对比
      in适合用于静态值列表或子查询结果集较小的情况。
-- 查询数学成绩为 85、90 或 95 的学生
SELECT * FROM stu_score
WHERE Math IN (85, 90, 95);-- 查询在某个班级的学生
SELECT * FROM stu_info
WHERE class_id IN (SELECT class_id FROM class WHERE class_name = '计算机');

  exists适合用于动态子查询或子查询结果集较大的情况。

-- 查询有成绩记录的学生
SELECT * FROM stu_info
WHERE EXISTS (SELECT 1 FROM stu_scoreWHERE stu_score.id = stu_info.id
);-- 查询没有成绩记录的学生
SELECT * FROM stu_info
WHERE NOT EXISTS (SELECT 1 FROM stu_scoreWHERE stu_score.id = stu_info.id
);
  • 性能对比
    IN 的性能:
    当子查询结果集较小时,IN 的性能较好,因为子查询的结果会被缓存,外部查询只需要与缓存的结果进行比较。
    当子查询结果集较大时,IN 的性能较差,因为缓存大量数据会占用内存,且比较操作较慢。
    EXISTS 的性能:
    当子查询结果集较大时,EXISTS 的性能较好,因为它不需要缓存结果,且可以在找到第一个匹配项时立即返回 TRUE。
    当子查询结果集较小时,EXISTS 的性能可能略低于 IN,因为需要为外部查询的每一行执行一次子查询。

  • NULL值处理区别
    in:如果子查询的结果中包含 NULL,IN 会忽略 NULL,不会将其与外部查询的值进行比较。

SELECT * FROM stu_score
WHERE Math IN (85, 90, NULL);
#如果 Math 是 NULL,上述查询不会返回该行。

EXISTS:不关心子查询的具体值,只关心是否存在匹配的行。

SELECT * FROM stu_info
WHERE EXISTS (SELECT 1 FROM stu_scoreWHERE stu_score.id = stu_info.id AND Math IS NULL
);

三、开窗函数

  结合order by关键词和limit关键词是可以解决很多的topN问题,比如从二手房数据集中查询出某个地区的最贵的10套房,从电商交易数据集中查询出实付金额最高的5笔交易,从学员信息表中查询出年龄最小的3个学员等。但是,如果需求变成从二手房数据集中查询出各个地区最贵的10套房,从电商数据集中查询出每月实付金额最高的5笔交易,从学员信息表中查询出各个科系下年龄最小的3个学员,该如何解决呢?
  其实这类问题的核心就是,筛选出组内的topN,而不是从全部数据集中挑选出topN。遇到这种既需要分组也需要排序的问题,直接上开窗函数就能解决了。
(1)开窗函数定义
  开窗函数是 SQL 中一种特殊的函数,用于在查询结果集的“窗口”(即一组相关行)上执行计算。与普通的聚合函数(如 SUM、AVG)不同,开窗函数不会将多行合并为一行,而是为每一行返回一个计算结果,同时保留原始行的详细信息。 注:MySQL 8.0 及以上版本支持开窗函数,低于版本不支持。
  开窗函数分为两部分,一部分是函数名称,开窗函数的数量比较少,总共才11个开窗函数+聚合函数(所有聚合函数都可以用作开窗函数),根据函数的性质,有的需要写参数,有的不需要写参数。
  另一部分为over语句,over()语句必须要写的,里面的参数都是非必须参数,可以根据需求有选择的使用。
在这里插入图片描述

函数名(字段) OVER ([PARTITION BY 分组字段] #含义是根据此字段将数据集分为多份[ORDER BY 排序字段] #每个窗口的数据依据此字段进行升序或降序排列[ROWS/RANGE 窗口范围]
)函数名:开窗函数的名称,如 ROW_NUMBER()、RANK()SUM() 等。
OVER:定义窗口的范围和规则。
PARTITION BY:将数据分组,类似于 GROUP BY,但不会合并行。
ORDER BY:指定窗口内的排序规则。
ROWS/RANGE:定义窗口的物理或逻辑范围。
#创建虚拟的业务员销售数据
create table Sales(idate date,iname char(5),sales int)
#向表中插入数据
insert into Sales values('2024-01-01', '张三', 200)-- 插入50行模拟数据
INSERT INTO Sales (idate, iname, sales)
VALUES
('2024-01-01', '张三', 200),
('2024-01-02', '张三', 650),
('2024-01-03', '王五', 200),
('2024-01-04', '赵六', 250),
('2024-01-05', '王五', 300),
......
('2024-02-18', '苏勇', 2500);# 一、查询各月中销售业绩最差的业务员
select * from(
select month(idate),iname,sales,row_number() over(partition by month(idate) order by sales) as sales_order from sales) as t  #易错点:在 SQL 中,所有的派生表必须有一个别名,没有指定别名,MySQL 报错
where sales_order= 1# row_number()、rank()、dense_rank()的区别
select * from(
select month(idate),iname,sales,row_number() over(partition by month(idate) order by sales) as row_order,rank() over(partition by month(idate) order by sales) as rank_order,dense_rank() over(partition by month(idate) order by sales) as dense_order from sales) as t# 连续登录的问题:创建虚拟的用户登录表
create table user_login(user_id varchar(100),login_time datetime);
# 二、查看每位用户连续登录的情况
#1、时间戳格式修改为时间格式
create table user_login_date (
select distinct user_id,date(login_time) login_date
from user_login)# login_date - irank 相等表示连续登录
-- select * from user_login_date#2、对用户登录数据进行排序
create table user_login_data_1 (select *,rank() over(partition by user_id order by login_date) irankfrom user_login_date)-- select * from user_login_data_1# 3、date_sub 从指定的日期减去指定的时间间隔
create table user_login_data_2(
select *,date_sub(login_date,interval irank day) idate from user_login_data_1);-- select * from user_login_data_2
# 4、计算连续登录的用户情况select user_id,min(login_date) as start_date,max(login_date) as end_date,count(login_date) as days
from user_login_data_2
group by user_id,idate#整合代码
select user_id,min(login_date) as start_date,max(login_date) as end_date,count(login_date) as days
from (select *,date_sub(login_date,interval irank day) idate from (select *,rank() over(partition by user_id order by login_date) irankfrom (select distinct user_id,date(login_time) login_date
from user_login) as c) as b) as a 
group by user_id,idate# 三、查看每位用户最大连续登录的天数
select user_id,max(days) from(select user_id,min(login_date) as start_date,max(login_date) as end_date,count(login_date) as days
from (select *,date_sub(login_date,interval irank day) idate from (select *,rank() over(partition by user_id order by login_date) irankfrom (select distinct user_id,date(login_time) login_date
from user_login) as c) as b) as a 
group by user_id,idate) as d
group by user_id# 四、查看在这段时间内连续登录天数>=5天的用户
#方案1:
select distinct user_id from (select user_id,min(login_date) as start_date,max(login_date) as end_date,count(login_date) as days
from (select *,date_sub(login_date,interval irank day) idate from (select *,rank() over(partition by user_id order by login_date) irankfrom (select distinct user_id,date(login_time) login_date
from user_login) as c) as b) as a 
group by user_id,idate
having days >=5) d #方案2:
#lead()函数:静态窗口函数
select *,lead(login_date,4) over (partition by user_id order by login_date ) as idate5
from user_login_date#计算第5次登录与当天的差值
select *,datediff(idate5,login_date)+1 days
from (select *,lead(login_date,4) over (partition by user_id order by login_date ) as idate5
from user_login_date) as a #查找相差天数为5的记录
select distinct user_id from (select *,datediff(idate5,login_date)+1 days
from (select *,lead(login_date,4) over (partition by user_id order by login_date ) as idate5
from user_login_date) as a )as b 
where days = 5

  DATE_SUB 是 SQL 中用于从日期中减去指定时间间隔的函数。它通常用于计算过去某个时间点的日期。以下是 DATE_SUB 函数的详细用法及解释:

DATE_SUB(date, INTERVAL value unit)
# date:要操作的日期或日期时间值。
# INTERVAL:表示时间间隔的关键字。
# value:要减去的时间间隔值,必须是一个整数。
# unit:时间间隔的单位,支持以下值:秒、分钟、小时、天、周、月、季度、年
示例:
SELECT DATE_SUB('2023-10-01', INTERVAL 5 DAY); # 从 2023-10-01 减去 5 天:结果:2023-09-26

  LEAD() 是 SQL 中的一种 窗口函数(Window Function),用于获取当前行之后的某一行数据。它通常用于分析时间序列数据或计算相邻行之间的差异。

LEAD(column_name, offset, default_value) OVER ([PARTITION BY partition_expression][ORDER BY sort_expression]
)
# column_name:需要获取值的列名。
# offset(可选):指定要获取的行数偏移量。默认值为 1,表示获取下一行。
# default_value(可选):如果偏移量超出范围(如最后一行没有下一行),则返回的默认值。如果未指定,默认返回 NULL。
# PARTITION BY(可选):将数据分组,LEAD() 函数会在每个分组内单独计算。
# ORDER BY(可选):指定窗口内的排序规则。

  LEAD() 函数的作用:获取当前行之后的某一行数据;常用于计算相邻行之间的差异,或分析时间序列数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/73534.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Kubernetes】Service 的类型有哪些?ClusterIP、NodePort 和 LoadBalancer 的区别?

在 Kubernetes 中&#xff0c;Service 是一种抽象的方式&#xff0c;用于将一组 Pod 进行连接并暴露给外部或集群内部访问。它的主要目的是通过提供稳定的 IP 地址和端口来允许其他服务或客户端与一组 Pod 进行通信。 Service 类型 Kubernetes 中 Service 有四种主要类型&…

MapReduce处理数据流程

&#xff08;一&#xff09;Shuffle MapReduce中的Shuffle过程指的是在Map方法执行后、Reduce方法执行前对数据进行分区排序的阶段 &#xff08;二&#xff09;处理流程 1. 首先MapReduce会将处理的数据集划分成多个split&#xff0c;split划分是逻辑上进行划分&#xff0c;…

OrioleDB: 新一代PostgreSQL存储引擎

PostgreSQL 12 引入了可插拔式的表存储方法接口&#xff0c;允许为不同的表选择不同的存储机制&#xff0c;例如用于 OLTP 操作的堆表&#xff08;HEAP、默认&#xff09;、用于 OLAP 操作的列式表&#xff08;Citus&#xff09;&#xff0c;以及用于超快速搜索处理的内存表。 …

电脑自动关机故障维修案例分享

电脑基本配置&#xff1a; C P U: AMD A10 9700 内存&#xff1a;8G 硬盘&#xff1a;金邦512G固态硬盘 主板&#xff1a;华硕 A320M-F 显卡&#xff1a;集成&#xff08;核心显卡&#xff09; 操作系统&#xff1a;Win10专业版 故障描述&#xff1a; 使用一段时间会黑屏…

JVM垃圾收集器相关面试题(1)

垃圾收集与内存管理摘要 一.核心垃圾收集算法对比 算法原理优点缺点适用场景标记-清除两次遍历&#xff08;标记存活对象→清除未标记对象&#xff09;实现简单内存碎片化、双遍历效率低老年代&#xff08;结合整理&#xff09;标记-复制内存对半分&#xff0c;存活对象复制到…

栈(LIFO)算法题

1.删除字符串中所有相邻的重复字符 注意&#xff0c;我们需要重复处理&#xff0c;而不是处理一次相邻的相同元素就结束了。对示例来说&#xff0c;如果只进行一次处理&#xff0c;结果为aaca&#xff0c;但是处理之后又出现了相邻的重复元素&#xff0c;我们还得继续处理&…

conda的基本使用及pycharm里设置conda环境

创建conda环境 conda create --name your_env_name python3.8 把your_env_name换成实际的conda环境名称&#xff0c;python后边的根据自己的需要&#xff0c;选择python的版本。 激活conda环境 conda activate your_env_name 安装相关的包、库 conda install package_name …

Python基于深度学习的多模态人脸情绪识别研究与实现

一、系统架构设计 A[数据采集] --> B[预处理模块] B --> C[特征提取] C --> D[多模态融合] D --> E[情绪分类] E --> F[系统部署] F --> G[用户界面] 二、数据准备与处理 1. 数据收集 - 视频数据&#xff1a;FER2013&#xff08;静态图像&#xff0…

synchronized与 Java内置锁(未写完)

文章目录 一、 synchronized 关键字二、Java对象结构1. 对象头2. 对象体3. 对齐字节4. 对象头中的字段长度5. Mark Word 的结构信息6. 使用 JOL 工具查看对象的布局 三、Java 内置锁机制3.1 内置锁的演进过程1. 无锁状态2. 偏向锁状态3. 轻量级锁状态4. 重量级锁状态 一、 sync…

LLM(3): Transformer 架构

Transformer 架构是当前大语言模型的主力架构和基础技术&#xff0c;本文以通俗易懂的方式&#xff0c;对此作简要介绍。 1.4 介绍 Transformer 架构 大多数现代的大规模语言模型&#xff08;LLMs&#xff09;依赖于 Transformer 架构&#xff0c;这是一种在 2017 年的论文《…

11.【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--微服务基础工具与技术--Ocelot 网关--整合日志

网关作为微服务架构的入口&#xff0c;承载着各服务间的请求转发与安全校验&#xff0c;其日志信息尤为关键。通过整合网关日志&#xff0c;可以将分散在不同系统中的访问记录、错误提示和异常信息集中管理&#xff0c;为问题排查提供全景视角。在排查故障时&#xff0c;统一日…

88.HarmonyOS NEXT 性能监控与调试指南:构建高性能应用

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; HarmonyOS NEXT 性能监控与调试指南&#xff1a;构建高性能应用 文章目录 HarmonyOS NEXT 性能监控与调试指南&#xff1a;构建高性能应用1. 性能监…

012---状态机的基本知识

1. 摘要 文章为学习记录。主要介绍状态机概述、状态转移图、状态编码、状态机写法、状态机代码示例。 2. 状态机概述 状态机 &#xff08;Finite State Machine&#xff09;&#xff0c;也称为同步有限状态机&#xff0c;用于描述有先后顺序或时序规律的事情。 “同步”&…

deepseek+kimi做ppt教程记录

1.首先注册deepseek和kimi deepseek官网&#xff1a;https://chat.deepseek.com/ kimi官网&#xff1a;https://kimi.moonshot.cn/ 以下以一篇工作总结报告为例 2.使用deepseek生成ppt大纲 让deepseek生成kimi生成ppt所需要的内容时&#xff0c;需要注意提示词内容&#xff0c;…

Java Module介绍

Java模块系统自Java 9开始引入&#xff0c;旨在提供更强大的封装机制、清晰的依赖关系定义以及可靠的配置。Java平台本身也被模块化了&#xff0c;提供了多个核心模块以及其他用于支持不同功能的模块。以下是一些重要的Java标准模块&#xff1a; java.base - 这是最基础的模块…

SOME/IP:用Python实现协议订阅、Offer、订阅ACK与报文接收

文章目录 前言一、代码层次二、详细代码1. eth_scapy_sd.py2、eth_scapy_someip.py3、network_define.py4、packet_define.py5、unpack_define.py6、someip_controller.py 前言 1、需要pip安装scapy库 2、需要修改根据实际情况配置network_define.py 3、执行someip_controller…

【Linux内核系列】:文件系统收尾以及软硬链接详解

&#x1f525; 本文专栏&#xff1a;Linux &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 世界上只有一种个人英雄主义&#xff0c;那么就是面对生活的种种失败却依然热爱着生活 内容回顾 那么在之前的学习中&#xff0c;我们…

最新版Chrome浏览器加载ActiveX控件技术--allWebPlugin中间件一键部署浏览器扩展

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

基于SpringBoot和MybatisPlus实现通用Controller

基于SpringBoot和MybatisPlus实现通用Controller&#xff0c;只需要创建实体类和mapper接口&#xff0c;单表增删改查接口就已经实现&#xff0c;提升开发效率 1.定义通用controller package com.xian.controller;import cn.hutool.core.map.MapUtil; import com.baomidou.my…

Axure大屏可视化原型模板及素材:数据可视化的高效解决方案

数据可视化已成为企业决策、运营分析、市场洞察的重要工具。数据可视化大屏&#xff0c;作为数据展示和交互的直观平台&#xff0c;能够实时呈现关键数据&#xff0c;帮助企业快速做出决策。Axure作为原型设计领域的领先工具&#xff0c;以其丰富的组件库、强大的交互设计能力和…