当前位置: 代码网 > it编程>数据库>Mysql > MySQL 流程控制函数与分组函数详解

MySQL 流程控制函数与分组函数详解

2026年08月28日 Mysql 我要评论
一、流程控制函数1、if(expr1,expr2,expr3)用于查询中进行条件判断的流程控制函数。expr1:要判断的条件表达式,如果条件为真(非零或非空),则返回 expr2,否则返回 expr3

一、流程控制函数

1、if(expr1,expr2,expr3)

用于查询中进行条件判断的流程控制函数。

  • expr1:要判断的条件表达式,如果条件为真(非零或非空),则返回 expr2,否则返回 expr3。
  • expr2:条件为真时返回的值。
  • expr3:条件为假时返回的值。
select if(2 < 3,'大','小') as out_put;

示例:查询员工的姓和名以及奖金率,如果有奖金率则返回有,没有则返回无,并以备注为列名。

分析:

  • 查询的表:employees
  • 查询的字段:last_name、first_name、commission_pct、备注
  • 查询的条件:无
  • 排序的条件:无
select
    last_name,
    first_name,
    if(commission_pct is null,'无','有') as 备注
from
    employees;

2、case

case 是一种流程控制函数,类似编程语言中的 switch 语法。

语法格式 1:

case value
    when compare_value then result
    [when compare_value then result ...]
    [else result]
end
  • value:需要进行比较的表达式或者列。
  • compare_value:进行比较的表达式或值。
  • result:当 value 等于 compare_value 时返回的结果。

语法格式 2:

case
    when condition then result
    [when condition then result ...]
    [else result]
end
  • condition:条件表达式,可以是任何布尔表达式。
  • result:当条件表达式为真时返回的结果。
  • else result:如果没有条件表达式为真时,则返回的默认结果。

示例:查询员工的工资,要求如下:

  1. 部门号=30,显示的工资为 1.1 倍。
  2. 部门号=40,显示的工资为 1.2 倍。
  3. 部门号=50,显示的工资为 1.3 倍。
  4. 其他部门,显示的工资为原工资。

分析:

  • 查询的表:employees
  • 查询的字段:salary、department_id、新工资
  • 查询的条件:无
  • 排序的条件:无

使用语法格式 1:

select
    salary,
    department_id,
    case department_id
        when 30 then salary * 1.1
        when 40 then salary * 1.2
        when 50 then salary * 1.3
        else salary
    end as 新工资
from
    employees;

使用语法格式 2:

select
    salary,
    department_id,
    case
        when department_id = 30 then salary * 1.1
        when department_id = 40 then salary * 1.2
        when department_id = 50 then salary * 1.3
        else salary
    end as 新工资
from
    employees;

示例:查询员工的工资情况:

  1. 如果工资大于 20000,显示 a 级别。
  2. 如果工资大于 15000,显示 b 级别。
  3. 如果工资大于 10000,显示 c 级别。
  4. 否则,显示 d 级别。
select
    salary,
    case
        when salary > 20000 then 'a'  --工资>20000 → a级别
        when salary > 15000 then 'b'  --15000<工资≤20000 → b级别
        when salary > 10000 then 'c'  --10000<工资≤15000 → c级别
        else 'd'  --工资≤10000 → d级别
    end as 工资级别
from
    employees;

二、分组函数(聚合函数)

分组函数用作统计使用,又称为聚合函数、统计函数或者组函数。

  • max():返回最大值。
  • min():返回最小值。
  • avg():返回参数的平均值。
  • count():返回行数。
  • sum():返回总和。

总结:

  • sum、avg 一般用于处理数值型,max、min、count 可以处理任何类型。
  • max、min、avg、count 聚合函数都忽略 null 值。
  • 可以和 distinct 搭配实现去重的运算。
  • 一般使用 count(*) 做统计函数。
  • 和聚合函数一同查询的字段要求是 group by 关键字后面的字段。

1、sum()

select
    sum(salary) as sum_sal  --查询所有员工工资总和
from
    employees;

2、avg()

select
    round(avg(salary),2) as avg_sal  --查询工资平均值,保留2位小数
from
    employees;

3、max()

select
    max(salary) as max_sal  --查询工资最大值
from
    employees;

4、min()

select
    min(salary) as min_sal  --查询工资最小值
from
    employees;

5、count()

select count(salary) as count_sal from employees;  --统计salary不为null的行数
select count(commission_pct) as count_sal from employees;  --忽略null值

示例:查询所有员工的工资总和、平均值、最高值、最低值以及总个数。

select
    sum(salary),    --工资总和
    avg(salary),    --工资平均值
    max(salary),    --工资最大值
    min(salary),    --工资最小值
    count(salary)   --非空工资的记录条数
from
    employees;

6、聚合函数使用细节与总结

数值型与字符串、日期的处理差异:

select sum(last_name), avg(last_name) from employees;  --sum、avg只适合数值,字符串求和无实际意义
select sum(hiredate), avg(hiredate) from employees;    --sum、avg对日期运算,无业务意义
select max(last_name), min(last_name) from employees;  --max/min可以用于字符串,按字典顺序取最大最小
select max(hiredate), min(hiredate) from employees;    --max/min可以用于日期,取最晚、最早日期

是否忽略 null 值:

select count(commission_pct) from employees;  --count统计不为null的佣金字段行数,null会跳过
select count(last_name) from employees;
select sum(commission_pct), avg(commission_pct), sum(commission_pct) / 35, sum(commission_pct) / 107 from employees;
select max(commission_pct), min(commission_pct) from employees;
select count(commission_pct) from employees;  --count忽略null值
select count(last_name) from employees;

搭配 distinct 实现去重:

select max(distinct salary), min(salary) from employees;
select sum(distinct salary), sum(salary) from employees;
select count(distinct salary), count(salary) from employees;

count() 详细说明:

select count(salary) from employees;
select count(*) from employees;
select count(1) from employees;

7、分组查询

分组查询的基本语法结构如下:

select
    聚合函数,
    分组字段       --select中非聚合的列,必须写在group by之后
from
    表名
where
    分组之前的筛选条件  --where:原始表数据过滤,不能写聚合函数
group by
    分组字段列表
having
    分组之后的筛选条件  --having:分组结果过滤,可以写聚合函数
order by
    排序字段 asc|desc
with rollup;  --生成汇总行

分组查询中的筛选条件分为两类:

  • 分组前筛选:作用于原始表,位于 group by 子句的前面,使用 where。
  • 分组后筛选:作用于分组后的结果集(虚表),位于 group by 子句的后面,使用 having。

注意:

  • 分组函数做条件时,肯定放在 having 子句中。
  • 能用分组前筛选的,就优先考虑使用分组前筛选。
  • group by 子句支持单字段分组、多字段分组(多个字段之间使用逗号隔开,没有先后顺序)、表达式或者函数。
  • 也可以添加排序,排序放在整个分组查询的最后。

示例:查询每个部门的平均工资。

select
    avg(salary),
    department_id
from
    employees
group by
    department_id;

示例:查询邮箱中包含 a 字符的每个部门的平均工资。

分析:

  • 查询的表:employees
  • 查询的字段:salary、department_id
  • 查询的条件:email like '%a%'
  • 分组的字段:department_id
  • 排序的条件:无
select
    avg(salary) as avg_sal,
    department_id
from
    employees
where
    email like '%a%'
group by
    department_id;

示例:查询有奖金率的每个领导手下员工的最高工资。

分析:

  • 查询的表:employees
  • 查询的字段:salary、manager_id
  • 查询的条件:commission_pct is not null
  • 分组的字段:manager_id
  • 排序的条件:无
select
    max(salary) as max_sal,
    manager_id
from
    employees
where
    commission_pct is not null
group by
    manager_id;

示例:添加复杂的筛选条件,查询哪个部门的员工个数大于 2。

分析(1):查询每个部门的员工个数。

select
    count(*),
    department_id
from
    employees
group by
    department_id;

分析(2):根据(1)的查询结果进行筛选,员工个数大于 2。

select
    count(*),
    department_id
from
    employees
group by
    department_id
having count(*) > 2;

示例:查询每个工种有奖金率的员工的最高工资大于 12000 的工种编号和最高工资。

select
    max(salary) as max_sal,  --查询最高工资,起别名max_sal
    job_id                    --工种编号
from
    employees                 --员工表
where
    commission_pct is not null  --分组前筛选:原始表,过滤有奖金的员工
group by
    job_id                     --按照工种编号分组
having
    max_sal > 12000;           --分组后筛选:分组结果,最高工资大于12000

示例:查询领导编号大于 102 的每个领导手下的最低工资大于 5000 的领导编号是哪个,以及其最低工资。

分析(1):查询每个领导手下的员工最低工资。

select
    min(salary),      --查询每个分组下员工的最低工资
    manager_id        --领导编号
from
    employees         --员工表
group by
    manager_id;       --根据领导编号分组

分析(2):根据(1)的结果继续添加筛选条件:编号大于 102。

select
    min(salary),      --最低工资
    manager_id        --领导编号
from
    employees         --员工表
where
    manager_id > 102  --分组前筛选:原始表,过滤领导编号>102的数据
group by
    manager_id;       --按领导编号分组

分析(3):根据(2)的结果继续筛选,最低工资大于 5000。

select
    min(salary),      --最低工资
    manager_id        --领导编号
from
    employees         --员工表
where
    manager_id > 102  --where:分组前过滤原始行,领导编号>102
group by
    manager_id        --按照领导编号分组
having
    min(salary) > 5000; --having:分组后过滤聚合结果,最低工资大于5000

示例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数大于 5 的有哪些。

select
    count(*) as emp_count,                        --统计每组员工数量,别名emp_count
    length(concat(last_name, first_name)) as len_name  --姓名总长度
from
    employees
group by
    length(concat(last_name, first_name))          --group by支持函数/表达式分组
having
    count(*) > 5;                                 --分组之后过滤,只保留员工数大于5的组

三、连接查询

需求:查询所有女明星对应的男朋友。

select `name`, boyname from beauty, boys;  --笛卡尔积,两张表所有行互相配对,产生错误大量数据
select `name`, boyname from beauty, boys
where beauty.boyfriend_id = boys.id;  --等值连接,添加两张表关联条件,消除笛卡尔积

笛卡尔积:是两个或多个表之间的连接操作。

笛卡尔积现象:表 1 有 m 行,表 2 有 n 行,结果为 m * n。

笛卡尔积产生的条件:

  • 省略连接条件。
  • 连接条件无效。
  • 所有表中的所有行互相连接。

注意:为了避免笛卡尔积产生,可以在 where 子句后面加入有效连接条件。

连接查询:又称为多表查询,当查询的字段来自多个表时,就会用到连接查询。

连接查询分类:

  • 按年代分类:
    • sql92 标准(淘汰,了解即可)。
    • sql99 标准(推荐使用),支持内连接 + 外连接(左外、右外)+ 交叉连接。
  • 按功能分类:
    • 内连接:等值连接、非等值连接、自连接。
    • 外连接:左外连接、右外连接、全外连接。
    • 交叉连接

连接查询语法格式总结:

select (7)
    查询列表
from 表1 别名 [连接类型]  (1)
join 表2 别名      (3)
on 连接条件    (2)
[where 筛选条件] (4)
[group by 子句] (5)
[having 筛选条件] (6)
[order by 子句] (8)

连接条件分类:

  • 内连接:inner。
  • 外连接
    • 左外连接:left [outer]。
    • 右外连接:right [outer]。
    • 全外连接:full [outer],mysql 不支持全外。
  • 交叉连接:cross。

内连接:inner

-- 语法格式:
select 查询列表
from 表1 别名
inner join 表2 别名
on 连接条件;

内连接分为:等值、非等值、自连接。

特点:

  • 可以添加排序、分组、筛选。
  • inner 关键字可以省略。
  • 筛选条件放在 where 后面,连接条件要放在 on 后面,提高分离性,便于阅读。

(1)等值连接

示例:查询员工名、部门名。

分析:

  • 查询的表:employees、departments
  • 查询的字段:first_name、department_name
  • 查询条件:无
select
    e.first_name,
    d.department_name
from
    employees as e
inner join departments as d
on e.department_id = d.department_id;

示例:查询名字中包含 a 的员工名和工种名。

select
    first_name,
    job_title
from
    employees e
inner join jobs j
on e.job_id = j.job_id
where
    e.first_name like '%a%';

示例:查询部门个数大于 3 的城市名和部门个数(添加分组 + 筛选)。

分析(1):查询每个部门的个数。

select
    count(*) as num,
    city
from
    departments d
inner join locations l
on d.location_id = l.location_id
group by
    city;

分析(2):根据(1)的结果筛选部门个数大于 3。

select
    count(*) as num,
    city
from
    departments d
inner join locations l
on d.location_id = l.location_id
group by
    city
having
    num > 3;

示例:查询哪个部门的员工个数大于 3 的部门名和员工个数,并按个数降序(添加排序条件)。

分析(1):查询每个部门的员工个数。

select
    count(*) as num,
    department_name
from
    employees e
inner join departments d
on e.department_id = d.department_id
group by
    department_name;

分析(2):根据(1)的结果筛选员工个数大于 3 的并排序。

select
    count(*) as num,
    department_name
from
    employees e
inner join departments d
on e.department_id = d.department_id
group by
    department_name
having
    num > 3
order by
    count(*) desc;

示例:查询员工名、部门名、工种名,并按部门名进行降序。

select
    first_name,        --员工名
    department_name,   --部门名
    job_title          --工种名
from
    employees e        --员工表,起别名e
inner join departments d  --内连接部门表,别名d
on e.department_id = d.department_id  --员工表部门id = 部门表部门id,表关联条件
inner join jobs j      --内连接工种表,别名j
on e.job_id = j.job_id --员工表工种id = 工种表工种id,表关联条件
order by
    department_name desc;  --按照部门名降序排序

(2)非等值连接

示例:查询员工的工资级别。

分析:

  • 查询的表:employees、job_grades
  • 查询思路:查询 employees 表中的 salary 字段在 job_grades 的最低工资和最高工资区间内,确定等级。
select
    salary,                --员工工资
    grade_level            --工资等级
from
    employees e            --员工表,别名e
inner join job_grades g    --内连接工资等级表,别名g
on e.salary between g.lowest_sal and g.highest_sal;  --非等值连接:员工工资落在等级工资区间

示例:查询工资级别的个数大于 20 的个数,并且按工资级别降序。

select
    count(*),              --统计每个工资级别下员工数量
    grade_level            --工资级别
from
    employees e
inner join job_grades g
on e.salary between g.lowest_sal and g.highest_sal  --非等值关联条件
group by
    grade_level            --按照工资级别分组
having
    count(*) > 20          --分组后过滤:只保留员工数大于20的等级
order by
    grade_level desc;      --工资级别降序排序

(3)自连接

示例:查询员工的名字、上级的名字。

select
    e.first_name,   --普通员工姓名,别名e代表员工
    m.first_name    --上级管理者姓名,别名m代表管理者
from
    employees e     --同一张表起第一个别名:员工
inner join employees m  --自连接:一张表当成两张表使用,第二个别名:管理者
on e.manager_id = m.employee_id;  --员工的管理者id = 管理者自己的员工编号

外连接:

  • 左外连接:left [outer]。
  • 右外连接:right [outer]。

应用场景:用于查询一个表中有、另一个表中没有的记录。

特点总结:

  • 外连接的查询结果为主表中的所有记录,如果从表中有和它匹配的,则显示匹配的值,如果从表中没有和它匹配的则显示 null。外连接查询结果 = 内连接结果 + 主表中有、从表中没有的记录。
  • 左外连接,left join 左边是主表,右边是从表;右外连接,right join 右边是主表,左边是从表。
  • 左外和右外交换两个表的顺序,可以实现相同的结果。
  • 全外连接 = 内连接结果 + 表1中有但表2中没有的 + 表2中有但表1中没有的。

连接类型对比:

连接类型关键字保留的记录未匹配时的处理
左外连接left join 或 left outer join左表全部记录右表字段填充 null
右外连接right join 或 right outer join右表全部记录左表字段填充 null
全外连接full join 或 full outer join两表全部记录缺失方字段填充 null

对比维度:

对比维度left joinright joinfull join
保留表左表全部右表全部两表全部
匹配失败填充右表字段为 null左表字段为 null对应方字段为 null
是否可互换可以(调换表顺序)可以(调换表顺序)不可以(需 union 模拟)
mysql 原生支持支持支持不支持

结果集范围对比:

查询包含 a 独有包含交集包含 b 独有结果集范围
left joina 全部
right joinb 全部
inner join交集
left + where b is nulla 独有(a-b)
full + where a is nullb 独有(b-a)
full join并集

引入:查询男朋友不在男神表中的女神名,即查询没有男朋友的女神。

左外连接:

select
    *
from
    beauty b
left join boys bo
on b.boyfriend_id = bo.id
where
    bo.id is null;

右外连接:

select
    *
from
    boys bo
right join beauty b
on bo.id = b.boyfriend_id
where
    bo.id is not null;  --筛选男神表id不为null,查询有男朋友的女神

示例:查询哪个部门没有员工。

左外连接:部门表为主表,员工表为从表。

select
    d.*,
    e.employee_id
from
    departments d
left join employees e
on d.department_id = e.department_id
where
    e.employee_id is null;  --员工id为null,代表该部门没有匹配到员工,即无员工的部门

等价的右外连接写法:把部门放右边做主表,员工表放左边。

select
    d.*,
    e.employee_id
from
    employees e
right join departments d
on d.department_id = e.department_id
where
    e.employee_id is null;  --左边员工表主键为null,代表该部门没有员工

全外连接:mysql 不支持 full join 语法。

-- select
--     *
-- from
--     beauty b
-- full join boys bo
-- on b.boyfriend_id = bo.id;

到此这篇关于mysql 流程控制函数与分组函数详解的文章就介绍到这了,更多相关mysql 流程控制函数与分组函数内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com