MySQL基础知识保姆级教程(三)基础语句

目录

简介

一、子查询

1.having过滤

2.limit限制查询

3.if条件判断

4.grop by排序

5.explain查询执行计划 

二、表关联

1.union合并查询结果

2.笛卡尔积

3. JOIN 连接

3.1左连接(left join)

3.2右连接(right join)

3.3内连接(inner join)


简介

继上两篇博客我们继续来说关于MySQL的基础语句,

MySQL基础知识保姆级教程(一)初识MySQL

MySQL基础知识保姆级教程(二)基础语句

一、子查询

1.having过滤

使用 HAVING 实现聚合后过滤

select id,sum(score) sum_score
from scores
group by id
having sum_score>=500;
  • select id,sum(score) sum_score :选取 id 字段,并对 score 字段求和,将求和结果别名设为 sum_score ,明确要查询的内容 。
  • from scores :从名为 scores 的表中获取数据,确定数据源 。
  • group by id :按照 id 字段进行分组,相同 id 的记录会被归为一组,后续聚合计算(如 sum(score) )是基于分组进行的 。
  • having sum_score>=500 :HAVING 子句用于对分组后的结果进行过滤,这里筛选出 sum_score(即分组内 score 求和结果 )大于等于 500 的分组,只返回满足该条件的分组数据 。HAVING 是在分组之后执行,能使用聚合函数的计算结果做条件,弥补 WHERE 不能处理聚合结果过滤的问题 。

使用子查询实现类似逻辑(另一种思路,先聚合再过滤)

-- 使用子查询
-- 先执行子查询,将子查询的结果当成一张新的表再执行外面的查询
select * from
(
    select id,sum(score) sum_score
    from scores
    group by id
) as a
where sum_score >= 500;

子查询部分(括号内):

select id,sum(score) sum_score
from scores
group by id
  • 先从 scores 表按 id 分组,计算每个分组 score 总和并命名为 sum_score ,这一步得到的是一个包含 id 和对应分组 score 总和的中间结果集,相当于一张临时表 。
  • as a :给子查询的结果集起别名 a ,方便外部查询引用 。
  • 外部查询 select * from ... where sum_score >= 500 :把子查询结果当作名为 a 的 “新表”,从这张 “表” 里选取所有字段(* 表示所有字段 ),并通过 WHERE 子句过滤出 sum_score 大于等于 500 的记录 。这种方式是先通过子查询完成分组聚合得到结果集,再对结果集用 WHERE 做常规行过滤,和 HAVING 实现的最终效果类似,但执行逻辑、语法结构有区别,实际使用中二者在功能和性能场景上有不同适用情况(比如复杂子查询嵌套等场景下写法灵活度有差异 )。

2.limit限制查询

select * from students limit 10;
-- 从10开始,取20条 
select * from students limit 10,20;
  • select * from students limit 10;

    • select * :表示选取 students 表中的所有字段(* 是通配符,代表所有列 )。
    • from students :指定数据来源是名为 students 的表 。
    • limit 10 :LIMIT 子句用于限制查询结果返回的记录数量,这里表示只从查询结果里选取前 10 条记录返回 ,常用于分页查询、获取固定数量样本数据等场景,比如只想看学生表中最前面 10 条学生信息时就可以这么用。
  • select * from students limit 10,20;

    • 同样,select * from students 是选取 students 表所有字段数据 。
    • limit 10,20 :LIMIT 子句里第一个参数 10 表示 “偏移量”,即从结果集的第 10 条记录之后开始(数据库中记录行号一般从 0 开始计数,所以这里实际是从第 11 条物理记录开始 );第二个参数 20 表示要选取的记录数量,也就是从偏移位置开始,往后取 20 条记录 。常用来实现分页功能,比如页面要展示第 2 页(假设每页 20 条 )数据时,就可以用 limit 10,20 (第 1 页是 limit 0,20 ,第 3 页是 limit 20,20 ,以此类推 ),获取对应页的学生记录 。

3.if条件判断

select id,name,sex,if(sex='男',1,2) as new_sex from students;
  • select id,name,sex,... :选取 students 表中的 idnamesex 字段数据,用于展示基础信息 。
  • if(sex='男',1,2) as new_sex :IF 是 SQL 里的条件判断函数,语法为 IF(条件, 条件为真返回值, 条件为假返回值) 。这里判断 sex 字段的值是否为 '男' :
    • 若为 '男' ,则返回 1 ;
    • 若不是 '男'(通常就是 '女' 等其他值 ),则返回 2 。
      最后用 as new_sex 给这个条件判断结果起别名 new_sex ,作为新的字段展示,整体就是查询学生基础信息同时,按性别做简单映射转换输出新的标识 。

CASE WHEN 语句实现条件判断

select id,name,sex,
case when sex='男' then 1
when sex='女' then 2
else 3 end as new_sex
from students;
  • select id,name,sex,... :同样先选取 students 表的 idnamesex 字段 。
  • case when sex='男' then 1 :CASE WHEN 是更灵活的条件分支结构,这里第一个分支判断 sex 为 '男' 时,返回 1 ;
  • when sex='女' then 2 :第二个分支,判断 sex 为 '女' 时,返回 2 ;
  • else 3 end :前面分支都不满足时(比如 sex 是其他值 ),执行 else 分支返回 3 ,最后用 as new_sex 给这一系列条件判断结果起别名 new_sex 。
    相比 IF 函数,CASE WHEN 支持多条件分支(不止简单的二元判断 ),复杂场景下更易用,这里也是实现根据性别映射输出新标识的需求 。
-- 给总分评级 
select
    id,
    sum_score,
    case
    when sum_score>=0 and sum_score<100 then '*'
    when sum_score>=100 and sum_score<200 then '**'
    when sum_score>=200 and sum_score<300 then '***'
    when sum_score>=300 and sum_score<400 then '****'
    when sum_score>=400 and sum_score<500 then '*****'
    when sum_score>=500 and sum_score<600 then '******'
    else '*******' end as stat
from
(
    select
        id,
        sum(score) as sum_score
    from
        scores
    group by
        id
) as a;
  1. 子查询部分
    • 先执行 (select id, sum(score) as sum_score from scores group by id) as a ,从 scores 表按 id 分组,计算每个 id 对应的 score 总和,别名 sum_score ,结果集命名为 a 。
  2. 主查询部分
    • select id, sum_score, ... 选取子查询结果里的 idsum_score 字段,并用 case when 语句根据 sum_score 数值区间(0 - 100100 - 200 等 ),返回对应星号评级(* 到 ******* ),评级结果别名 stat ,最终输出 id、总分、评级信息 。
    • 作用是对学生(或其他主体,由 id 关联 )的总分做区间评级,方便直观查看不同 id 对应的总分等级 。
-- 给总分评级,统计每种评级的人数 
select 
    stat, 
    count(1) as num 
from 
( 
    select 
        id, 
        sum_score, 
        case 
        when sum_score>=0 and sum_score<100 then '*' 
        when sum_score>=100 and sum_score<200 then '**' 
        when sum_score>=200 and sum_score<300 then '***' 
        when sum_score>=300 and sum_score<400 then '****' 
        when sum_score>=400 and sum_score<500 then '*****' 
        when sum_score>=500 and sum_score<600 then '******' 
        else '*******' end as stat 
    from 
    ( 
        select 
            id, 
            sum(score) as sum_score 
        from 
            scores 
        group by 
            id 
    ) as a 
) as b 
group by 
    stat;

4.grop by排序

-- 按总分排序
-- asc 升序, desc: 降序
select
    id,
    sum(score) as sum_score
from
    scores
group by
    id
order by sum_score desc;
  • 功能:从 scores 表中,按 id 分组计算每个 id 的 score 总和(别名 sum_score ),再按照 sum_score 字段 降序(desc ) 排列分组结果 。
  • 关键语法:
    • GROUP BY id :按 id 分组,让 sum(score) 针对每个 id 单独计算总和 。
    • ORDER BY sum_score desc :基于分组计算出的 sum_score 字段排序,desc 表示降序(若用 asc 则是升序,默认不写 ORDER BY 子句时结果无序 )。
-- 总分前十的学生
select
    id,
    sum(score) as sum_score
from
    scores
group by
    id
order by sum_score desc
limit 10;

除此之外的子查询还有上篇博客说的select form等

5.explain查询执行计划 

-- 打印sql的执行计划
explain select
    id,
    sum(score) as sum_score
from
    scores
group by
    id
order by
    sum_score desc
limit 10;
  • explain 关键字:MySQL 中,在查询语句前加 explain ,可让数据库返回这条查询的 执行计划 ,包含查询会用到的索引、表扫描方式、操作执行顺序等信息,用于分析查询性能瓶颈(比如是否全表扫描、索引是否有效利用 )。
  • 主查询逻辑:从 scores 表按 id 分组,计算 score 总和(sum_score ),再按 sum_score 降序排序,最后用 limit 10 取前 10 条结果 。explain 会拆解这个过程,展示数据库执行该查询的底层步骤 。

二、表关联

1.union合并查询结果

合并多张表 / 同表多次查询结果,列名以首次查询为准

-- 1. union
-- 两个sql结构要一致
select * from students where name='寇凝丹'
union all
select * from students where name='寇凝丹';

-- union: 去除重复数据
select * from students where name='寇凝丹'
union
select * from students where name='寇凝丹';
  1. UNION ALL 部分
    两次执行 select * from students where name='寇凝丹' ,用 UNION ALL 合并结果。UNION ALL 会 保留所有结果行(包括重复行 ),如果 students 表中 name='寇凝丹' 的记录有 1 条,合并后结果是 2 条相同记录 。
  2. UNION 部分
    同样两次查询 name='寇凝丹' 的记录,用 UNION 合并。UNION 会 自动去除重复行(完全相同的记录只保留 1 条 ),若原表中该姓名记录是 1 条,合并后结果还是 1 条 。

2.笛卡尔积

-- 10、笛卡尔积
create table names(
    id varchar(10),
    name varchar(10)
);
insert into names values
('001','张三'),
('002','李四'),
('003','王五'),
('004','赵六');

create table ages(
    id varchar(10),
    age int
);
insert into ages values
('001',23),
('002',24),
('003',24),
('005',25);

-- 笛卡尔积
select * from names,ages;
  1. 建表与插入数据
    • 创建 names 表,含 id(字符串类型 )、name(字符串类型 )字段,插入 4 条记录(张三、李四、王五、赵六 )。
    • 创建 ages 表,含 id(字符串类型 )、age(整数类型 )字段,插入 4 条记录(不同 id 对应的年龄 )。
  2. 笛卡尔积查询
    select * from names,ages; 执行时,数据库会将 names 表的 每一条记录 与 ages 表的 每一条记录 进行组合,结果集数量是两表记录数的乘积(这里 names 4 条 × ages 4 条 = 16 条结果 )。
    笛卡尔积不考虑关联条件,会产生大量冗余组合,实际业务中常需用 WHERE 加关联条件(如 names.id = ages.id )筛选有效关联,避免无意义数据 。

-- 再笛卡尔积的基础上增加条件实现表关联
select * from names,ages 
where names.id=ages.id;
  • 功能:先对 names 表和 ages 表做笛卡尔积(两表所有记录组合 ),再通过 where names.id=ages.id 筛选出 id 字段匹配 的记录,最终结果等价于 INNER JOIN 关联查询(只保留两表 id 相同的组合 )。
  • 作用:避免笛卡尔积的冗余数据,只保留表间 id 关联的有效记录,实现类似 select * from names inner join ages on names.id=ages.id; 的效果(旧版 SQL 常用这种语法模拟连接,现代更推荐显式 JOIN 写法 )。

3. JOIN 连接

3.1左连接(left join)

以左表数据为准,关联右表匹配行;右表无匹配时,用 NULL 填充右表字段

-- 2、left join(左关联)
-- 以左表为基础进行关联
select * from 
names as a 
left join 
ages as b 
on a.id=b.id;
  • 功能:用 LEFT JOIN 关联 names 表(别名 a ,左表 )和 ages 表(别名 b ,右表 ),保留左表(names )的所有记录 :
    • 右表(ages )有匹配 id 的行,就关联对应数据;
    • 右表无匹配行,右表字段用 NULL 填充 。
  • 关键语法:
    • left join :左连接关键字,确保左表所有记录出现在结果,右表按需匹配或补 NULL 。
    • on a.id=b.id :关联条件,指定用 id 字段匹配两张表的记录 。

3.2右连接(right join)

以右表数据为准,关联左表匹配行;左表无匹配时,用 NULL 填充左表字段,且左、右连接可通过调换表顺序相互转化

-- 3、right join(右关联)
select * from 
names as a 
right join 
ages as b 
on a.id=b.id;
  • 功能:用 RIGHT JOIN 关联 names 表(别名 a ,左表 )和 ages 表(别名 b ,右表 ),保留右表(ages )的所有记录 :
    • 左表(names )有匹配 id 的行,就关联对应数据;
    • 左表无匹配行,左表字段用 NULL 填充 。
  • 关键语法:
    • right join :右连接关键字,确保右表所有记录出现在结果,左表按需匹配或补 NULL 。
    • on a.id=b.id :关联条件,指定用 id 字段匹配两张表的记录 。

3.3内连接(inner join)

只保留两表能匹配(交集 )的行,类似 “共同满足条件的数据”,举例 “取有相同兴趣爱好的记录” 可用内连接

-- 1、inner join(内关联)
-- 两边都需要有数据才能关联到
select * from 
names as a 
inner join 
ages as b 
on a.id=b.id;
  • 功能:用 INNER JOIN 关联 names 表(别名 a )和 ages 表(别名 b ),只保留 两表 id 字段匹配 的记录(即两边都有对应 id 数据的行才会出现在结果 )。
  • 关键语法:
    • inner join :内连接关键字,取两表满足 ON 条件的交集数据 。
    • on a.id=b.id :关联条件,指定用 id 字段匹配两张表的记录 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值