一.介绍
1.在MySQL中,为了提高代码重用性和隐藏实现细节,MySQL提供了很多函数。函数可以理解为别人封装好的模板代码。
2.分类:聚合函数,数学函数,字符串函数,日期函数,控制流函数,窗口函数
二:聚合函数
-- 数学函数
-- 求绝对值
select abs(-10); -- 10
select abs(10); -- 10
select abs(表达式或者字段) from 表;
-- 向上取整
select ceil(1.1); -- 2
select ceil(1.0); -- 1
-- 向下取整
select floor(1.1); -- 1
select floor(1.9); -- 1
-- 取列表最大值
select greatest(1,2,3); -- 3
-- 取列表最小值
select least(1,2,3); -- 1
-- 取模
select mod(5,2); -- 1
-- 取x的y次方
select power(2,3); -- 8
-- 取随机数
select rand(); -- 0.0005110669885865105
-- 将小数四舍五入取整
select round(3.5415); -- 4
select round(3.5415,3); -- 保留三位小数 3.542
select category_id,round(avg(price),2) from product group by category_id;
-- 将小数直接截取到指定位数
select truncate(3.1415,3); -- 3.141
四:字符串函数
-- 字符串函数
-- 1.获取字符串字符个数
select char_length('hello'); -- 5
select char_length('你好啊'); -- 3
-- length 取长度,返回的单位是字节
select length('hello'); -- 5
select length('你好啊'); -- 9
-- 2.字符串合并
select concat('hello','world');
select concat(c1,c2) from table_name;
-- 3.指定分隔符进行字符串合并
select concat_ws('-','hello','world');-- hello-world
-- 4.返回字符串在列表中的位置
select field('aaa','aaa','bbb','ccc'); -- 1
select field('bbb','aaa','bbb','ccc'); -- 2
select field('aaa','aaa','aaa','bbb','ccc'); -- 1 返回在列表中第一次出现的位置
-- 5.去除字符串空格
select ltrim(' aaaa'); -- 去除左边空格
select rtrim('aaaa '); -- 去除右边空格
select trim(' aaaa '); -- 去除两边空格
-- 6.字符串截取
select mid('helloworld',2,3); -- 从第二个字符开始截取,截取长度为3 ell
-- 7.获取字符串在另一个字符串中出现的位置
select position('abc' in 'habcelloabcworld'); -- 2 截取出现的第一个位置
-- 8.字符串替换
select replace('aaahelloaaaworld','aaa','bbb');-- bbbhellobbbworld
-- 9. 字符串翻转
select reverse('hello'); -- olleh
-- 10.返回字符串的后几个字符
select right('hello',3); -- 返回后三个字符 llo
-- 11.字符串比较
select strcmp('hello','world'); -- -1
-- 12.字符串截取
select substr('hello',2,3); -- 从第二个字符开始截取,截取长度为3 ell
-- 13.将小写转化为大写
select ucase('helloworld');
select upper('helloworld'); -- HELLOWORLD
-- 14.将大写转化为小写
select lcase('HELLOWORLD');
select lower('HELLOWORLD'); -- helloworld
五:日期函数
-- 日期函数
-- 1.获取时间戳(毫秒值)
select unix_timestamp();
-- 2.将一个日期字符串转为毫秒值
select unix_timestamp('2021-12-21 08:08:08');-- 1640045288
-- 3.将时间戳毫秒值转为指定格式的日期
select from_unixtime(1640045288,'%Y-%m-%d %H:%i:%s');-- 2021-12-21 08:08:08
-- 4.获取当前的年月日
select curdate();
select current_date(); -- 2024-01-29
-- 5.获取当前的时分秒
select current_time();
select curtime(); -- 18:42:09
-- 6.获取年月日和时分秒
select current_timestamp(); -- 2024-01-29 18:47:12
-- 7.从日期字符串中获取年月日
select date('2022-12-12 12:34:56'); -- 2022-12-12
-- 8.获取日期之间的差值
select datediff('2021-12-23','2008-08-08'); -- 4885
-- 9.获取时间之间的差值(秒级)
select timediff('12:12:34','10:18:56'); -- 01:53:38
-- 10.日期格式化
select date_format('2021-1-1 1:1:1','%Y-%m-%d %H:%i:%s');-- 2021-01-01 01:01:01
-- 11.将字符串转为日期
select str_to_date('August 10 2017','%M%d%Y'); -- 2017-08-10
-- 12.将日期进行减法(日期向前跳转)
select date_sub('2021-10-01',interval 2 day); -- 2021-09-29
select date_sub('2021-10-01',interval 2 month); -- 2021-08-01
-- 13.将日期进行加法(日期向后跳转)
select date_add('2021-10-01',interval 2 day); -- 2021-10-03
select date_add('2021-10-01',interval 2 month); -- 2021-12-01
-- 14.从日期中获取相关数据
select extract(hour from '2021-12-13 11:12:12'); -- 11
select extract(month from '2021-12-13 11:12:12');-- 12
select extract(year from '2021-12-13 11:12:12'); -- 2021
-- 15.获取给定日期所在月的最后一天
select last_day('2021-08-13'); -- 2021-08-31
-- 16.获取指定年份和天数的日期
select makedate('2021',53); -- 2021年的第53天:2021-02-22
-- 17.从日期中获取相关数据
select year('2021-12-13 11:12:12'); -- 2021
select month('2021-12-13 11:12:12'); -- 12
select hour('2021-12-13 11:12:12'); -- 11
select quarter( '2021-12-13 11:12:12'); -- 获取季度:4
-- 18.根据日期获取信息
select monthname('2021-12-13 11:12:13'); -- 获取月份英文
select dayname('2021-12-13 11:12:13'); -- 获取周几英文
select dayofmonth('2021-12-13 11:12:13'); -- 当月的第几天
select dayofweek('2021-12-13 11:12:13'); -- 获取周几,1表示周日,2表示周一
select dayofyear('2021-12-13 11:12:13'); -- 获取一年的第几天
select week('2021-12-13 11:12:13'); -- 获取一年的第几周
select yearweek('2021-3-1'); -- 获取某年的第几周202109
select now(); -- 获取当前时间
六:控制流函数
(1)if逻辑判断语句
-- IF
select if(5>3,'大于','小于'); -- 条件满足,返回第一个字段,不满足,返回第二个字段
select *,if(score>=85,'优秀','及格')flag from score;
-- IFNULL
select ifnull(5,0); -- 第一个字段为null,则当作0处理,否则就返回其本身
select ifnull(null,0);
select *,ifnull(cumm,0) comm_flag from emp;
-- ISNULL
select isnull(5); -- 不为null,返回0;为null,返回1
select isnull(null);
-- NULLIF
select nullif(12,12); -- 相等返回null,不相等返回第一个字段
select nullif(12,13);
(2)case when 语句
use mydb1;
-- 创建订单表
create table orders(
oid int primary key, -- 订单id
price double, -- 订单价格
payType int -- 支付方式
);
insert into orders values(1,1200,1);
insert into orders values(2,1000,2);
insert into orders values(3,200,3);
insert into orders values(4,3000,1);
insert into orders values(5,1500,2);
-- 方式一
select
*,
case payType
when 1 then '微信支付'
when 2 then '支付宝支付'
when 3 then '银行卡支付'
else
'其他支付方式'
end as payTypeStr
from orders;
-- 方式二
select
*,
case
when payType=1 then '微信支付'
when payType=2 then '支付宝支付'
when payType=3 then '银行卡支付'
else
'其他支付方式'
end as payTypeStr
from orders;
七:窗口函数
4.序号函数
-- 求出每个部门薪资排在前三名的员工-分组求TOPN
select *
from
(
select
dname,
ename,
salary,
dense_rank() over(partition by dname order by salary desc) as rn
from employee
) t
where t.rn<=3
-- 对所有员工进行排序(不分组)
-- 不加partition表示全局排序
select
dname,
ename,
salary,
dense_rank() over(order by salary desc)as rn
from employee;
5.开窗聚合函数
(1)概念
在窗口中每条记录动态地应用聚合函数( sun(),avg(),max(),min(),count() ),可以动态计算在指定的窗口内的各种聚合函数值
(2)操作
select
dname,
ename,
salary,
sum(salary) over(partition by dname order by hiredate)as pv1
from employee;
select
dname,
ename,
salary,
sum(salary) over(partition by dname )as pv1
from employee; -- 如果没有order by 排序语句 默认把分组内的所有数据进行sum操作
select
dname,
ename,
hiredate,
salary,
sum(salary) over(partition by dname order by hiredate rows between unbounded preceding and current row)as c1
from employee;-- 从开头行加到现在行
select
dname,
ename,
salary,
sum(salary) over(partition by dname order by hiredate rows between 3 preceding and current row)as c1
from employee;-- 现在行的前三行加上现在行
select
dname,
ename,
salary,
sum(salary) over(partition by dname order by hiredate rows between 3 preceding and 1 following)as c1
from employee;-- 现在行的前三行加上现在行加上现在行的后一行
select
dname,
ename,
salary,
sum(salary) over(partition by dname order by hiredate rows between current row and undounded following)as c1
from employee;-- 从当前行加到最后
6.分布函数
(1)cume_dist()
用途:分组内小于,等于当前rank值的行数/分组内总行数
应用场景:查询小于等于当前薪资(salary)的比例
select
dname,
ename,
salary,
cume_dist() over( order by salary)as c1,
cume_dist() over(partition by dname order by salary)as c2
from employee;
/*c1:(不加partition by,不分组)
第一个:salary少于等于3000的有3个人,总共12个人
3/12=0.25
c2:(加partition by,分组)
研发部第一个:salary少于等于3000的有1个人,总共6个人
1/6=0.16666666667
*/
(2)percent_rank()
用途:每行按照公式(rank-1)/(rows-1)进行计算,其中,rank为rank()函数产生的序号,rows为当前窗口的记录总数
select
dname,
ename,
salary,
rank() over(partition by dname order by salary desc)as rn,
percent_rank() over(partition by dname order by salary)as rn2
from employee;
/*
rn2:
第一行:(1-1)/(6-1)= 0
第二行:(1-1)/(6-1)= 0
第三行:(2-1)/(6-1)= 0.4
*/
7.前后函数(lag和lead)
用途:返回位于当前行的前n行(lag(expr,n))或后n行(lead(expr,n))的expr的值
应用场景:查询前1名同学的成绩和当前同学成绩的差值
select
dname,
ename,
salary,
hiredate,
lag(hiredate,1,'2000-01-01') over(partition by dname order by hiredate )as time1,
-- 返回上一行的内容,没有值时默认为2000-01-01
lag(hiredate,2) over(partition by dname order by hiredate)as time2
-- 返回上两行的内容,没有值时为null
from employee;
select
dname,
ename,
salary,
hiredate,
lead(hiredate,1,'2000-01-01') over(partition by dname order by hiredate )as time1,
-- 返回下一行的内容,没有值时默认为2000-01-01
lead(hiredate,2) over(partition by dname order by hiredate)as time2
-- 返回下两行的内容,没有值时为null
from employee;
8.头尾函数(first_value和last_value)
用途:返回第一个(first_value)或最后一个(last_value)expr的值
应用场景:截至到当前,按照日期排序查询第1个入职和最后1个入职员工的薪资
select
dname,
ename,
salary,
hiredate,
first_value(salary) over(partition by dname order by hiredate )as first,
last_value(salary) over(partition by dname order by hiredate)as last
from employee;
9.其他函数
(1)nth_value(expr,n)
用途:返回窗口中第n个expr的值,expr可以是表达式,也可以是列名
应用场景:截至到当前薪资,显示每个员工的薪资中排名第2或者第3的薪资
select
dname,
ename,
salary,
hiredate,
nth_value(salary,2) over(partition by dname order by hiredate )as second_salary,
-- 从当前行开始,排名的2的薪资
nth_value(salary,3) over(partition by dname order by hiredate)as third_salary
-- 从当前行开始,排名的3的薪资
from employee;
(2)ntile(n)
用途:将分区中的有序数据分为n个等级,记录等级数
应用场景:将每个部门员工按照入职日期分为3组
select
dname,
ename,
salary,
hiredate,
ntile(3) over(partition by dname order by hiredate)as nt
from employee;
-- 取出每个部门的第一组员工
select
*
from(
select
dname,
ename,
salary,
hiredate,
ntile(3) over(partition by dname order by hiredate)as nt
from employee
)t
where t.nt = 1;