文章目录
- 第六章:
- 6.函数
- 6.1 聚合函数
- 6.2 数学函数
- 6.3 字符串函数
- 6.4 日期函数
- 6.4.1 日期格式
- 6.5 控制流函数
- 6.5.1 if逻辑判断语句
- 6.5.2 case when语句
- 6.6 窗口函数
- 6.6.1 序号函数
- 6.6.2 开窗聚合函数
- 6.6.3 分布函数
- 6.6.4 前后函数
- 6.6.5 头尾函数
- 6.6.6 其他函数
- 6.7 练习
第六章:
6.函数
作用:提高代码重用性和隐藏实现细节
分类:
-
聚合函数
-
数学函数
-
字符串函数
-
日期函数
-
控制流函数
-
窗口函数
6.1 聚合函数
- group_concat()
作用:根据group by指定的列进行分组,并用分隔符分隔,将同一个分组中的值连接起来,返回一个字符串结果,实现行的合并
语法:group_concat ([distinct] 字段名 [order by 排序字段 asc/desc] [separator ‘分隔符’] )
separator为一个字符串值,默认为逗号

6.2 数学函数
| 函数名 | 功能 |
|---|---|
| ABS(x) | 返回x的绝对值 |
| CEIL(x) | 返回大于或等于x的最小整数 |
| FLOOR(x) | 返回小于或等于x的最大整数 |
| GREATEST(expr1, expr2, expr3, …) | 返回列表中的最大值 |
| LEAST(expr1, expr2, expr3, …) | 返回列表中的最小值 |

| 函数名 | 功能 |
|---|---|
| MAX(expression) | 返回字段expression中的最大值 |
| MIN(expression) | 返回字段expression中的最小值 |
| MOD(x,y) | 返回x除以y后的余数 |
| PI() | 返回圆周率 3.141593 |
| POW(x,y) | 返回x的y次方 |

| 函数名 | 功能 |
|---|---|
| RAND() | 返回0到1的随机值 |
| ROUND(x) | 返回离x最近的整数,遵循四舍五入规则 |
| ROUND(x,y) | 返回指定位数的小数,遵循四舍五入规则 |
| TRUNCATE(x,y) | 返回数值x保留到小数点后y位的值,不遵循四舍五入规则 |

6.3 字符串函数
| 函数名 | 功能 |
|---|---|
| CHAR_LENGTH(s) | 返回字符串s的字符数 |
| CHARACTER_LENGTH(s) | 返回字符串s的字符数 |
| CONCAT(s1,s2,s3,…) | s1,s2等多个字符串合并成一个字符串 |
| CONCAT_WS(s1,s2,s3,…) | 同CONCAT函数,每个字符串之间加上x,x可以是分隔符 |
| FIELD(s,s1,s2,s3,…) | 返回第一个字符串s在字符串列表(s1,s2,…)中的位置 |

| 函数名 | 功能 |
|---|---|
| LTRIM(s) | 去除字符串s开始处的空格 |
| MID(s,n,len) | 从字符串s的n位置开始截取长度为len的子字符串,同SUBSTRING函数 |
| POSITION(s1 IN s) | 从字符串s中获取s1的开始位置 |
| REPLACE(s,s1,s2) | 字符串s2替代字符串s中的字符串s1 |
| REVERSE(s) | 字符串s的顺序反过来 |

| 函数名 | 功能 |
|---|---|
| RIGHT(s,n) | 返回字符串s的后n个字符 |
| RTRIM(s) | 去除字符串s结尾处的空格 |
| STRCMP(s1,s2) | 比较s1和s2,若相等返回0,s1>s2返回1,s1<s2返回-1 |
| SUBSTR(s,start,len) | 从字符串s的start位置开始截取长度为len的子字符串 |
| SUBTRING(s,start,len) | 从字符串s的start位置开始截取长度为len的子字符串 |

| 函数名 | 功能 |
|---|---|
| TRIM(s) | 去除字符串s开始和结尾处的空格 |
| UCASE(s) | 字符串转换为大写 |
| UPPER(s) | 字符串转换为大写 |
| LCASE(s) | 字符串转换为小写 |
| LOWER(s) | 字符串转换为小写 |

6.4 日期函数
| 函数名 | 功能 |
|---|---|
| UNIX_TIMESTAMP() | 返回从1970-01-01 00:00:00到当前毫秒值 |
| UNIX_TIMESTAMP(DATE_STRING) | 将制定日期转为毫秒值时间戳 |
| FROM_UNIXTIME(BIGINT UNIXTIME[, STRING FORMAT]) | 将毫秒值时间戳转为指定格式日期 |
| CURDATE() | 返回当前日期 |
| CURRENT_DATE() | 返回当前日期 |

| 函数名 | 功能 |
|---|---|
| TIMEDIFF(time1, time2) | 计算时间差值 |
| DATE_FORMAT(d, f) | 按表达式f的要求显示日期d |
| STR_TO_DATE(string, format_mask) | 将字符串转为日期 |
| DATE_SUB(date, INTERVAL expr type) | 函数从日期减去指定的时间间隔 |
![]() |

6.4.1 日期格式
| 描述 | 描述 |
|---|---|
| %a | 缩写星期名 |
| %b | 缩写月名 |
| %c | 月,数值 |
| %D | 带有英文前缀的月中的天 |
| %d | 月的天,数值(00-31) |
| %e | 月的天,数值(0-31) |
| %f | 微秒 |
| %H | 小时(00-23) |
| %h | 小时(01-12) |
| %I | 小时(01-12) |
| %i | 分钟,数值(00-59) |
| %j | 年的天(001-366) |
| %k | 小时(0-23) |
| %l | 小时(1-12) |
| %M | 月名 |
| %m | 月,数值(00-12) |
| %p | AM 或 PM |
| %r | 时间,12-小时(hh:mm:ss AM 或PM) |
| %S | 秒(00-59) |
| %s | 秒(00-59) |
| %T | 时间,24-小时(hh:mm:ss) |
| %U | 周(00-53)星期日是一周的第一天 |
| %u | 周(00-53)星期一是一周的第一天 |
| %V | 周(01-53)星期日是一周的第一天,与%X使用 |
| %v | 周(01-53)星期一是一周的第一天,与%x使用 |
| %W | 星期名 |
| %w | 周的天(0=星期日, 6=星期六) |
| %X | 年,其中的星期日是周的第一天,4位,与%V使用 |
| %x | 年,其中的星期一是周的第一天,4位,与%v使用 |
| %Y | 年,4位 |
| %y | 年,2位 |
6.5 控制流函数
6.5.1 if逻辑判断语句
| 格式 | 含义 |
|---|---|
| IF(expr, v1, v2) | 若表达式expr成立,返回结果v2,否则返回结果v2 |
| IFNULL(v1, v2) | 若v1的值不为NULL,返回v1,否则返回v2 |
| ISNULL(expression) | 判断表达式是否为NULL |
| NULLIF(expr1, expr2) | 若字符串expr1与expr2字符串相等返回NULL,否则返回expr1 |

6.5.2 case when语句
格式:
CASE expression
WHEN conditon1 THEN result1
WHEN conditon2 THEN result2
....
WHEN conditonN THEN resultN
ELSE result
END
含义:CASE表示函数开始,END表示函数结束。若condition1成立,返回result1,condition2成立,返回result2,当全部不成立返回result,而当有一个成立后,后面将不再执行

6.6 窗口函数
窗口函数又被称为开窗函数。
非聚合窗口函数对于聚合函数来说,聚合函数是一组数据计算后返回单个值,非聚合函数一次指挥处理一行数据。窗口聚合函数在行记录上计算某个字段的结果时,可将窗口范围内的数据输入到聚合函数中,并不改变行数。



语法:
windows_function (expr) OVER(
PARTITION BY ...
ORDER BY ...
frame_clause
)
-
windows_function:窗口函数名
-
expr:参数
-
OVER:包含三个选项
-
分区(PARTITION BY):用于将数据行拆分成多个分区。若省略PARTITION BY,所有数据作为一个组进行计算
-
排序(ORDER BY):用于指定分区内的排序方式
-
窗口大小(frame_clause):用于在当前分区内指定一个计算窗口
6.6.1 序号函数
-
ROW_NUMBER()
-
RANK()
-
DENSE_RANK()
作用:实现分组排序,并添加序号
语法:
row_number() | rank() | dense_rank() over(
partition by ...
order by ...
)
create table emp(
dname varchar(20),
ename varchar(20),
eid varchar(20),
sal double
);
insert into emp values('技术部', '101', 'xiaoming', '3500');
insert into emp values('技术部', '101', 'xiaowang', '4000');
insert into emp values('技术部', '101', 'xiaoli', '3600');
insert into emp values('运营部', '102', 'xiaohua', '3000');
insert into emp values('运营部', '102', 'xiaohong', '3100');
insert into emp values('运营部', '102', 'xiaolu', '3300');
-- 对每个部门员工按薪资排序,给出排名
select dname,ename,sal,
row_number() over(partition by dname order by sal desc) as rn1,
rank() over(partition by dname order by sal desc) as rn2,
dense_rank() over(partition by dname order by sal desc) as rn3
from emp;
-- 求出每个部门薪水排前两名的员工,分组求TOPN
select * from (select dname,ename,sal, dense_rank() over(partition by dname order by sal desc) as rn from emp)t where t.rn <= 2;
-- 对所有员工进行全局排序
select dname,ename,sal,dense_rank() over(partition by dname order by sal desc) as rn from emp;
6.6.2 开窗聚合函数
SUM, AVG, MIN, MAX
- 在窗口中每条记录动态地应用聚合函数,可动态计算在指定地窗口内的各种聚合函数值
create table emp(
dname varchar(20),
ename varchar(20),
eid varchar(20),
sal double
);
insert into emp values('技术部', '101', 'xiaoming', '3500');
insert into emp values('技术部', '101', 'xiaowang', '4000');
insert into emp values('技术部', '101', 'xiaoli', '3600');
insert into emp values('运营部', '102', 'xiaohua', '3000');
insert into emp values('运营部', '102', 'xiaohong', '3100');
insert into emp values('运营部', '102', 'xiaolu', '3300');
-- 对每个部门员工按薪资排序,给出排名
select dname,ename,sal,
row_number() over(partition by dname order by sal desc) as rn1,
rank() over(partition by dname order by sal desc) as rn2,
dense_rank() over(partition by dname order by sal desc) as rn3
from emp;
-- 求出每个部门薪水排前两名的员工,分组求TOPN
select * from (select dname,ename,sal, dense_rank() over(partition by dname order by sal desc) as rn from emp)t where t.rn <= 2;
-- 对所有员工进行全局排序
select dname,ename,sal,dense_rank() over(partition by dname order by sal desc) as rn from emp;
-- 若没有ORDER BY排序语句, 默认把分组内所有数据进行sum操作
select dname,ename,sal,sum(sal) over(partition by dname order by sal desc) as p1 from emp;
select dname,ename,sal,sum(sal) over(partition by dname ) as p2 from emp;
select dname,ename,sal,sum(sal) over(partition by dname rows between 3 preceding and current row) as p3 from emp;
select dname,ename,sal,sum(sal) over(partition by dname rows between 3 preceding and 1 following) as p4 from emp;
select dname,ename,sal,sum(sal) over(partition by dname rows between current row and unbounded following) as p5 from emp;
select dname,ename,sal,max(sal) over(partition by dname order by sal desc) as p5 from emp;
6.6.3 分布函数
CUME_DIST 和 PERECENT_RANK
- CUME_DIST:用于分组内小于、等于当前rank值的行数/分组内总行数,应用于查询小于等于当前薪资(sal)比例
create table emp(
dname varchar(20),
ename varchar(20),
eid varchar(20),
sal double
);
insert into emp values('技术部', '101', 'xiaoming', '3500');
insert into emp values('技术部', '101', 'xiaowang', '4000');
insert into emp values('技术部', '101', 'xiaoli', '3600');
insert into emp values('技术部', '101', 'xiaoni', '3500');
insert into emp values('技术部', '101', 'xiaona', '3400');
insert into emp values('技术部', '101', 'xiaone', '3300');
insert into emp values('技术部', '101', 'xiaonl', '3200');
insert into emp values('运营部', '102', 'xiaohua', '3000');
insert into emp values('运营部', '102', 'xiaohong', '3100');
insert into emp values('运营部', '102', 'xiaolu', '3300');
insert into emp values('运营部', '102', 'xiaolo', '3800');
insert into emp values('运营部', '102', 'xiaola', '3700');
insert into emp values('运营部', '102', 'xiaole', '3600');
insert into emp values('运营部', '102', 'xiaolt', '3000');
select dname,ename,sal,
cume_dist() over(order by sal) as rn1, -- 没有partition语句 所有数位于一组
cume_dist() over(partition by ename order by sal) as rn2
from emp;
- PERECENT_RANK:用于每行按照公式(rank-1) / (rows-1)进行计算,rank为rank()函数产生的序号,rows为当前窗口的记录总行数。不常用。
select dname,ename,sal,
rank() over(partition by dname order by sal desc) as rn,
percent_rank() over(partition by dname order by sal desc) as rn2
from emp;
6.6.4 前后函数
LAG和LEAD
- 用于返回位于当前行的前n行(LAG(expr, n)或后n行(LEAD(expr, n)的expr值,应用于查询前1名同学的成绩和当前同学成绩的差值
-- LAG
select dname,ename,sal,
lag(sal,1,3500) over(partition by dname order by sal ) as last_1_sal,
lag(sal,2) over(partition by dname order by sal ) as last_2_sal
from emp;
-- LEAD
select dname,ename,sal,
lead(sal,1,3500) over(partition by dname order by sal ) as last_1_sal,
lead(sal,2) over(partition by dname order by sal ) as last_2_sal
from emp;
6.6.5 头尾函数
FIRST_VALUE和LAST_VALUE
- 用于返回第一个(FIRST_VALUE)或最后一个(LAST_VALUE)的expr值。应用于截止到目前,按入职编号排序查询第一个入职和最后一个入职的员工薪资
select dname, ename, sal, eid, -- 若不指定order by 将会排序混乱,出现错误的结果
first_value(sal) over(partition by dname order by eid) as first,
last_value(sal) over(partition by dname order by eid) as last
from emp;
6.6.6 其他函数
NTH_VALUE(expr, n)和NTILE(n)
- 用于返回窗口中第n个expr值。应用于截止到当前薪资,显示每个员工中薪资排第2或3的薪资
-- NTH_VALUE()
-- 查询各部门截止目前薪资排第2或3的员工个人信息
select dname, ename, sal, eid, -- 若不指定order by 将会排序混乱,出现错误的结果
nth_value(sal,2) over(partition by dname order by eid) as second_sal,
nth_value(sal,3) over(partition by dname order by eid) as thrid_sal
from emp;
-- NTILE()
-- 根据入职编号将各部门员工分3组
select dname, ename, sal, eid, -- 若不指定order by 将会排序混乱,出现错误的结果
ntile(3) over(partition by dname order by eid) as rn
from emp;
-- 取出各部门的第一组员工
select
*
from (select dname, ename, sal, eid, ntile(3)
over(partition by dname order by eid)
as rn from emp)t
where t.rn = 1;
6.7 练习
-- 查询各部门平均薪水最高的部门名
select
a.deptno,a.dname,a.location,avg_sal
from
dept a,
(
select *
from
(
select
*,
rank() over(order by avg_sal desc ) rn
from
(
select deptno,avg(sal) avg_sal from emp group by deptno
)t1
)t2
where rn = 1
)t3
where a.deptno = t3.deptno;
-- 查询员工比所属领导薪资高的员工个人信息
create view test_view
as
select
a.ename ename,
a.sal esal,
b.ename mgrname,
b.sal mgrsal,
a.deptno
from
emp a,
emp b
where
a.mgr = b.deptno
and a.sal > b.sal;
select * from dept a join test_view b on a.deptno = b.deptno;




















