目录
常见函数一:数值函数
一、常见数值函数
1. 基本函数
2. 角度与弧度互换函数
3. 三角函数
4. 指数与对数
5. 进制间的转换
常见函数二:日期函数
一、常见日期函数
二、SQL演示
1. curdate:当前日期
2. curtime:当前时间
3. now:当前日期和时间
4. YEAR , MONTH , DAY:当前年、月、日
5. date_add:增加指定的时间间隔
6. datediff:获取两个日期相差的天数
三、案例
常见函数三:聚合函数
一、五大常用聚合函数
二、GROUP BY
三、HAVING
四、SQL底层执行原理
1. SELECT语句的完整结构
2. SQL语句的执行过程
常见函数四:流程函数
一、作用
二、常见
三、SQL演示
1. if
2. ifnull
3. case when then else end
四、案例
常见函数一:数值函数
一、常见数值函数
1. 基本函数
函数 | 功能 |
ABS(x) | 返回x的绝对值 |
SIGN(X) | 返回X的符号。正数返回1,负数返回-1,0返回0 |
PI() | 返回圆周率的值 |
CEIL(x),CEILING(x) | 返回大于或等于某个值的最小整数 |
FLOOR(x) | 返回小于或等于某个值的最大整数 |
LEAST(e1,e2,e3…) | 返回列表中的最小值 |
GREATEST(e1,e2,e3…) | 返回列表中的最大值 |
MOD(x,y) | 返回X除以Y后的余数 |
RAND() | 返回0~1的随机值 |
RAND(x) | 返回0~1的随机值,其中x的值用作种子值,相同的X值会产生相同的随机数 |
ROUND(x) | 返回一个对x的值进行四舍五入后,最接近于X的整数 |
ROUND(x,y) | 返回一个对x的值进行四舍五入后最接近X的值,并保留到小数点后面Y位 |
TRUNCATE(x,y) | 返回数字x截断为y位小数的结果 |
SQRT(x) | 返回x的平方根。当X的值为负数时,返回NULL |
举例:
SELECT ABS(-123),ABS(32),SIGN(-23),SIGN(43),PI(),CEIL(32.32),CEILING(-43.23),FLOOR(32.32),
FLOOR(-43.23),MOD(12,5)
FROM DUAL;
取随机数
SELECT RAND(),RAND(),RAND(10),RAND(10),RAND(-1),RAND(-1)
FROM DUAL;
四舍五入,截断操作
SELECT ROUND(12.33),ROUND(12.343,2),ROUND(12.324,-1),TRUNCATE(12.66,1),TRUNCATE(12.66,-1)
FROM DUAL;
单行函数可以嵌套
SELECT TRUNCATE(ROUND(123.456,2),0)
FROM DUAL;
2. 角度与弧度互换函数
函数 | 用法 |
RADIANS(x) | 将角度转化为弧度,其中,参数x为角度值 |
DEGREES(x) | 将弧度转化为角度,其中,参数x为弧度值 |
SELECT RADIANS(30),RADIANS(60),RADIANS(90),DEGREES(2*PI()),DEGREES(RADIANS(90))
FROM DUAL;
3. 三角函数
函数 | 用法 |
SIN(x) | 返回x的正弦值,其中,参数x为弧度值 |
ASIN(x) | 返回x的反正弦值,即获取正弦为x的值。如果x的值不在-1到1之间,则返回NULL |
COS(x) | 返回x的余弦值,其中,参数x为弧度值 |
ACOS(x) | 返回x的反余弦值,即获取余弦为x的值。如果x的值不在-1到1之间,则返回NULL |
TAN(x) | 返回x的正切值,其中,参数x为弧度值 |
ATAN(x) | 返回x的反正切值,即返回正切值为x的值 |
ATAN2(m,n) | 返回两个参数的反正切值 |
COT(x) | 返回x的余切值,其中,X为弧度值 |
举例:
- ATAN2(M,N)函数返回两个参数的反正切值。
- 与ATAN(X)函数相比,ATAN2(M,N)需要两个参数,例如有两个点point(x1,y1)和point(x2,y2),使用ATAN(X)函数计算反正切值为ATAN((y2-y1)/(x2-x1)),使用ATAN2(M,N)计算反正切值则为ATAN2(y2-y1,x2-x1)。由使用方式可以看出,当x2-x1等于0时,ATAN(X)函数会报错,而ATAN2(M,N)函数则仍然可以计算。
- ATAN2(M,N)函数的使用示例如下:
SELECT SIN(RADIANS(30)),DEGREES(ASIN(1)),TAN(RADIANS(45)),DEGREES(ATAN(1)),DEGREES(ATAN2(1,1))
FROM DUAL;
4. 指数与对数
函数 | 用法 |
POW(x,y),POWER(X,Y) | 返回x的y次方 |
EXP(X) | 返回e的X次方,其中e是一个常数,2.718281828459045 |
LN(X),LOG(X) | 返回以e为底的X的对数,当X <= 0 时,返回的结果为NULL |
LOG10(X) | 返回以10为底的X的对数,当X <= 0 时,返回的结果为NULL |
LOG2(X) | 返回以2为底的X的对数,当X <= 0 时,返回NULL |
mysql> SELECT POW(2,5),POWER(2,4),EXP(2),LN(10),LOG10(10),LOG2(4)
-> FROM DUAL;
+----------+------------+------------------+-------------------+-----------+---------+
| POW(2,5) | POWER(2,4) | EXP(2) | LN(10) | LOG10(10) | LOG2(4) |
+----------+------------+------------------+-------------------+-----------+---------+
| 32 | 16 | 7.38905609893065 | 2.302585092994046 | 1 | 2 |
+----------+------------+------------------+-------------------+-----------+---------+
1 row in set (0.00 sec)
5. 进制间的转换
函数 | 用法 |
BIN(x) | 返回x的二进制编码 |
HEX(x) | 返回x的十六进制编码 |
OCT(x) | 返回x的八进制编码 |
CONV(x,f1,f2) | 返回f1进制数变成f2进制数 |
mysql> SELECT BIN(10),HEX(10),OCT(10),CONV(10,2,8)
-> FROM DUAL;
+---------+---------+---------+--------------+
| BIN(10) | HEX(10) | OCT(10) | CONV(10,2,8) |
+---------+---------+---------+--------------+
| 1010 | A | 12 | 2 |
+---------+---------+---------+--------------+
1 row in set (0.00 sec)
常见函数二:日期函数
一、常见日期函数
函数 | 功能 |
CURDATE() | 返回当前日期 |
CURTIME() | 返回当前时间 |
NOW() | 返回当前日期和时间 |
YEAR(date) | 获取指定date的年份 |
MONTH(date) | 获取指定date的月份 |
DAY(date) | 获取指定date的日期 |
DATE_ADD(date, INTERVAL expr type) | 返回一个日期/时间值加上一个时间间隔expr后的 时间值 |
DATEDIFF(date1,date2) | 返回起始时间date1 和 结束时间date2之间的天 数 |
二、SQL演示
1. curdate:当前日期
select curdate();
2. curtime:当前时间
select curtime();
3. now:当前日期和时间
select now();
4. YEAR , MONTH , DAY:当前年、月、日
select YEAR(now());
select MONTH(now());
select DAY(now());
5. date_add:增加指定的时间间隔
select date_add(now(), INTERVAL 70 YEAR );
6. datediff:获取两个日期相差的天数
select datediff('2021-10-01', '2021-12-01');
三、案例
查询所有员工的入职天数,并根据入职天数倒序排序。
思路: 入职天数,就是通过当前日期 - 入职日期,所以需要使用datediff函数来完成。
select name, datediff(curdate(), entrydate) as 'entrydays' from emp order by entrydays desc;
常见函数三:聚合函数
一、五大常用聚合函数
- SUM():求总和,只适用于数值类型字段,如果是字符串类型不会报错会返回0,会自动过滤空值
- AVG():求平均值,只适用于数值类型字段,字符串类型不会报错会返回0,会自动过滤空值
- MAX():求最大值,适用于数值类型、字符串类型和日期时间类型字段
- MIN():求最小值,适用于数值类型、字符串类型和日期时间类型字段
- COUNT():用于计算查询结果集中的数据共有多少条
-
- COUNT(*)
- COUNT(常数):例如COUNT(0),COUNT(1)
- COUNT(指定字段):此方式只能用于那种不存在NULL的字段,如果存在空值,统计总数时不计入
- 如果是MyISAM引擎,这三种方式的效率相同,因为此引擎内部有一个计数器在维护着行数。如果是InnoDB引擎,那么第一和第二种效率高于第三种,后面会细说
注意:MySQL中聚合函数是不能嵌套使用的
我们创建一个表t_decade_book来进行验证
DROP TABLE IF EXISTS t_decade_book;
CREATE TABLE t_decade_book (
book_id int(10) NOT NULL AUTO_INCREMENT COMMENT '书id',
book_name varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '书名',
book_count int(10) DEFAULT NULL COMMENT '数量',
detail varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '描述',
PRIMARY KEY (book_id) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO t_decade_book VALUES (1, 'Java从入门到秃头', 20, 'Java学习');
INSERT INTO t_decade_book VALUES (2, '数据库从删库到跑路', 20, '数据库学习');
INSERT INTO t_decade_book VALUES (3, '测试从入职到干架', 20, '测试脚本学习');
INSERT INTO t_decade_book VALUES (4, '划水越划越爽', NULL, '划水技巧学习');
得到的表数据如下
SELECT AVG(book_count),SUM(book_count),AVG(book_count)*4 FROM t_decade_book;
SELECT MAX(book_count),MIN(book_count),MAX(book_name),MIN(book_name) FROM t_decade_book;
SELECT COUNT(book_id),COUNT(1),COUNT(*),COUNT(book_count) FROM t_decade_book;
SELECT AVG(book_count),SUM(book_count),SUM(book_count)/4,SUM(book_count)/COUNT(book_count) FROM t_decade_book;
执行结果如下
二、GROUP BY
首先我们向之前创建的t_decade_blog表中插入一条数据
INSERT INTO t_decade_blog(id,name,author,create_time,views)VALUES('d3258b79-d543-49bb-9850-16cac7566666','JVM系列','十年',NOW(),8000);
表格中结果如下
然后我们测试一下GROUP BY操作
# 根据单列进行分组
SELECT author,AVG(views) FROM t_decade_blog GROUP BY author;
# 根据多列进行分组,如果分组的条件相同,顺序不同不会影响最终结果
# 我们可以理解为根据这些条件进行组合,只有符合这些条件的才会分到一个组里
SELECT id,author,AVG(views) FROM t_decade_blog GROUP BY id,author;
SELECT author,id,AVG(views) FROM t_decade_blog GROUP BY author,id;
# 当使用GROUP BY关键字时,SELECT中涉及到的非聚合函数包含的字段,必须出现在GROUP BY后面
# 但是GROUP BY关键字后面的字段不一定要出现在SELECT之后
# 另外,在不使用GROUP BY时,聚合函数不能和普通字段放在一起进行查询
SELECT author,id,AVG(views) FROM t_decade_blog GROUP BY author;
# with rollup作用在聚合函数。如果聚合函数是COUNT(*)则会在统计的记录中再次求COUNT(*)
# 如果是AVG(),则会去除分组条件,求该字段的AVG()
# 使用WITH ROLLUP后不能再使用ORDER BY
SELECT author,AVG(views) FROM t_decade_blog GROUP BY author WITH ROLLUP;
SELECT book_id,AVG(book_count) FROM t_decade_book GROUP BY book_id WITH ROLLUP;
SELECT author,COUNT(views) FROM t_decade_blog GROUP BY author WITH ROLLUP;
执行结果如下
注意GROUP BY的使用顺序
- 放在FROM、WHERE后面
- 放在ORDER BY、LIMIT前面
三、HAVING
1、HAVING 子句可以让我们筛选分组后的各组数据
- 当我们想使用聚合函数作为数据的过滤条件时,就不能搭配WHERE使用了,必须使用HAVING来进行替换。比如我们想筛选出哪些部门的最高工资大于10000,那么就要先根据部门id进行分组,然后再使用HAVING对MAX(salary)进行过滤
- 如果过滤条件中没有聚合函数,那就强烈建议使用WHERE
- HAVING必须声明在GROUP BY后面
- 在日常开发中,使用HAVING的前提是我们使用了GROUP BY
2、HAVING和WHERE的对比
- 从适用范围来说,HAVING更广
- 如果过滤条件中没有聚合函数,那么WHERE的执行效率要高于HAVING。因为WHERE的执行顺序是排在HAVING前面的,它会筛选掉不满足条件的数据,这样后面GROUP BY分组以及HAVING要处理的数据量就更小了
# 错误演示
SELECT id,MAX(views)
FROM t_decade_blog
WHERE MAX(views) > 4000
GROUP BY id;
SELECT id,MAX(views)
FROM t_decade_blog
GROUP BY id
HAVING MAX(views) > 4000;
# 如果我们想查出特定博客id中最大浏览量大于4000的书籍
# 方式一:WHERE搭配HAVING,推荐此方式,执行效率更高
SELECT id,MAX(views)
FROM t_decade_blog
WHERE id IN ('76782763-48d0-4cef-b8e1-1054e181e41d',
'd3258b79-d543-49bb-9850-16cac7565f57',
'd3258b79-d543-49bb-9850-16cac7566666')
GROUP BY id
HAVING MAX(views) > 4000;
# 方式二
SELECT id,MAX(views)
FROM t_decade_blog
GROUP BY id
HAVING MAX(views) > 4000
AND id IN ('76782763-48d0-4cef-b8e1-1054e181e41d',
'd3258b79-d543-49bb-9850-16cac7565f57',
'd3258b79-d543-49bb-9850-16cac7566666');
四、SQL底层执行原理
1. SELECT语句的完整结构
SQL92语法结构
SELECT 字段1,字段2,...(可能存在聚合函数)
FROM 表1,表2,...
WHERE 多表的连接条件 AND 不包含聚合函数的过滤条件
GROUP BY 分组字段1,分组字段2...
HAVING 包含聚合函数的过滤条件
ORDER BY 排序字段1,排序字段2...(ASC / DESC)
LIMIT 偏移量,条目数
SQL99语法结构
SELECT 字段1,字段2,...(可能存在聚合函数)
FROM 表1 (LEFT / RIGHT) JOIN 表2 ON 多表的连接条件
(LEFT / RIGHT) JOIN 表2 ON 多表的连接条件2...
WHERE 不包含聚合函数的过滤条件
GROUP BY 分组字段1,分组字段2...
HAVING 包含聚合函数的过滤条件
ORDER BY 排序字段1,排序字段2...(ASC / DESC)
LIMIT 偏移量,条目数
2. SQL语句的执行过程
我们就以SQL99语法结构为例进行分析
- 首先执行FROM至HAVING范围内的语句
-
- 先根据 FROM 找出所需要的表,这里相当于之前说过的CROSS JOIN—> 然后根据ON后面的连接条件去除无法被关联的数据—> 判断是否是左/右外连接(LEFT / RIGHT JOIN) —> 根据WHERE过滤数据—> 根据 GROUP BY 分组(这一步之后,针对每组的聚合函数进行过滤才有了意义,这就能说得通为什么WHERE中不能使用聚合函数)—> 根据 HAVING 进行分组
- 然后执行 SELECT:执行完第一步会查出所有字段,这一步筛选出我们需要哪些字段,如果有DISTINCT关键字,那么还会进行去重
- 最后执行 ORDER BY 和 LIMIT:对上一步得到的结果集进行排序,然后再进行分页
常见函数四:流程函数
一、作用
流程函数也是很常用的一类函数,可以在SQL语句中实现条件筛选,从而提高语句的效率。
二、常见
函数 | 功能 |
IF(value , t , f) | 如果value为true,则返回t,否则返回f |
IFNULL(value1 , value2) | 如果value1不为空,返回value1,否则 返回value2 |
CASE WHEN [ val1 ] THEN [res1] ... ELSE [ default ] END | 如果val1为true,返回res1,... 否 则返回default默认值 |
CASE [ expr ] WHEN [ val1 ] THEN [res1] ... ELSE [ default ] END | 如果expr的值等于val1,返回res1,... 否则返回default默认值 |
三、SQL演示
1. if
select if(false, 'Ok', 'Error');
2. ifnull
select ifnull('Ok','Default');
select ifnull('','Default');
select ifnull(null,'Default');
3. case when then else end
需求:查询emp表的员工姓名和工作地址 (北京/上海 ----> 一线城市 , 其他 ----> 二线城市)
select
name,
( case workaddress when '北京' then '一线城市' when '上海' then '一线城市' else '二线城市' end ) as '工作地址'
from emp;
四、案例
create table score(
id int comment 'ID',
name varchar(20) comment '姓名',
math int comment '数学',
english int comment '英语',
chinese int comment '语文'
) comment '学员成绩表';
insert into score(id, name, math, english, chinese) VALUES (1, 'Tom', 67, 88, 95 ), (2, 'Rose' , 23, 66, 90),(3, 'Jack', 56, 98, 76);
具体的SQL语句如下
select
id,
name,
(case when math >= 85 then '优秀' when math >=60 then '及格' else '不及格' end ) '数学',
(case when english >= 85 then '优秀' when english >=60 then '及格' else '不及格' end ) '英语',
(case when chinese >= 85 then '优秀' when chinese >=60 then '及格' else '不及格' end ) '语文'
from score;
MySQL的常见函数我们学习完了,那接下来,我们就来分析一下,在前面讲到的两个函数的案例
场景,思考一下需要用到什么样的函数来实现?
- 数据库中,存储的是入职日期,如 2000-01-01,如何快速计算出入职天数呢? 答案: datediff
- 数据库中,存储的是学生的分数值,如98、75,如何快速判定分数的等级呢?答案:case ... when ...