MySQL学习笔记
前言
雁过留痕,想要记录自己的学习经历,增强自己的内心底气。本篇记录的内容包含学习过程中的编程刷题练习以及面试考点汇总。
本文中的所有题目都来自牛客sql专项编程练习,部分知识点也有源地址链接提供。内容有点乱,后续有时间会更新。
理论积累——概念选择题
数据库系统包括数据库和数据库管理系统
三级模式两级映射:
-
人们为数据库设计了一个严谨的体系结构,数据库领域公认的标准结构是三级模式结构,它包括外模式、概念模式、内模式,有效地组织、管理数据,提高了数据库的逻辑独立性和物理独立性。用户级对应外模式,概念级对应概念模式,物理级对应内模式,使不同级别的用户对数据库形成不同的视图。
模式改变,外模式和应用程序不变。
数据库设计过程主要包括需求分析、概念结构设计、逻辑结构分析、数据库物理设计、数据库实施、数据库运行和维护阶段。就是没有算法设计。 -
JOIN专题
一图搞懂各种join连接方式:
图片来源点此处
Mysql(版本8.0.25)不支持full join,执行报错full outer join
MySQL中没有full (......) join
感觉我还是没懂这个东西,需要写代码尝试。
-
四种范式
第一范式:数据表中的每个字段不可再分割
第二范式:要求在满足第一范式的基础上,还要满足数据表里的每一条数据记录,都是可唯一标识的,而且所有的非主键字段,都必须完全依赖主键,不能只依赖主键的一部分。
第三范式:第三范式(Third Normal Form,3rd NF)就是指表中的所有数据元素不但要能唯一地被主关键字所标识,而且它们之间还必须相互独立,不存在其他的函数关系。第三范式是在第二范式上的基础上增加条件消除非主属性的传递依赖。
BCNF范式: -
从图中判断系统关系类型
最小关系系统
完备关系系统
-
MySQL语法注意点
- case when的正确语法是: case when … then … when … then … else … end,case和end不能缺少
- where子句不能与聚合函数一起使用。
-
MySQL多表连接、分组统计的方法
-
MySQL中update、modify、alter和insert的区别
-
权限
revoke
grant
drop
remove
withdraw
操作 |
|
---|---|
insert |
|
update |
|
alter |
|
-
事务
数据库事务的四大特性为:
1)原子性
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
2)一致性
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
3) 隔离性
当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
4)持续性
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。 -
触发器
D 触发器(trigger)是SQL server 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作( insert,delete, update)时就会激活它执行。触发器经常用于加强数据的完整性约束和业务规则等。 不会触发触发器的包括 SELECT、TRUNCATE、WRITETEXT、UPDATETEXT。 -
零散知识点
delete不能删除整张表但是drop可以。
这道题问的是元组数目不是执行结果,执行结果答案是2,但是元组数目也就是结果记录显示只有一行
如何分析MySQL的执行效率? -
视图
在视图中可以进行基本的增删改查故AB排除,在视图中也可以定义新的视图,却无法创建表,因为视图是个虚表。
触发器是定义在关系表上的由事件驱动的特殊存储过程。 -
索引
图文并茂的索引详解 索引专题图解
在使用like“%国%”进行查询时,是进行全表扫描的,不会使用索引的,因为索引是遵循最左匹配的原则的
1)主索引是候选索引的特例,能唯一标识一条记录,只能由一个字段组成。一个表只能建立一个主索引。 2)候选索引也能唯一标识一条记录,但不一定只由一个字段组成,可以由两个或两个以上字段组成,一个表可以建立多个候选索引。 3)普通索引就没有任何限制了,不能唯一标识一条记录,可以任意建立,数量不限。建立普通索引的主要目的是为了加快查询速度和建立表之间的联系。 4)唯一索引已经淘汰不用了,它的唯一性是指索引项的唯一而不是字段值的唯一。
一个表只能有一个聚集索引,但是可以有多个非聚集索引
13. 脏读、幻读、不可重复读与四种隔离级别
https://blog.csdn.net/weixin_51201930/article/details/123572289
14.
常见面试问答
1.索引的底层实现:
B树:
B Tree 是平衡查找树,所有叶子节点到根节点的距离相等,节点间使用指针相连。每个节点内的数据按顺序存储,同时为其子节点的划分阈值。
B+树:
B+ Tree是B Tree的变种,其所有数据存储于叶子节点,中间节点只存储指针。
- 相同大小的磁盘页使用B+树能存储更多的节点元素,降低树的高度,使得IO次数更少。
- B+树每次查找都查找到叶子节点,查询性能更稳定。
- B+树所有叶子节点形成有序链表,便于范围查询。B树查找范围时先通过二分查找找到下限,再不断中序遍历找到上限。而B+树先二分查找找到下限,再顺序遍历叶子节点链表即可找到上限。
哈希索引:
哈希索引是基于hash表实现的,hash索引本身只需要存储每个键值的hash码,因此其结构十分紧凑,查询效率也很高(能以O(1)的复杂度进行查找)。结构【键值,hash码,指针】。
哈希索引缺陷:
- hash索引只能等值查找,不能进行范围查找和部分查找。
- 无法用于排序与分组。
- 当大量值的hash码存在冲突时,其效率不一定比B+树高。
- 二次扫描:第一次找到满足hash值得数据,第二次对比键值取出数据。
2.聚簇索引、非聚簇索引(辅助索引):
聚簇索引:
• 索引和数据存放在一起,索引结构的叶子节点保存了行数据。
• 索引顺序与物理顺序相同,更适合between and和order by操作;
• 每张表只能有一个聚集索引;
• [InnoDB使用聚簇索引]
非聚簇索引:
• 索引和数据分开,索引结构的叶子节点指向数据。
• 索引顺序与物理顺序无关;
• 每新建一个索引就会建立一个非聚集索引,因此大量建立索引需要更多的资源和开销,并影响insert和update性能;
• [MyISAM使用非聚簇索引]
3.关系模型的三类完整性约束:
- 实体完整性(主键):每个元组都是唯一可标识的;
- 参照完整性(外键):将有关联的表使用外键联系起来,保证修改一个表中的数据时,对应的另一个表中数据及时更新。
- 用户定义完整性:又叫域完整性或语义完整性,指明关系中属性的取值范围,防止属性的值与应用定义矛盾。
4.一致性哈希:
一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,一致性Hash算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。
5.Redis:
Redis: 基于内存的高性能key-value数据库。
优点:
• 速度快:基于内存;
• 支持事务:处理都是原子性的;
• 支持丰富的数据类型:string,list,set等;
• 丰富的特性:可用于缓存、消息、按key设置过期时间。
为什么快:
• 基于内存:数据存在内存中,绝大部分的请求都是内存操作,速度很快;
• 单进程单线程:避免了进程线程的竞争和进程切换带来的开销,也不必考虑锁的问题;
• IO多路复用:使得单个线程可以处理多个接口的请求。
6.ACID:
• 原子性(atomicity):事务被视为不可分割的最小单元,事务中的操作要么全部成功提交,要么失败回滚。反向执行回滚日志中的操作可实现回滚;
• 一致性(consistency):数据库在事务执行前后都保持一致性状态,在一致性状态下,所有事务对同一数据的访问结果是相同的;
• 隔离性(isolation):事务提交前,其所做的修改对其他事务不可见;
• 持久性(durable):事务提交后,其所做的修改会永久保存到数据库中,即使数据库发生崩溃也不会失效。
7. 并发一致性问题:
• 丢失修改:两个事务同时修改一个数据,后修改的结果覆盖了前一个修改的结果。
• 读脏数据:事务1修改了数据后事务2读取数据,但紧接着事务1撤回了修改,事务2读取的数据就是脏数据。
• 不可重复读:事务1多次读取同一个数据,在事务1执行过程中,事务2修改数据并提交,之后事务1读取的数据和之前的结果不同。
• 幻影读:事务1读取一个范围数据,事务2在其中插入数据后,事务1再次读取范围数据和之前不同。
并发一致性问题主要是破坏了事务的隔离性,解决方法是保证事务的隔离性。可以通过封锁来实现隔离性,但是封锁需要用户自己控制,相当复杂。数据库管理系统提供了不同的隔离级别,可以更方便地管理。
8. 隔离级别:这道题答案有误
事务隔离级别的具体说明
• 未提交读:允许一个事务读取另外一个事务没有提交的数据;
• 提交读:一个事务只能读取另外一个事务已经提交的数据;
• 可重复读:保证同一个事务中对同一个数据的读取结果是一致的;【MySQL的默认隔离级别】,目标是克服读写提交中出现的不可重复读的现象,但是会导致幻读的现象。
• 可串行化:强制事务串行执行,事务间就可以相互不影响。需要加锁保证同一时间只有一个事务执行。是数据库最高的隔离级别,它要求所有的sql都按顺序执行,这样就克服了上述隔离级别出现的各种问题,所以他能够完全保证数据的一致性。
9. 视图:
视图是虚拟的表,不包含数据,只包含动态检索数据的查询(即SQL查询语句)。
使用场景:
• 重用SQL语句;
• 简化SQL操作,不必知道包含的基本查询的细节;
• 使用表的组成部分而不是整个表;
• 保护数据,可以给用户授权表的部分访问权限而非全部;
• 更改数据和表示:返回与底层表示和格式不同的数据;
规则和限制:
• 命名唯一;
• 数量没有限制,可以嵌套(从视图创建新视图);
• 不能索引,也不能有关联的触发器和默认值;
• 可以和表一起使用。
10. InnoDB与MyISAM比较:
- 事务:InnoDB是事务性的,可以有Commit和RollBack操作;
- 并发:MyISAM只支持表级锁,InnoDB还支持行级锁;
- 外键:InnoDB支持外键;
- 备份:InnoDB支持在线热备份(系统运行时备份);
- 崩溃恢复:MyISAM更容易崩溃,且修复很慢;
- 其他特性:MyISAM支持表压缩和空间数据索引。
- MyISAM适合只读数据或表较小、可以容忍修复操作的场景。InnoDB适合大数据量的情况,故障可RollBack。
11. InnoDB 4大特性:
1. 插入缓冲:
a. 要求:非聚簇索引,索引不唯一;
b. 插入前先检查是否在缓冲区,若是则直接插入,否则先放入insert buffer对象中。再以一定的频率进行insert buffer和非聚簇索引的子节点进行合并,可以将多个处于同一索引页的插入合并到一个操作中,大大提高了非聚簇索引的插入性能,减少了随机IO带来的性能损耗。
2. 二次写:二次写缓存是位于系统表空间的存储,用来缓存从缓冲池到数据文件中的数据页,当数据库宕机时可以从中找到备份进行恢复;
3. 自适应哈希:经常访问的索引会被自动生成到哈希索引中去,通过缓冲池的B+树构造而来,建立速度很快。
4. 预读:(extent,page两种单位)
a. 线性预读:将下一个extent读入buffer;
b. 随机预读:将同一extent中的剩余page读入buffer。
12. 范式(解决增删改异常)
- 第一范式:属性不可分;
- 第二范式:所有非主属性依赖于主键;
- 第三范式:所有非主属性不传递函数依赖于主键。
13. 数据库优化:
结构优化:
• 分解字段很多的表:有些字段使用频率低;
• 增加中间表:经常需要联合查询的表建立中间表,将联合查询改为对中间表的查询;
• 为频繁使用和查询的字段建立索引;
• 尽可能使用not null,给空字段定义默认值;
SQL语句优化:
• 避免使用select *,将需要查询的字段列出来;
• 使用连接(join)代替子查询;
• 使用limit对查询结果进行限定;
• 避免在where子句中进行null判断,使用or和(!=, <>),否则数据库会放弃索引进行全表扫描。
14. Union 和 Union all 的区别:
• 重复数据:Union会去掉重复值,Union all不会;
• 顺序:Union按照字段排序结果,Union all不会;
• 效率:Union all比Union快很多。
15. MySQL索引:
- 唯一索引:索引列的所有值必须唯一,可以为空;
- 主键索引:是一种唯一索引,一张表只能有一个主键索引,且不能为空;
- 普通索引:基本索引类型,没有唯一性限制,可以为空;
- 全文索引:针对文件、文本的检索,MyISAM和高版本InnoDB支持;fulltext索引配合match against操作检车或过滤文本中的关键字,而不是直接与索引中的值相比较。
- 组合索引:一个索引中包含多个列。只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合。
16. 存储过程:
- 存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。
- 存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字- 并给定参数(需要时)来调用执行。
- 存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。
触发器是一种特殊类型的存储过程,主要是通过事件进行触发而被执行的,而存储过程可以通过存储过程名字而被直接调用。当对某一表进行诸如Update、 Insert、 Delete 这些操作时,SQL Server就会自动执行触发器所定义的SQL 语句,从而确保对数据的处理必须符合由这些SQL 语句所定义的规则。
17. 联结JOIN:
- CROSS JOIN:返回笛卡尔积;
- INNER JOIN在CROSS JOIN的基础上筛选不符合条件的数据;
- 自然联结在普通的INNER JOIN的基础上删除了重复列。
牛客编程–非技术快速入门篇:
提示:这里可以添加要学的内容
- 限制查询返回的行数
select device_id from user_profile limit 2
- 对列进行重新命名
select device_id as user_infors_example from user_profile limit 2
- 多个并列条件
case 1:
select device_id, gender, age, university, gpa
from user_profile
# where university=('北京大学' or '复旦大学' or '山东大学') 这是错误的
where university in ('北京大学','复旦大学','山东大学')
#多个同类条件表达形式
#主要考察 where in 和 where not in 的用法
case2:
select device_id, gender, age, university, gpa
from user_profile
where (university='山东大学' and gpa>3.5)
or (university='复旦大学' and gpa>3.8)
- 字符匹配
一般形式为:
列名 [NOT ] LIKE
匹配串中可包含如下四种通配符:
_:匹配任意一个字符;
%:匹配0个或多个字符;
[ ]:匹配[ ]中的任意一个字符(若要比较的字符是连续的,则可以用连字符“-”表 达 );
[^ ]:不匹配[ ]中的任意一个字符。
select device_id, age, university from user_profile
where university like '%北京%'
- 计算男生人数以及平均GPA
#注意看题目要求,以及按要求查询到的结果的各方面与原表格之间是否有差别
#题目文字没有说明的要求要自己多加观察
# select count*, ave(gpa) from user_profile where gender='male'这个运行结果是错误的
select
count(gender) as male_num,
round(avg(gpa),1) as avg_age
from user_profile
where gender='male'
# 表头重命名,用as语法
#浮点数的平均值可能小数点位数很多,按照示例保存一位小数,用round函数
- 题目:题目:现在运营想查看每个学校用户的平均发贴和回帖情况,寻找低活跃度学校进行重点运营,请取出平均发贴数低于5的学校或平均回帖数小于20的学校。
select
university,
avg(question_cnt) as avg_question_cnt,
avg(answer_cnt) as avg_answer_cnt
from user_profile
group by university
having avg_question_cnt<5 or avg_answer_cnt<20
- 题目:现在运营想要查看不同大学的用户平均发帖情况,并期望结果按照平均发帖情况进行升序排列,请你取出相应数据。
select
university,
avg(question_cnt) as avg_question_cnt
from user_profile
group by university
order by avg_question_cnt#默认是升序
- 题目:现在运营想要查看所有来自浙江大学的用户题目回答明细情况,请你取出相应数据
select
user_profile.device_id,
question_practice_detail.question_id,
question_practice_detail.result
from question_practice_detail as qpd
inner join user_profile as ap
on up.device_id=qpd.device_id and up.university='浙江大学'
order by question_id
- 题目:运营想要了解每个学校答过题的用户平均答题数量情况,请你取出数据。
select
university,
# avg(question_id) as avg_answer_cnt这样是计算不出来的
count(question_id)/count(distinct qpd.device_id) as avg_answer_cnt
from user_profile as up
inner join question_practice_detail as qpd
on up.device_id=qpd.device_id
group by up.university
- 题目:计算每个学校用户不同难度下的用户平均答题题目数
#运营想要计算一些参加了答题的不同学校、不同难度的用户平均答题量,请你写SQL取出相应数据
#查询结果 university difficult_level avg_answer_cnt
select
university,
difficult_level,
round(count(qpd.question_id)/count(distinct qpd.device_id), 4) as avg_answer_cnt
from question_practice_detail as qpd
left join user_profile as up
on up.device_id=qpd.device_id
left join question_detail as qd
on qd.question_id=qpd.question_id
group by university, difficult_level
- 题目:展现山东大学用户在不同难度下的平均答题题目数,并给出相应数据
#case 1
select
university,
difficult_level,
count(qpd.question_id)/count(distinct qpd.device_id) as avg_answer_cnt
from question_practice_detail as qpd
inner join user_profile as up
on up.device_id=qpd.device_id and up.university='山东大学'
inner join question_detail as qd
on qpd.question_id=qd.question_id
group by difficult_level
#case 2
select
up.university,
difficult_level,
count(qpd.question_id)/count(distinct qpd.device_id) as avg_answer_cnt
from
user_profile as up,
question_practice_detail as qpd,
question_detail as qd
where
up.university='山东大学'
and up.device_id=qpd.device_id
and qpd.question_id=qd.question_id
group by
qd.difficult_level
- 题目:现在运营想要分别查看学校为山东大学或者性别为男性的用户的device_id、gender、age和gpa数据,请取出相应结果,结果不去重。你的查询应返回以下结果(注意输出的顺序,先输出学校为山东大学再输出性别为男生的信息)
select
device_id, gender, age, gpa
from user_profile
where
university='山东大学'
union all
select
device_id, gender, age, gpa
from user_profile
where
gender='male'
# union 合并两个或多个 SELECT 语句的结果集,不包括重复行,同时进行默认规则的排序
# unionAll 对两个结果集进行并集操作,包括重复行,不进行排序
- 题目:多分支函数的使用
#case 1
SELECT
CASE
WHEN GRADE BETWEEN 85 AND 100 THEN '优'
WHEN GRADE BETWEEN 70 AND 84 THEN '良'
WHEN GRADE BETWEEN 60 AND 69 THEN '及格'
ELSE '不及格'
END 等级, COUNT(*) 人数
FROM SC
GROUP BY
CASE
WHEN GRADE BETWEEN 85 AND 100 THEN '优'
WHEN GRADE BETWEEN 70 AND 84 THEN '良'
WHEN GRADE BETWEEN 60 AND 69 THEN '及格'
ELSE '不及格'
END
#case2
select
case
when age<25 or age is null then '25岁以下'
when age>=25 then '25岁及以上'
end as age_cut,#不加as也可以
count(*) as number#不加as也能编译通过 符合题目的格式要求
from user_profile
group by age_cut
#case3
select
device_id, gender,
case
when age<20 then '20岁以下'
when age>=20 and age<=24 then '20-24岁'
when age>=25 then '25岁及以上'
else '其他'
end as age_cut
from user_profile
- 题目:计算用户8月每天的练题数量
思路:
限制条件:计算每天的题目数量,group by(时间--->2021年8月)
显示栏目名需令其别名
group by的使用场景?
select
day(date) as day,
count(question_id) as question_cnt
from question_practice_detail
where month(date)=8 and year(date)=2021
group by date
- 题目SQL29:计算用户的平均次日留存率
现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。
这道题有点难┗|`O′|┛ 嗷~~
思路:
限制条件:第二天还会来刷题
隐藏内容:
同一用户今天刷题,第二天还刷题
不关心用户一天刷了几道题,只关心用户是否刷题
关键动词:
1)去重
2)sql函数的积累
3)表示今天刷题且明天也刷题
难点:将动作转化为sql语言的逻辑习惯
select
count(q2.device_id)/count(q1.device_id) as avg_ret
from
(select distinct device_id, date from question_practice_detail) as q1
left join
(select distinct device_id, date from question_practice_detail) as q2
on q1.device_id=q2.device_id and q2.date=date_add(q1.date, interval 1 day)
- 题目:现在运营举办了一场比赛,收到了一些参赛申请,表数据记录形式如下所示,现在运营想要统计每个性别的用户分别有多少参赛者,请取出相应结果
难点:该题目给出的列表比较特殊,栏目列表中的内容不止一段
重点:字符串截取函数substring_index([列表名],‘隔开各字符段的符号’,K ),K>0时表示从左边数第K个间隔符前面的内容,K<0表示从右边数第K个间隔符以后的内容。
select
substring_index(profile,',',-1) as gender,
count(device_id) as number
from user_submit
group by gender
练习题1:对于申请参与比赛的用户,blog_url字段中url字符后的字符串为用户个人博客的用户名,现在运营想要把用户的个人博客用户字段提取出单独记录为一个新的字段,请取出所需数据。
select
device_id,
substring_index(blog_url,'/',-1)
from user_submit
练习题2:SQL32 截取出年龄
select
substring_index(substring_index(profile,',',-2),',',1) as age,
count(device_id) as number
from user_submit
group by age
- 题目:现在运营想要找到每个学校gpa最低的同学来做调研,请你取出每个学校的最低gpa。根据示例,你的查询结果应参考以下格式,输出结果按university升序排序。
select
a.device_id,
a.university,
a.gpa
from user_profile a
right join
(
select university, min(gpa) as gpa
from user_profile
group by university
) as b
on a.university=b.university and a.gpa=b.gpa
order by university
#case2
select device_id,university,gpa
from user_profile
where (university,gpa) in (select university,min(gpa) from user_profile group by university)
order by university
- 题目:浙大不同难度题目的正确率
现在运营想要了解浙江大学的用户在不同难度题目下答题的正确率情况,请取出相应数据,并按照准确率升序输出。
select difficult_level,
avg(if(qpd.result='right', 1, 0)) as correct_rate#简洁用法,记住
# sum(if(qpd.result='right', 1, 0)) / count(qpd.question_id) as correct_rate
# count(if(qpd.result='right', 1, null)) / count(qpd.question_id) as correct_rate
from user_profile as up
inner join question_practice_detail as qpd
on up.device_id = qpd.device_id
inner join question_detail as qd
on qd.question_id = qpd.question_id
where up.university = '浙江大学'
group by qd.difficult_level
order by correct_rate asc;
- 题目:现在运营想要取出用户信息表中对应的数据,并先按照gpa、年龄降序排序输出,请取出相应数据。
知识点补充:
限定条件:2021年8月份,匹配date字段即可,匹配方法主要有三种:
(1)like语法:date like “2021-08%”
(2)year、month函数:year(date)=‘2021’ and month(date)=‘08’;
(3)date_format函数:date_format(date, ‘%Y-%m’)=‘2021-08’;
2:总用户数:count函数计数,因为用户有重复,所以需要distinct去重,即count(distinct device_id)
3:总次数:count(question_id)即可
select device_id, gpa, age
from user_profile
# order by gpa,age desc#这种写法是错误的
order by gpa desc,age desc
- 题目:现在运营想要了解2021年8月份所有练习过题目的总用户数和练习过题目的总次数,请取出相应结果。
select count(distinct device_id) as did_cnt, count(question_id) as question_cnt
#不加distinct 是不会给用户去重的,count本身不具备去重功能
from question_practice_detail
#group by date_format(date,'%Y%m')='202108'#没有真正理解group by的含义,聚合函数是用来分组归类的,不是用来找条件的
where date_format(date,'%Y%m')='202108'
- 题目:现在运营想要找到每个学校gpa最低的同学来做调研,请你取出每个学校的最低gpa。
方案一
select device_id, university, gpa
from user_profile
where gpa in
(
select min(gpa) as gpa
from user_profile
group by university
)
order by university #按照A-Z的顺序排序算作升序排序
方案二
select device_id,university,gpa
from user_profile
where (university,gpa) in (select university,min(gpa) from user_profile group by university)
order by university
牛客编程–SQL必知必会:
面试问答:
提示:这里可以添加计划学习的时间
在面试某上海上市金融科技公司中曾被问到的一个问题是:
你在项目中你用过分组函数吗?
我:用过(必须展现实力)
那你听清楚我下面这个问题,分组SQL语句中,select和from和where和group by 和 having 这几部分的执行顺序是怎么样的?
我:先是from,再到 where ,再到select,再到group by ,最后having。
补充:
1.sql语句的执行过程是:from–>where–>group by -->having --> select— >order by;
2.where是对表中的内容进行查询筛选,从而获得查询结果,having是对表的查询结果进行再次筛选,获得select的呈现结果
你能说说为什么是这样子的吗?
我:因为首先肯定是要确定数据从哪张表来,然后按where条件查询出结果,再然后才能进行group by分组(分组条件可以有多个,按字段顺序依次分组),最后是由having对分组后的结果集进行过滤。
例如:
- 周一至周五晚上 7 点—晚上9点
- 周六上午 9 点-上午 11 点
- 周日下午 3 点-下午 6 点
学习产出:
提示:这里统计学习计划的总量
例如:
- 技术笔记 2 遍
- CSDN 技术博客 3 篇
- 习的 vlog 视频 1 个