MySQL

MySQL基本语句

(2条消息) Mysql 最最最基本语句(大全)mysql数据库基础知识一个笨小孩哎呀的博客-CSDN博客

(2条消息) MySQL增删改查(基础)_朱wwww的博客-CSDN博客

MySQL中添加字段

1
alter table car_evidence add `unit_name` varchar(64) comment '单位'

MySQL中修改字段

1
2
3
ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 [属性];
alter table user MODIFY new1 VARCHAR(10);  #修改一个字段的类型
alter table user CHANGE new1 new4 int;  #修改一个字段的名称,此时一定要重新指定该字段的类型

MySQL中删除字段

1
2
alter table 表名 drop column `unit_name`; 
truncate table tb_user #清空表中的数据

case when 语句

1
2
3
4
select name,case when (age > 60) then "老同学"
when (age > 20 ) then "年轻" #从此处以及排除了年龄大于60的选项
else "小同学" end as age_level from student
order by name asc;

if、ifnull的用法

1
2
3
4
5
IF(expr1 , expr2 , expr3);
-- expr1的值为TRUE,则返回值为expr2;expr1的值为FALSE,则返回值为expr3

IFNULL(expr1 , expr2);
-- 判断第一个参数expr1是否为NULL;如果expr1不为空,直接返回expr1;如果expr1为空,返回第二个参数expr2

MySQL连表查询的问题:

对于关联查询,以左关联为例,连接的条件是id,若右表的关联id为空,左表的id不为空,且左表的id为查询条件,仍能够查询 出左表需要的数据:

1
2
3
4
5
6
7
8
select 
b.content as content
,h.address as address
from
tb_blog b left join tb_hotel h
on b.id = h.id
where b.id = 4
---此处h.id = 4 不存在

MySQL日期相关函数

1
2
3
4
5
DATE(datatime) ---从精确到秒的日期格式中提取出年月日
DATE_FORMATE(yourdatetime,'%Y-%m-%d') ---指定返回的日期格式为年月日

SELECT FROM_UNIXTIME(1633022400) AS 'Formatted Date'; --将以秒为单位时间戳转化为具体日期
SELECT FROM_UNIXTIME(send_time/1000) AS 'Formatted Date';--将以毫秒为单位时间戳转化为具体日期

GPT回答:

MySQL 中用于处理日期的函数有很多,下面是一些比较常用的函数及示例:

  1. CURDATE()
    功能:返回当前日期,去掉时间部分。
    示例:

    1
    SELECT CURDATE();  -- 返回 2021-12-19
  2. CURRENT_DATE()
    功能:也返回当前日期,去掉时间部分,与 CURDATE() 的作用相同。
    示例:

    1
    SELECT CURRENT_DATE();  -- 返回 2021-12-19
  3. NOW()
    功能:返回当前日期和时间。
    示例:

    1
    SELECT NOW();  -- 返回 2021-12-19 08:34:17
  4. DATE_FORMAT(date,format)
    功能:对日期进行格式化处理,返回一个指定格式的字符串。
    示例:

    1
    SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');  -- 返回 2021-12-19 08:34:17
  5. DATE_ADD(date, INTERVAL value unit)
    功能:给指定的日期添加一个时间间隔。
    示例:

    1
    SELECT DATE_ADD('2021-12-19', INTERVAL 1 DAY);  -- 返回 2021-12-20
  6. DATE_SUB(date, INTERVAL value unit)
    功能:从指定的日期中减去一个时间间隔。
    示例:

    1
    SELECT DATE_SUB('2021-12-19', INTERVAL 1 MONTH);  -- 返回 2021-11-19
  7. DATEDIFF(date1, date2)
    功能:计算两个日期之间的天数差。
    示例:

    1
    SELECT DATEDIFF('2021-12-19', '2021-11-19');  -- 返回 30
  8. YEAR(date)、MONTH(date)、DAY(date)
    功能:分别返回指定日期的年份、月份、日期。
    示例:

    1
    SELECT YEAR('2021-12-19'), MONTH('2021-12-19'), DAY('2021-12-19');  -- 返回 2021, 12, 19

更多 MySQL 日期函数的介绍及使用可以参考 MySQL 官方文档:Date and Time Functions

Mysql中的字段拼装及换行

1
2
3
4
5
6
select 
CONCAT(sender ,":" ,content,'\n') AS content,
FROM_UNIXTIME(send_time/1000) AS 'Formatted Date'
from learning.content_test
where room_id =1
order by send_time

通过GROUP_CONCAT()函数,可以将某个分组下的指定字段进行拼接,整合成一个字段

1
2
3
4
5
select
GROUP_CONCAT(CONCAT(sender,':',content) SEPARATOR '|||') as content,
room_id
from learning.content_test
GROUP BY room_id

MySQL去重

mysql去重之distinct

​ distinct只能放在查询的最前面,且会根据查询的所有字段去重,如查询字段为A、B、C 那么只有当A、B、C完全相同时才会 选择一条,单单只是A、B相同不会进行去重;

mysql去重之group by

​ 使用group by能够弥补distinct的不足,可以根据group by后面的字段进行去重,即group by后面是A、B,查询的字段是A、B、C,则只要A、B相同就会去重

MySQL类型转换及对索引的影响

​ Mysql在where查询条件中会自动对数据类型进行转化,但是这个转化涉及到的性能消耗还是比较高的,当然,在mybatis中也会自动对传入的参数进行转化(我好像没有看到他转化),从而减小mysql参数转换的消耗,那么Mybatis是如何进行参数转换的呢?待学习

​ 特别注意,在MySQL进行隐式转换时,有可能会导致索引失效,这个在写代码时一定要考虑到!

MySQL连接语句及查询条件

sql语句的执行顺序:sql语句执行顺序并不是顺序的,而是按以下顺序进行:from —》where—》group by—》聚合函数—》having—》select—》order by

关于join on 后面所跟的查询条件,在只是内关联查询时是相同的,即A join B on 条件1 and 条件2 and 条件3 与A join B on 条件1 where 条件2 and 条件 3的效果是相同的。

但是在left join 与right join 时,条件在on后面与在where后面是不同的,因为在on后面,则不论条件是否成立,主表的数据一定能够查询到,而在where后面,两张表中不满足条件的数据都不会被查到。

如下sql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
select 
e.salary as salary,
e.`name` as `name`,
d.name as departmentName
FROM employee e left join department d
on e.departmentId = d.id
and e.salary <80000
结果:
salary name departmentName
85000 Joe
80000 Henry
60000 Sam Sales
90000 Max
69000 Janet IT
85000 Randy
70000 Will IT

select
e.salary as salary,
e.`name` as `name`,
d.name as departmentName
FROM employee e left join department d
on e.departmentId = d.id
where e.salary <80000

结果:
salary name departmentName
60000 Sam Sales
69000 Janet IT
70000 Will IT
所以在左关联或右关联中,对于主表限制的条件一定要放在where中

MYSQL常见报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'learning.content_test.send_time' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

参考文档:https://blog.csdn.net/ss810540895/article/details/127485417

--select 查询中包含了group by 以外的字段
--若group by和order by同时存在时,group by中有的字段,order by中也要有
对于这类问题,有一个方法是通过聚合函数来解决,同时在使用聚合函数时,必须要有group by语句

SELECT room_id,
GROUP_CONCAT(CONCAT(sender, ':', content) SEPARATOR '|||') AS content
FROM learning.content_test
GROUP BY room_id
ORDER BY MIN(send_time);


--为什么有group by 放在order by后面会报错?
一般情况下,先group byorder by是在分好的组中根据所给字段进行排序,反之则先总体排序在进行分组,目前来看二者的最终效果是一样的;但是我在高版本中进行分组和排序时,分组必须在排序前

--only_full_group_by模式的必要性?
该模式满足SQL92的标准,可以防止语义不明确

参考文档:http://www.ywnds.com/?p=8184



子查询

列子查询

子查询返回的结果是一列多行

1
select * from emp where salary > all ( select salary fron emp where dept_id = (select id fron dept mhere nane=‘财务部')》));

列子查询一般用到: in,比较符号,all 等

行子查询

子查询返回的结果是一行多列

1
select * from emp where (salary , managepid)=(select salary,managerid from emp where nane =‘张无忌 );

表子查询

子查询返回的结果是一张表

1
2
3
select e.*,d.* from (select * from emp where entrydate > '2806-81-01') e 
left join dept d
on e.dept_id : d.id ;
在SELECT中使用聚合函数的列需要,该列的字段需要进行聚合,或group by 或 count()

多表连接查询:inner join(自然连接,只加载符合查询结果的值,不会有空值) 与outer join(一般是left join 与right join,outer可以省略,left join即保留左边那个表的全部,右边可能有空值)

开窗函数

开窗函数的格式:SUM(计算字段名) OVER (PARTITION BY 分组字段名)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#假设有一个学生表 student,包含以下字段:id(学号)、name(姓名)、age(年龄)、score(分数)、class_id(班级编号)。请你编写一个 SQL 查询,返回每个学生的详细信息(字段顺序和原始表的字段顺序一致),并计算每个班级的学生平均分(class_avg_score)
select id,name,age,score,class_id,
avg(score) over (partition by class_id) class_avg_score
from student;

#实现同组内数据的 累加求和
SUM(计算字段名) OVER (PARTITION BY 分组字段名 ORDER BY 排序字段 排序规则)

#Rank 开窗函数的语法如下:
RANK() OVER (
PARTITION BY 列名1, 列名2, ... -- 可选,用于指定分组列
ORDER BY 列名3 [ASC|DESC], 列名4 [ASC|DESC], ... -- 用于指定排序列及排序方式
) AS rank_column

select id,name,age,score,class_id
,rank() over (partition by class_id order by score desc) ranking
from student


#Row_Number 开窗函数的语法如下(几乎和 Rank 函数一模一样)
ROW_NUMBER() OVER (
PARTITION BY column1, column2, ... -- 可选,用于指定分组列
ORDER BY column3 [ASC|DESC], column4 [ASC|DESC], ... -- 用于指定排序列及排序方式
) AS row_number_column


#Lag 函数用于获取 当前行之前 的某一列的值。它可以帮助我们查看上一行的数据。
LAG(column_name, offset, default_value) OVER (PARTITION BY partition_column ORDER BY sort_column)
#Lead 函数用于获取 当前行之后 的某一列的值。它可以帮助我们查看下一行的数据。
LEAD(column_name, offset, default_value) OVER (PARTITION BY partition_column ORDER BY sort_column)


#请你编写一个 SQL 查询,返回每个学生的详细信息(字段顺序和原始表的字段顺序一致),并且按照分数降序的方式获取每个班级内的学生的前一名学生姓名(prev_name)、后一名学生姓名(next_name)
select id,name,age,score,class_id,
lag(name,1,null) over(partition by class_id order by score desc ) prev_name,
lead(name,1,null) over(partition by class_id order by score desc ) next_name
from student;

MySQL默认的隔离级别

(29条消息) mysql四类隔离级别mysql默认事务隔离级别和光同尘ss的博客-CSDN博客

四类隔离级别:

image-20230320085433707

image-20230320085507610

image-20230320085527675

image-20230320085559518

存储引擎

存储引擎是作用到表上的

查看存储引擎

1
show engines;

image-20230301094904527

InnoDB特性

  1. 事务控制(需要提交事务才能够完成事务)
  2. 支持外键约束
  3. 一般是聚合索引

image-20230301095553061

存储方式:

image-20230301095907479

image-20230301101407188

数据库锁

全局锁:对整个数据库实例加锁,后续的DML、DDL语句以及更新事务的提交都将会被阻塞。一般用于全库的逻辑备份。(保证备份数据的一致性)

使用方式:

1
2
3
flush tables  with read lock;
mysqldump -uroot -p12345678 heima>D:/heima.sql--这一行不是在mysql命令行中执行的,直接在cmd命令窗口执行即可
unlock tables;

不加全局锁的一致性备份方式:

1
mysqldump -single-transaction -uroot -p12345678 heima>D:/heima.sql

表级锁:

  • 表锁
    • 表共享读锁 read (其他客户端包括自己都不能修改表中的内容,会被阻塞,但是能够读取数据)
    • 表独占写锁 write(其他客户端都不能修改表中的内容,会被阻塞,也不能读取数据;当前客户端可以做所有操作)
    • 加锁方式 :lock table ‘表名’ read/write
    • 释放锁:unlock tables
  • 元数据锁(MDL)
    • 该锁的存在是为了避免DML语句与DDL语句的冲突,在表中存在事务时,不可对元数据(表结构)进行操作
    • 当对表进行增删改查时会自动加上MDL读锁,对表结构进行更改时,会自动加上MDL写锁
  • 意向锁
    • 为了解决在执行DML语句时,其他线程要对该表进行加锁,避免行锁与表锁之间的冲突,通过意向锁来减少表锁的检查。当线程A执行DML语句(如update)时,会在加上行锁的同时加一把意向锁。此时线程B加表锁时会先去判断是否被意向锁所兼容,若不兼容则阻塞
    • 意向共享锁(IS);由语句 select … lock in share mode 添加 与表锁排他锁互斥
    • 意向排他锁(IX);由语句 inseet\delete\update\select … for update 添加

行级锁:

进行行锁测试时要开启事务来进行测试

注意:InnoDB的行锁是针对于索引加的锁,不通过索引条件检索数据,InnoDB会对表中所有记录加锁,升级为表锁。

  • 行锁
    • 共享锁(S):允许一个事务读一行,阻止其他事务获取排他锁;(其他事务可以读)
    • 排他锁(X):允许获取排他锁的事务更新数据,组织其他事务获取相同数据集的共享锁、排他锁(其他事务啥也不能做)
  • 间隙锁
    • 间隙锁的唯一目的就是防止其他事务插入间隙,间隙锁可以共存,一个事务采用间隙锁,不会阻止其他事务在同一间隙上采用间隙锁
  • 临键锁
    • 索引上的等值查询给不存在的记录加锁时优化为间隙查询

按性质主要分为悲观锁和乐观锁

  1. 乐观锁(Optimistic Locking):
    • 乐观锁是一种不直接锁定数据的机制,它假设不会有并发冲突,只有在提交事务时才会检查是否有冲突,如果有则进行回滚或重试。
    • 示例:假设某个表中的一列表示库存数量,事务A读取该列并更新库存数量,然后提交事务。在提交时,事务A会检查库存数量是否发生变化,如果无变化则提交成功,否则回滚或重试。
  2. 悲观锁(Pessimistic Locking):
    • 悲观锁是一种在操作数据时直接锁定数据的机制,即使没有并发冲突也会锁住数据,这样其他事务无法对数据进行操作。
    • 示例:假设某个表中的一列表示库存数量,事务A读取该列并锁定数据,然后执行更新与提交事务。在事务A提交之前,其他事务无法读取或更新该列。

​ 行锁和页锁适用于并发度高、冲突少的情况;表锁适用于并发性较低的情况;乐观锁适用于并发度高、冲突少、读多写少的情况;悲观锁适用于并发度高、冲突多、写多读少的情况。

索引

​ 索引是一种帮助我们更快查找到数据的方法,索引的基本语法:创建、修改、删除、查询,索引生效的前提是要有序

​ 索引分为一级索引和二级索引,一级索引含有一条记录的全部数据,二级索引含有一级索引的index,同时二级索引也是引起回表的原因

索引分类:

1.普通索引(normal index):最基本的索引类型,没有任何限制。

2.唯一索引(unique index):与普通索引类似,但是列中的值必须唯一。

3.全文索引(full-text index):只能用于myisam表,用于全文搜索。

4.主键索引(primary key index):特殊的唯一索引,用于标识表中每行数据的唯一性。

5.联合索引(composite index):将多个列组合成一个索引,可以提高查询效率。

6.空间索引(spatial index):特殊的索引类型,用于处理包含空间数据类型的列。

image-20230301092319417

索引结构

image-20230301092634917

image-20230301092827166

B+树

索引的底层结构是B+树,若一个表未创建主键索引,也会创建B+树(将rowid做为主键索引)

image-20230708093837384

Hash索引

Hash索引一般只用于等值比较,查询的效率是非常高的,但是不适用于范围查询也不支持排序。

补充HashMap的底层原理,来更容易理解Hash

map的底层数据结构!!(通过散列key来存储键值对)

1、key通过运算得到一个值,通过这个值将key-value键值对存入该值对应的位置

2、hashmap处理重复元素的方法是通过新的value来覆盖旧的value

image-20230307164006238

image-20230307165040999

聚合索引和非聚合索引

所有非主键索引都可以称之为二级索引

image-20230308181834819

回表

image-20230708100221842

索引覆盖

减少了回表的一些情况

image-20230308143103583

image-20230708100437196

ps:联合索引查询时,若是多个字段用and连接,那么只要存在最左字段,其位置在哪都可以,因为mysql会在查询时帮我们进行优化,但是最好还是我们自己把该字段写在最左边!

索引下推(ICP)

对于二级索引的优化,减少范围查询时的回表次数

即根据二级索引查找到数据后一次性全部回表,不在一次一次的回表(如何一次性全部回表呢?)

索引设计原则

image-20230301094006831

最左前缀原则就是为了使联合索引能够生效,即在查询时一定要将所创建的联合索引最左边的那个字段包含,且在最前面。

联合索引的适用场景:联合索引能够减少开销,有利于索引的覆盖(当查询的字段都属于联合索引时,能够很快定位到所需查询的位置,不需要再次回表,此外在用联合索引进行查询时,不能够跳过索引列表中中间的几个字段,否则效率回降低!

联合索引中:带头大哥不能死,中间兄弟不能断

索引的优缺点

优点:

  1. 提高检索效率
  2. 降低排序成本,索引对应的字段会有一个自动排序的功能,默认是升序asc

缺点:

  1. 创建索引和维护索引需要一定的时间,且随着数据量的增大而增大
  2. 索引需要占用物理空间,数据量越大占用空间越大
  3. 会降低表怎删改的效率,每次增删改索引都需要进行动态维护

存储过程

存储过程是SQL语句的集合

image-20230301094202845

分隔符修改

image-20230301094410282

SQL优化

SQL的优化一般是在索引的基础上进行的优化

SQL优化的5个主要方法:

  1. 创建索引减少扫描量
  2. 调整索引减少计算量(in关键字后的内容过多也会导致查询时间过长)
  3. 索引覆盖(减少不必要的访问列,避免回表查询)
  4. 干预执行计划
  5. SQL改写

分析

1、查看各个语句的执行次数(提供优化的方向)

image-20230301101814456

image-20230301101823060

image-20230301101944846

2、定位低效sql语句

image-20230301102232553

通过 show processlist 可以看出当前数据库的状态,若某条语句正在进行,说明该条语句的性能就比较低了

3、分析语句,通过explain可以分析语句

image-20230301102906411

image-20230301103226600

image-20230301103314344

type字段决定mysql如何查找表中的数据,查找数据记录的大概范围。这个字段的所有值表示的从最优到最差依次为:

system > const > eq_ref (使用唯一索引进行查询)> ref(使用普通索引或者唯一索引的前缀部分进行查询) > range(使用范围查找) > index (扫描二级索引)> all;

trace工具

image-20230708151321351

1
set session optimizer_trace="enable=on",end_markers_in_json=on;//启动trace

索引优化

索引生效的前提是要有序
  1. 全值匹配
  2. 最左前缀原则
  3. 不要再索引列上做任何函数操作、计算操作、or操作、类型转化
    • 若需要对索引列进行操作,尽量考虑用范围相关的操作,如like、>这些
  4. 存储引擎不能使用索引中范围条件右边的列
    • 范围查询会使后面字段无序,造成部分索引失效
  5. 尽量使用覆盖索引(只访问索引的查询),减少select * 语句
  6. 不等号、空值、or会导致索引失效,要少用
  7. like的%写最右,因为前模糊的话一般要全部扫描了
  8. 字符串不加单引号也会导致索引失效
  9. 范围查询的优化(将大的范围拆分成多个小的范围)

补充:一般在explain的时候若有possible_keys可以使用FORCE_INDEX(索引名称)来强制使用索引image-20230708150244801

索引使用总结:

全值匹配我最爱,最左前缀要遵守;

带头大哥不能死,中间兄弟不能断;

索引列上少计算,范围之后全失效;

Like百分写最右,覆盖索引不写星;

不等空值还有or,索引失效要少用;

VAR引号不可丢,SQL高级也不难!

SQL优化

  1. 不要使用select *
  2. 小表驱动大表:select 成绩 from 学生(数据少,为小表,主表) left join 成绩(数据多,为大表) on id = id
  3. 用连接查询代替子查询(具体情况具体分析)
  4. 提升group by 的效率(为group by的那个字段添加索引)
  5. 批量插入数据(即便是批量插入也建议控制一下数量,一次插入500作用就差不多了)image-20230708152705687
  6. 一次查询过多的话要使用limit(用Mybati的时候他有一个分页插件,会帮我们改写sql,所以在mapper文件中一般不需要写limit这种)
  7. 通过id来过滤查询的内容,利用主键查询提高效率(in那边还可以通过表连接再来提升一次效率)image-20230708155500235
  8. 用union all来代替union,因为union需要去重,会占用更多CPU资源
  9. join的表不宜过多

MySQL存储过程

1
2
3
4
5
6
7
8
9
10
mysql> delimiter //
mysql> create procedure proc1(out s int
-> begin
->
-> select count (*into s from emp;
-> end;
-> //
-> delimiter;


delimiter是分隔符的意思,如果我们没有声明分隔符,编译器会把存储过程当成SQL语句进行处理,那么存储过程的编译过程会报错,所以事先要使用delimiter关键字声明当前分隔符(delimiter //),这样MySQL才会将“;”当做存储过程中的代码,不会执行这些代码。但记得用完之后要把分隔符还原(delimiter;)

调用存储过程:

MySQL 中使用 CALL 语句来调用存储过程。调用存储过程后,数据库系统将执行存储过程中的 SQL 语句,然后将结果返回给输出值。

CALL 语句接收存储过程的名字以及需要传递给它的任意参数,基本语法形式如下:

1
CALL sp_name([parameter[...]]);

其中,sp_name 表示存储过程的名称,parameter 表示存储过程的参数。

MySQL分库分表

数据的分库分表分区,中心思想都是是使得单一数据库/数据表的数据量变小,来缓解单一数据库的性能问题。

拆分策略:

  • 垂直分库:以表为依据,不同的表分到不同的库中,每个库中的表结构不同,数据不同
  • 垂直分表:以字段为依据,不同的字段拆分到不同的表中,每个表的结构不同,数据不同(通过主键关联)
  • 水平分库:以字段为依据,将一个库的数据拆分到不同的库中,每个库的表结构相同,数据不同
  • 水平分表:以字段为依据,将一个表中的数据拆分到其他数据库表中,每个表的结构相同,数据不同

image-20231226201257763

image-20231226201200968

分库分表实现的技术:

  • shardingJDBC:基于AOP思想,在sql前进行拦截,性能较好
  • MyCat:中间件,不同调整代码,性能较差

MySQL分区

​ 表分区是将一个大表,分成若干个小表,一般根据日期将表进行分区,分区表在查询过程中一定要注意要带有分区字段作为查询条件,若是关联查询,则两个表的分区字段都需要带上。

分区的策略:

  • range分区
  • list分区(可以有效的帮我们进行一些挑选分区)
  • hash分区(分布比较均匀)

基本SQL及相关操作语句练习

1934. 确认率 - 力扣(LeetCode)

1
2
3
4
select s.user_id, round(sum(if(c.action="confirmed", 1, 0))/count(*), 2) confirmation_rate
from Signups s left join Confirmations c on s.user_id=c.user_id
group by s.user_id
分组练习及连接练习 sql中能够使用一些string中用到的函数!

570. 至少有5名直接下属的经理 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
select a.Name
from Employee a
join Employee b
on a.Id = b.ManagerId
group by a.Name
having count(b.Name) >= 5

Group BySelect指定的字段限制
select后的字段:
要么就要包含在 Group By 语句的后面,作为分组的依据;
要么就要被包含在聚合函数中。
错误:
SELECT name, salary FROM student GROUP BY name
select 后的字段 salary 不在 group by 后面,所以salary无法显示全部值。
正确1
SELECT name, salary FROM student GROUP BY name , salary
select 后的字段 name,salary 都包含在group by 后面,两个字段分组。
正确2
SELECT name,MAX(salary) FROM student GROUP BY name
select 后的字段 salary 虽然不在 group by 后面,但是在聚合函数MAX(salary)里面,所以只会有一个值会正确。

练习题:

(2条消息) MySQL学习:50道经典题目(含参考答案)(更新中)_mysql考试试题_Ghost_pepper的博客-CSDN博客