MySQL 函数与分组篇(聚合函数 + GROUP BY + 常用函数)

文章目录

文章作者:当战神遇到编程

文章专栏:MySQL

欢迎大家点赞👍评论📝收藏⭐文章



一: 聚合函数

聚合函数是为了进行聚合查询,聚合查询就是就是进行"行与行之间的运算"

以下这些常用函数都只能接受一个参数

函数 作用
COUNT(expr) 统计数量
SUM(expr) 求和
AVG(expr) 平均值
MAX(expr) 最大值
MIN(expr) 最小值

准备测试表

员工表 emp

sql 复制代码
CREATE TABLE emp(
    emp_id INT,
    name VARCHAR(20),
    dept_id INT,
    salary DECIMAL(10,2)
);

部门表 dept

sql 复制代码
CREATE TABLE dept(
    dept_id INT,
    dept_name VARCHAR(20)
);

1.计数函数 (COUNT)

COUNT() 用于统计结果集中记录的行数。

sql 复制代码
-- 方式 A:统计总行数(包含 NULL 值)
SELECT COUNT(*) FROM emp;

-- 方式 B:统计指定列的有值行数(忽略 NULL 值)
SELECT COUNT(salary) FROM emp;

2.求和函数 (SUM)

SUM() 用于计算数值列的总和。

(1) 针对单个字段求和

这是最基础的用法,统计某一列的总数。

sql 复制代码
-- 统计公司所有人的基本工资总和
SELECT SUM(salary) FROM emp;
  • 特点 :它会自动忽略 NULL 值(不计入总和)。

(2) 针对多个字段(或表达式)求和

有时候我们需要统计的不是某一个列,而是几个列计算后的总结果。

sql 复制代码
-- 统计公司"实发工资"的总和(基本工资 + 奖金)
SELECT SUM(salary + bonus) FROM emp;
  • 核心逻辑

    1.数据库会先计算每一行的 salary + bonus。

    2.然后再将每一行算出的结果进行累加。

  • 避坑提醒(NULL 陷阱)

    ○ 在 SQL 中,任何数值 + NULL 的结果都是 NULL。

    ○ 如果某员工有 salary 但 bonus 是 NULL,那么 salary + bonus 的结果就是 NULL,这条数据就不会被计入总和。

  • 非数值处理:只能作用于数值类型(数字)。对字符串求和没有意义,通常结果为 0。

3.平均值函数 (AVG)

AVG(expr) 用于计算一组数值的平均值。

sql 复制代码
-- 统计公司所有人的平均工资
SELECT AVG(salary) FROM emp;

-- 统计公司所有人的平均总收入(基本工资 + 奖金)
SELECT AVG(salary + bonus) FROM emp;

深度详细拆解(必看要点)

  • 结果支持小数

    ○ 特点:AVG 的计算结果通常会自动转换为浮点数(小数)

  • NULL 的陷阱(最核心区别)

    ○ AVG 在计算时会同时忽略分子和分母中的 NULL

    ○ 举例:有 3 个人,工资分别是 1000, 2000, NULL。

    ○ AVG 的计算逻辑是 (1000 + 2000) / 2 = 1500。

  • 非数值处理:只能作用于数值类型(数字)。对字符串求平均值没有意义,通常结果为 0。

4. 最大值与最小值函数 (MAX / MIN)

MAX(expr) 和 MIN(expr) 分别用于找出一组值中的最高分和最低分。

sql 复制代码
-- 找出公司里的最高工资和最低工资
SELECT MAX(salary), MIN(salary) FROM emp;

-- 找出最高的"个人净收入"(工资 - 扣款)
SELECT MAX(salary - deduction) FROM emp;

深度详细拆解

  • 字符串:按字母顺序排列(A 最小,Z 最大)。MAX(name) 会返回字母表靠后的名字。

  • NULL 的处理

    ○ 它们都会自动忽略 NULL

    ○ 如果一列全是 NULL,结果返回 NULL。

二: 分组查询 (GROUP BY) 与 结果筛选 (HAVING)

分组查询是聚合查询的核心环节,它负责将全表数据按指定维度进行"分类汇总"。

1.基础案例:按维度统计

sql 复制代码
-- 案例 1:按部门统计人数
-- 注意:COUNT(name) 会忽略名字为 NULL 的记录
SELECT dept_id, COUNT(name) FROM emp GROUP BY dept_id;

-- 案例 2:按部门统计平均工资
SELECT dept_id, AVG(salary) FROM emp GROUP BY dept_id;

2.核心铁律:SELECT 的限制

在使用 GROUP BY 时,SELECT 后面的普通字段必须出现在 GROUP BY 子句中。

  • 逻辑解释:分组后,一组对应一行结果。如果某字段(如姓名)在组内不唯一,数据库无法确定显示哪一个,因此必须按该字段分组或对其使用聚合函数。

3.分组后的筛选:HAVING

当我们需要对聚合后的统计结果进行过滤时(比如:只看人数 > 1 的部门),必须使用 HAVING。

sql 复制代码
-- 查询人数大于 1 的部门
SELECT dept_id, COUNT(*) AS total FROM emp GROUP BY dept_id HAVING COUNT(*) > 1;

WHERE 与 HAVING 的本质区别

子句 执行时机 作用对象 备注
WHERE 分组前 筛选原始数据 决定哪些行能进入分组环节
HAVING 分组后 筛选分组结果 决定哪些组能出现在最终结果中

4.综合实战:先筛选,后分组

在实际业务中,我们通常需要先排除不符合条件的原始数据,再进行统计。

sql 复制代码
-- 需求:先筛选工资 > 6000 的员工,再按部门统计人数
SELECT dept_id, COUNT(*) FROM emp WHERE salary > 6000 GROUP BY dept_id;

5.SQL 逻辑执行顺序

  • FROM:定位表数据。
  • WHERE:对原始行进行初次过滤。
  • GROUP BY:将剩下的行分堆。
  • HAVING:对分好的堆进行过滤。
  • SELECT:提取字段、计算表达式、计算聚合函数、起别名。
  • ORDER BY:对最终结果进行排序。
  • LIMIT:最后一切两半,取指定行数。

三: 日期函数

1.获取当前时间

这类函数不需要参数,直接调用即可获取数据库服务器的当前时钟。

函数 返回值示例 说明
CURDATE( ) 2023-10-27 仅日期 (Current Date)
CURTIME( ) 14:30:05 仅时间 (Current Time)
NOW( ) 2023-10-27 14:30:05 日期 + 时间(最常用)

场景一:直接查看系统时间

sql 复制代码
-- 一次性查看日期、时间、以及完整的时间戳
SELECT CURDATE(), CURTIME(), NOW();

场景二:插入数据时自动记录时间

这是最常用的场景。比如有一个新用户注册,你需要记录他注册的精确瞬间。

sql 复制代码
-- 假设表名叫 users,有一个字段叫 registration_time
INSERT INTO users (username, registration_time) VALUES ('张三', NOW());
  • 意义: 使用 NOW() 可以确保记录下的是数据库服务器接收到请求的那一秒,非常精准。

2.日期提取与转换

当你有一个完整的"日期时间"字符串,但只需要其中一部分时使用。

  • DATE(expr):
    作用 :强行切掉时间部分,只留日期。
    场景: 比如记录是 2023-10-27 14:30:05,执行 DATE() 后得到 2023-10-27。

3.日期的加减运算(实战核心)

这是日期处理中最难也最强大的部分,使用了特殊的 INTERVAL(间隔)语法。

  • ADDDATE(date, INTERVAL expr unit)(加法):
    ○ ELECT ADDDATE(NOW(), INTERVAL 7 DAY); ------ 获取 7 天后 的时间。
  • SUBDATE(date, INTERVAL expr unit)(减法):
    ○ SELECT SUBDATE(NOW(), INTERVAL 1 MONTH); ------ 获取 1 个月前 的时间(常用于统计上月报表)。

注意: unit 可以是 DAY, MONTH, YEAR, HOUR 等。

4.计算日期差:DATEDIFF(expr1, expr2)

  • 计算逻辑:expr1 - expr2。
  • 单位 :固定返回天数
  • 注意顺序:
    ○ DATEDIFF('2023-10-01', '2023-10-05') 结果是 -4
    ○ 如果第一个日期比第二个早,结果就是负数。

四: 字符串处理函数

1.获取长度

(1) CHAR_LENGTH(str)

返回字符串的 字符个数(一个汉字算 1 个字符)

sql 复制代码
SELECT CHAR_LENGTH('hello');   -- 5
SELECT CHAR_LENGTH('你好');    -- 2

(2) LENGTH(str)

返回字符串占用的 字节数

sql 复制代码
SELECT LENGTH('hello');   -- 5
SELECT LENGTH('你好');    -- 6 (UTF8下一个汉字3字节)

2.字符串拼接

(1) CONCAT(str1,str2,...)

直接拼接多个字符串

sql 复制代码
SELECT CONCAT('张','三');  
-- 张三
sql 复制代码
SELECT CONCAT(name,'-',age) FROM student;

(2) CONCAT_WS(sep,str1,str2,...)

按指定分隔符拼接

sql 复制代码
SELECT CONCAT_WS('-', '2026','04','22');
-- 2026-04-22

3.大小写转换

(1) LOWER(str) / LCASE(str)

转小写

sql 复制代码
SELECT LOWER('HELLO');
-- hello

(2) UPPER(str) / UCASE(str)

转大写

sql 复制代码
SELECT UPPER('hello');
-- HELLO

4.截取字符串(重点)

(1) SUBSTR(str,pos,len)

从指定位置开始截取 len 个字符

sql 复制代码
SELECT SUBSTR('abcdef',2,3);
-- bcd

说明:

  • 下标从 1 开始
  • pos = 起始位置

常见场景:手机号隐藏

sql 复制代码
SELECT CONCAT(SUBSTR(phone,1,3),'****',SUBSTR(phone,8,4)) FROM user;

5.替换字符串(重点)

(1) REPLACE(str,old,new)

sql 复制代码
SELECT REPLACE('I like java','java','mysql');
-- I like mysql

批量修改数据

sql 复制代码
UPDATE user SET address = REPLACE(address,'北京','上海');

6.左右截取

(1) LEFT(str,len)

取左边 len 个字符

sql 复制代码
SELECT LEFT('abcdef',3);
-- abc

(2) RIGHT(str,len)

取右边 len 个字符

sql 复制代码
SELECT RIGHT('abcdef',2);
-- ef

7.去空格(高频)

(1) TRIM(str)

去除两边空格

sql 复制代码
SELECT TRIM('   hello   ');
-- hello

(2) LTRIM(str)

去左边空格

sql 复制代码
SELECT LTRIM('   hello');

(3) RTRIM(str)

去右边空格

sql 复制代码
SELECT RTRIM('hello   ');

8.查找字符串位置

INSTR(str,substr)

返回子串第一次出现的位置(从1开始)

sql 复制代码
SELECT INSTR('abcdef','cd');
-- 3

找不到返回:

sql 复制代码
0

五: 数学函数

1.ABS(X)

返回 X 的绝对值。

sql 复制代码
SELECT ABS(-10);
-- 10

2.CEIL(X) / CEILING(X)

向上取整(返回不小于 X 的最小整数)

sql 复制代码
SELECT CEIL(3.2);
-- 4

3.FLOOR(X)

向下取整(返回不大于 X 的最大整数)

sql 复制代码
SELECT FLOOR(3.9);
-- 3

4.ROUND(X,D)

四舍五入,保留 D 位小数。

sql 复制代码
SELECT ROUND(3.14159,2);
-- 3.14
sql 复制代码
SELECT ROUND(3.56);
-- 4

5.RAND()

返回 0~1 之间随机小数。

sql 复制代码
SELECT RAND();

随机抽取一条数据

sql 复制代码
SELECT * FROM student ORDER BY RAND() LIMIT 1;

六: 其他常用函数

1.VERSION( )

查看当前 MySQL 版本。

sql 复制代码
SELECT VERSION();

2.DATABASE( )

查看当前正在使用的数据库。

sql 复制代码
SELECT DATABASE();

3.USER( )

查看当前登录用户。

sql 复制代码
SELECT USER();

4.MD5(str)

对字符串进行 MD5 摘要加密,返回 32 位字符串。

sql 复制代码
SELECT MD5('123456');

常用于:

  • 密码加密存储(旧项目常见)
  • 数据校验

实际开发更推荐使用更安全的加密方式(如 bcrypt)。

5.IFNULL(val1,val2)

如果 val1 为 NULL,则返回 val2,否则返回 val1。

sql 复制代码
SELECT IFNULL(NULL,'默认值');
-- 默认值
sql 复制代码
SELECT IFNULL(100,0);
-- 100

实际开发常用场景

查询工资为空时显示 0

sql 复制代码
SELECT name, IFNULL(salary,0) FROM emp;
相关推荐
u0109147602 小时前
C#怎么使用Span和Memory C#如何用Span优化内存操作减少GC压力提升性能【进阶】
jvm·数据库·python
阿丰资源2 小时前
基于SpringBoot+MySQL的时装购物系统(附源码)
java·spring boot·mysql
m0_716430072 小时前
CSS项目开发如何提速_应用BEM规范建立可复用的样式库
jvm·数据库·python
gjc5922 小时前
MySQL运维避坑:你的MySQL总是关机慢、启动卡?
运维·数据库·mysql
maqr_1102 小时前
PyTorch bfloat16 张量转 NumPy 的兼容性解决方案
jvm·数据库·python
weixin_408717772 小时前
mysql如何防止SQL注入攻击_使用预编译语句与参数化查询
jvm·数据库·python
A_QXBlms2 小时前
企微定时群发全流程技术实操+高效工具落地方案
数据库·企业微信
weixin_424999362 小时前
http-equiv属性有哪些常用值_meta模拟HTTP头汇总【详解】
jvm·数据库·python
zhojiew2 小时前
在AWS上完成Apache Doris存算一体/存算分离和湖仓数据库部署的实践
数据库·apache·aws