【MySQL】函数


活动地址:CSDN21天学习挑战赛
作者简介:大家好我是狂暴于涛侠本侠
个人主页:狂暴于涛侠

MySQL的函数

  • MySQL函数的概述
    • 1. 聚合函数
    • 2. 数学函数
    • 3. 字符串函数
    • 4. 日期函数
    • 5. 控制流函数
    • 6. 窗口函数
      • 序号函数
      • 开窗聚合函数- SUM,AVG,MIN,MAX
      • 分布函数- CUME_DIST和PERCENT_RANK
      • 前后函数- LAG和LEAD
      • 头尾函数- FIRST_VALUE和LAST_VALUE
      • 其他函数-- NTH_VALUE(expr, n)、NTILE(n)

MySQL函数的概述

概述:
在MySQL中,为了提高代码重用性和隐藏实现细节,MySQL提供了很多函数。函数可以理解为别人封装好的模板代码。

  • 在MySQL中,函数非常多,主要可以分为以下几类:
  • 1. 聚合函数
  • 2. 数学函数
  • 3. 字符串函数
  • 4. 日期函数
  • 5. 控制流函数
  • 6. 窗口函数

1. 聚合函数

概述:

  1. 在MySQL中,聚合函数主要由:count,sum,min,max,avg,这些聚合函数我们之前都学过,不再重复。这里我们学习另外一个函数:group_concat ( ),该函数用户实现行的合并
  2. group_concat() 函数首先根据group by指定的列进行分组,并且用分隔符分隔,将同一个分组中的值连接起来,返回一个字符串结果。

语法:
group_concat([distinct] 字段名 [order by 排序字段 asc/desc] [separator ‘分隔符’])
说明:
  (1)使用distinct可以排除重复值;
  (2)如果需要对结果中的值进行排序,可以使用order by子句;
  (3)separator是一个字符串值,默认为逗号。

首先我们先创建一个表格

create database mydb4;
use mydb4;
 
create table emp(
    emp_id int primary key auto_increment comment '编号',
    emp_name char(20) not null default '' comment '姓名',
    salary decimal(10,2) not null default 0 comment '工资',
    department char(20) not null default '' comment '部门'
);
 
insert into emp(emp_name,salary,department) 
values('张晶晶',5000,'财务部'),('王飞飞',5800,'财务部'),('赵刚',6200,'财务部'),('刘小贝',5700,'人事部'),
('王大鹏',6700,'人事部'),('张小斐',5200,'人事部'),('刘云云',7500,'销售部'),('刘云鹏',7200,'销售部'),
('刘云鹏',7800,'销售部');

【MySQL】函数_第1张图片
接下来进行一些操作:

-- 将所有员工的名字合并成一行 
select group_concat(emp_name) from emp;

在这里插入图片描述


-- 指定分隔符合并
select group_concat(emp_name separator ';' ) from emp;

在这里插入图片描述


-- 指定排序方式和分隔符 
select department,group_concat(emp_name separator ';' ) from emp group by department; 

【MySQL】函数_第2张图片


-- 指定排序方式和分隔符 
select department,group_concat(emp_name order by salary desc separator ';' ) from emp group by department;

【MySQL】函数_第3张图片


2. 数学函数

【MySQL】函数_第4张图片
例子:

-- 求绝对值
selectabs ( -10);
selectabs (10);
selectabs(表示式或者字段) 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( ) ;

-- 取随机数在100以内的整数
select floor(rand() *100);

-- 将小数的四舍五入
select round( 3.5415);-- 4
-- 将小数的四舍五入,保留三位小数
select round( 3.5415);-- 3.542
 

-- 将小数直接截取到指定位数
select truncate(3.1415,3); -- 3.141

3. 字符串函数

【MySQL】函数_第5张图片
例子:

-- 字符串函数
-- 1:获取字符串字符个数
select char_length( ' hello' ); -- 5
select char_length('你好吗'); -- 3
-- length取长度,返回的单位是字节
select length( ' hello'); -- 5
select length('你好吗'); -- 9  每个汉字是3个字符
-- 2:字符串合并
select concat( ' hello' , 'world' );-- helloworld
select concat(c1,c2) from table_name;
-- 2:指定分隔符进行字符串合并
select concat_ws( '-', 'hello ' , ' world ' ) ; -- hello-world
-- 3:返回字符串在列表中第一次出现的位置
select field( 'aaa ' , 'aaa' , ' bbb ' , 'ccc'); -- 1
select field( ' bbb' , 'aaa ' , ' bbb' , 'ccc ' ); -- 2
-- 4:去除字符串左边空格
select ltrim( 'aaaa'); -- 去除左边空格
select rtrim( 'aaaa'); -- 去除右边空格
select trim( 'aaaa' ); -- 去除两端空格
-- 5:字符串截取
select mid("helloworld",2,3); -- 从第二个字符开始截取,截取长度为3
-- 6:获取字符串A在字符串B中第一次出现的位置
select position( 'abc' in 'habcelloabcworld ' );-- 2
-- 7:字符串替换
select replace( 'aaahelloaaaworld' , 'aaa' , 'bbb' );-- bbbhellobbbworld
-- 8:字符串翻转
select reverse( 'hello');-- olleh

-- 9:返回字符串的后几个字符
select right( 'hello',3); -- 返回最后三个字符 llo
-- 10:字符串比较
select strcmp( ' hello' , 'world ' );-- -1 和c语言一样也是先比较第一个不一样的字符然后看字符码
-- 11:字符串截取
select substr( 'hello',2,3); -- ell 			从第二个字符开始截取,截取三个字符
select substr( 'hello',2,3); -- ell			  从第二个字符开始截取,截取三个字符
-- 12:将小写转大写
select ucase ( "helloworld" );-- HELLOWORD
select upper( "helloworld" ) ;-- HELLOWORD
-- 13:将大写转为小写
select lcase( "HELLOWORD" );-- helloword
select lower("HELLOWORD" );-- helloword

4. 日期函数

【MySQL】函数_第6张图片
【MySQL】函数_第7张图片
【MySQL】函数_第8张图片

-- 日期函数
-- 1:获取时间戳(毫秒值)
select unix_timestamp();
-- 2:将一个日期字符串转为毫秒值
select unix_timestamp( '2021-12-21 08:08:08');
-- 3:将时间戳毫秒值转为指定格式的日期
select from_unixtime(1640045288, '%Y-%m-%d %H:%i:%s')-- %Y-%m-%d %H:%i:%s年月日时分秒
-- 4:获取当前的年月日
select curdate();
select current_date();
-- 5:获取当前的时分秒
SELECT CURRENT_TIME();SELECT CURTIME();
-- 6:获取年月日和时分秒
SELECT CURRENT_TIMESTAMP();
-- 7:从日期字符串中获取年月日
select date('2022-12-12 12:34:56');
-- 8:获取日期之间的差值
select datediff('2021-12-23','2008-08-08');
select datediff(current_date(),'2008-08-08');
-- 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
select date_format('2021-12-13 11:11:11','%Y-%m-%d %H:%i:%s');
-- 11:将字符串转为日期
select str_to_date('2021-12-13 11:11:11', '%Y-%m-%d %H:%i:%s');
-- 12:将日期进行减法 -- 日期向前跳转
select date_sub('2021-10-01' ,interval 2 day) ;select date_sub('2021-10-01',interval 2 month);
-- 13:将日期进行加法  -- 日期向后跳转
select date_add('2021-10-01',interval 2 day);
select date_add('2021-10-01',interval 2 month);
-- 14:从日期中获取小时
select extract(hour from '2021-12-13 11:12:13');
select extract(year from '2021-12-13 11:12:13');
select extract(month from '2021-12-13 11:12:13');
-- 15:获取给定日期所在月的最后一天
select last_day ('2021-08-13');-- 2021-08-31
-- 16:获取指定年份和天数的日期
select makedate( ' 2021',53);-- 2021-02-22
-- 17:根据日期获取年月日、时分秒
select year('2021-12-13 11:12:13' );
select month('2021-12-13 11:12:13');
select minute('2021-12-1311:12:13');
select quarter('2021-12-13 11:12:13');-- 4 				获取季度

-- 18:根据日期获取信息
SELECT MONTHNAME( '2021-12-13 11:12:13');-- 获取月份的英文
SELECT DAYNAME( '2021-12-13 11:12:13' ); -- 获取周几: Monday
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 WEEK( '2021-01-01 11:12:13');
SELECT WEEK( '2021-12-31 11:12:13' );
SELECT YEARWEEK( '2021-3-01');
SELECT NOW();

5. 控制流函数

【MySQL】函数_第9张图片

-- 控制流函数
-- IF
select if(5>3,'大于','小于');
select *,if(score >= 85, '优秀','及格') flag from score;

【MySQL】函数_第10张图片
下面是if语句:

-- IFNULL
select ifnull(5,0);  -- 5
select ifnul1(NULL,0);-- 0
select *,ifnull(comm,0) comm_flag from emp ;
-- ISNULL
select isnull(5); -- 0
select isnul1(NULL); -- 1
-- NULLIF
select nullif(12,12); -- null
select nullif(12,10); -- 12 返回第一个值  

下面是case语句:

create table orders(
oid int primary key, -- 订单id
price double, -- 订单价格
payType int -- 支付类型(1:微信支付2:支付宝支付3:银行卡支付4:其他)
);
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);

-- 方式1
select
  *,
case payType
		when 1 then '微信支付'
		when 2 then '支付宝支付'
		when 3 then '银行卡支付'
		else
		'其他支付方式'
end as payTypeStr
from orders;

-- 方式2
select
*,
case
when payType=1 then '微信支付'
when payType=2 then '支付宝支付'
when payType=3 then '银行卡支付'
else '其他支付方式'
end as payTypeStr
from orders;

【MySQL】函数_第11张图片

select -- 输出你好 2>1 对之后不会执行下面的
case
		when 2>1 then '你好'
		when 2<1 then 'hello'
		when 3>2 then '正确'
		else'其他'
end as info ;

6. 窗口函数

介绍:
MySQL 8.0 新增窗口函数,窗口函数又被称为开窗函数,与Oracle 窗口函数类似,属于MySQL的一大特点.
非聚合窗口函数是相对于聚函数来说的。聚合函数是对一组数据计算后返回单个值(即分组),非聚合函数一次只会处理一行数据。窗口聚合函数在行记录上计算某个字段的结果时,可将窗口范围内的数据输入到聚合函数中,并不改变行数。
【MySQL】函数_第12张图片
语法结构:
window_function ( expr ) OVER (
PARTITION BY …
ORDER BY …
frame_clause
)
其中,window_function 是窗口函数的名称;expr 是参数,有些函数不需要参数;OVER子句包含三个选项:

分区(PARTITION BY)
PARTITION BY选项用于将数据行拆分成多个分区(组),它的作用类似于GROUP BY分组。如果省略了 PARTITION BY,所有的数据作为一个组进行计算
排序(ORDER BY)
OVER 子句中的ORDER BY选项用于指定分区内的排序方式,与 ORDER BY 子句的作用类似
以及窗口大小(frame_clause)。
frame_clause选项用于在当前分区内指定一个计算窗口,也就是一个与当前行相关的数据子集。

序号函数

序号函数有三个:ROW_NUMBER()、RANK()、DENSE_RANK(),可以用来实现分组排序,并添加序号。

格式:
row_number()|rank()|dense_rank() over (
partition by … - -按照什么分组
order by … - -每组按照什么排序
)

我们先创建一个表:

use mydb4; 
create table employee( 
   dname varchar(20), -- 部门名 
   eid varchar(20), 
   ename varchar(20), 
   hiredate date, -- 入职日期 
   salary double -- 薪资
); 
insert into employee values('研发部','1001','刘备','2021-11-01',3000);
insert into employee values('研发部','1002','关羽','2021-11-02',5000);
insert into employee values('研发部','1003','张飞','2021-11-03',7000);
insert into employee values('研发部','1004','赵云','2021-11-04',7000);
insert into employee values('研发部','1005','马超','2021-11-05',4000);
insert into employee values('研发部','1006','黄忠','2021-11-06',4000);

insert into employee values('销售部','1007','曹操','2021-11-01',2000);
insert into employee values('销售部','1008','许褚','2021-11-02',3000);
insert into employee values('销售部','1009','典韦','2021-11-03',5000);
insert into employee values('销售部','1010','张辽','2021-11-04',6000);
insert into employee values('销售部','1011','徐晃','2021-11-05',9000);
insert into employee values('销售部','1012','曹洪','2021-11-06',6000);
-- 对每个部门的员工按照薪资排序,并给出排名       rn1
-- 对每个部门的员工按照薪资排序,并给出排名 rank  rn2
-- 对每个部门的员工按照薪资排序,并给出排名 dense-rank  rn3
select 
dname,
ename,
salary,
row_number() over(partition by dname order by salary desc) as rn1,-- 就算salary一样还是分出第一第二
rank() over(partition by dname order by salary desc) as rn2,-- 就算salary一样不分出第一第二但是没有第二而是直接第三
dense_rank() over(partition by dname order by salary desc) as rn3-- salary一样并列第一还是会有第二
from employee;

【MySQL】函数_第13张图片

-- 求出每个部门薪资排在前三名的员工- 分组求TOPN
--首先下面这个方法可以么?
select 
     dname,
     ename,
     salary,
     dense_rank() over(partition by dname order by salary desc)  as rn
    from employee,
where rn <= 3;
-- 要知道是先执行from employee,后立刻执行where,但是此时根本不知道rn是什么根本没办法编译成功

-- 所以我们应该改成下面这种写法
select 
* 
from -- 先执行form
(
    select 
     dname,
     ename,
     salary,
     dense_rank() over(partition by dname order by salary desc)  as rn,-- 这里只是拿dense_rank()来示范而已
    from employee
)t
where t.rn <= 3; -- from后执行where

【MySQL】函数_第14张图片

-- 对所有员工进行全局排序(不分组)
-- 不加partition by表示全局排序
select 
     dname,
     ename,
     salary,
     dense_rank() over( order by salary desc)  as rn
from employee;

【MySQL】函数_第15张图片

开窗聚合函数- SUM,AVG,MIN,MAX

概念:
在窗口中每条记录动态地应用聚合函数(SUM()、AVG()、MAX()、MIN()、COUNT()),可以动态计算在指定的窗口内的各种聚合函数值。

select  
 dname,
 ename,
 hiredate,
 salary,
 sum(salary) over(partition by dname order by hiredate) as pv1 -- 默认从第一行加到当前行
from employee;

【MySQL】函数_第16张图片


select  
 dname,
 ename,
 hiredate,
 salary,
sum(salary) over(partition by dname) as pv3
from employee;  -- 如果没有order  by排序语句  默认把分组内的所有数据进行sum操作

【MySQL】函数_第17张图片


select  
 dname,
 ename,
 salary,
 sum(salary) over(partition by dname order by hiredate  rows between unbounded preceding and current row) as c1 
 -- rows between unbounded preceding and current row的意思是从默认开始行加到当前行
from employee;

【MySQL】函数_第18张图片


select  
 dname,
 ename,
 salary,
 sum(salary) over(partition by dname order by hiredate   rows between 3 preceding and current row) as c1
  -- rows between 3 preceding and current row从上面三行加到当前行
from employee;

【MySQL】函数_第19张图片


select  
 dname,
 ename,
 salary,
 sum(salary) over(partition by dname order by hiredate   rows between 3 preceding and 1 following) as c1 
 -- rows between 3 preceding and 1 following上面三行加当前行加下面一行
from employee;

【MySQL】函数_第20张图片


select  
 dname,
 ename,
 salary,
 sum(salary) over(partition by dname order by hiredate   rows between current row and unbounded following) as c1 
 -- rows between current row and unbounded following当前行加到最后
from employee;

【MySQL】函数_第21张图片


分布函数- CUME_DIST和PERCENT_RANK

介绍-CUME_DIST
用途:分组内小于、等于当前rank值的行数 / 分组内总行数
应用场景:查询小于等于当前薪资(salary)的比例

select  
 dname,
 ename,
 salary,
 cume_dist() over(order by salary) as rn1, -- 没有partition语句 所有的数据位于一组
 cume_dist() over(partition by dname order by salary) as rn2 
from employee;
操作
/*
rn1: 没有partition,所有数据均为1组,总行数为12,
     第一行:小于等于3000的行数为3,因此,3/12=0.25
     第二行:小于等于4000的行数为5,因此,5/12=0.4166666666666667
rn2: 按照部门分组,dname='研发部'的行数为6,
     第一行:研发部小于等于3000的行数为1,因此,1/6=0.16666666666666666
*/

【MySQL】函数_第22张图片


介绍-PERCENT_RANK
用途:每行按照公式(rank-1) / (rows-1)进行计算。其中,rank为RANK()函数产生的序号,rows为当前窗口的记录总行数
应用场景:不常用

select 
 dname,
 ename,
 salary,
 rank() over(partition by dname order by salary desc ) as rank值,
 percent_rank() over(partition by dname order by salary desc ) as rn2
from employee;

/*
   当前rank值-1 / 总行数-1
 rn2:
  第一行: (1 - 1) / (6 - 1) = 0
  第二行: (1 - 1) / (6 - 1) = 0
  第三行: (3 - 1) / (6 - 1) = 0.4
*/

【MySQL】函数_第23张图片


前后函数- LAG和LEAD

介绍
用途:返回位于当前行的前n行(LAG(expr,n))或后n行(LEAD(expr,n))的expr的值
应用场景:查询前1名同学的成绩和当前同学成绩的差值

-- lag的用法
select 
 dname,
 ename,
 hiredate,
 salary,
 lag(hiredate,1,'2000-01-01') over(partition by dname order by hiredate) as last_1_time,
 --  2000-01-01是自己设定的默认值,如果不设置默认为null
 lag(hiredate,2) over(partition by dname order by hiredate) as last_2_time 
from employee;
/*
last_1_time: 指定了往上第1行的值,default为'2000-01-01'  
                         第一行,往上1行为null,因此取默认值 '2000-01-01'
                         第二行,往上1行值为第一行值,2021-11-01 
                         第三行,往上1行值为第二行值,2021-11-02 
last_2_time: 指定了往上第2行的值,为指定默认值
                         第一行,往上2行为null
                         第二行,往上2行为null
                         第四行,往上2行为第二行值,2021-11-01 
                         第七行,往上2行为第五行值,2021-11-02 
                         。。。
*/

【MySQL】函数_第24张图片


-- lead的用法
select 
 dname,
 ename,
 hiredate,
 salary,
 lead(hiredate,1,'2000-01-01') over(partition by dname order by hiredate) as last_1_time,
 lead(hiredate,2) over(partition by dname order by hiredate) as last_2_time 
from employee;

【MySQL】函数_第25张图片


头尾函数- FIRST_VALUE和LAST_VALUE

介绍
用途:返回第一个(FIRST_VALUE(expr))或最后一个(LAST_VALUE(expr))expr的值
应用场景:截止到当前,按照日期排序查询第1个入职和最后1个入职员工的薪资

-- 注意,  如果不指定ORDER BY,则进行排序混乱,会出现错误的结果
select
  dname,
  ename,
  hiredate,
  salary,
  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;
/*
   first_value(salary)是开始时的薪资
	 last_value(salary)是到本行为止最后一个位置的薪资
*/

【MySQL】函数_第26张图片


其他函数– NTH_VALUE(expr, n)、NTILE(n)

介绍-NTH_VALUE(expr,n)
用途:返回窗口中第n个expr的值。expr可以是表达式,也可以是列名
应用场景:截止到当前薪资,显示每个员工的薪资中排名第2或者第3的薪资

-- 查询每个部门截止目前薪资排在第二和第三的员工信息
select 
  dname,
  ename,
  hiredate,
  salary,
  nth_value(salary,2) over(partition by dname order by salary) as second_score,
  nth_value(salary,3) over(partition by dname order by salary) as third_score
from employee

【MySQL】函数_第27张图片


介绍–NTILE
用途:将分区中的有序数据分为n个等级,记录等级数
应用场景:将每个部门员工按照入职日期分成3组

-- 根据入职日期将每个部门的员工分成3组
select 
  dname,
  ename,
  hiredate,
  salary,
ntile(3) over(partition by dname order by  hiredate  ) as rn ,
ntile(4) over(partition by dname order by  hiredate  ) as rn 
-- 如果分组不能整除会先正常算最后按单个算
from employee;

【MySQL】函数_第28张图片



-- 取出每个部门的第一组员工
select
*
from
(
    SELECT 
        dname,
        ename,
        hiredate,
        salary,
    NTILE(3) OVER(PARTITION BY dname ORDER BY  hiredate  ) AS rn 
    FROM employee
)t
where t.rn = 1;

【MySQL】函数_第29张图片


你可能感兴趣的:(MySQL,mysql,数据库,java)