六.运算符
6.1 算术运算符(掌握)
mysql
加:+
在MySQL +就是求和,没有字符串拼接
减:-
乘:*
除:/ div(只保留整数部分)
div:两个数相除只保留整数部分
/:数学中的除
模:% mod
mysql中没有 +=等运算符
mysql
#select 表达式
select 1+1;
update t_employee set salary = salary+100 where eid=27;
select 9/2, 9 div 2;
mysql> select 9/2, 9 div 2;
+--------+---------+
| 9/2 | 9 div 2 |
+--------+---------+
| 4.5000 | 4 |
+--------+---------+
1 row in set (0.00 sec)
mysql
select 9.5 / 1.5 , 9.5 div 1.5;
mysql> select 9.5 / 1.5 , 9.5 div 1.5;
+-----------+-------------+
| 9.5 / 1.5 | 9.5 div 1.5 |
+-----------+-------------+
| 6.33333 | 6 |
+-----------+-------------+
1 row in set (0.00 sec)
select 9 % 2, 9 mod 2;
select 9.5 % 1.5 , 9.5 mod 1.5;
mysql
select 'hello' + 'world';
mysql> select 'hello' + 'world';
+-------------------+
| 'hello' + 'world' |
+-------------------+
| 0 |
+-------------------+
1 row in set, 2 warnings (0.00 sec)
6.2 比较运算符(掌握)
大于:>
小于:<
大于等于:>=
小于等于:<=
等于:= 不能用于null判断
不等于:!= 或 <> 不能用于null判断
算数 10 / 4 2.5
div -- 没有余数 10 div 4 -- 2
处理null值:
是null:
字段 is null
字段 <=> null
不是null:
字段 is not null
not 字段 <=> null
逻辑
and or xor not
区间集合
[not]between X and Y [X,Y]
[not] in (值....)
模糊匹配:
like
%:任意多个
_:任意一个
查询薪资高于15000的员工姓名和薪资
sql
select ename,salary from t_employee where salary>15000;
mysql> select ename,salary from t_employee where salary>15000;
+--------+--------+
| ename | salary |
+--------+--------+
| 孙洪亮 | 28000 |
| 贾宝玉 | 15700 |
| 黄冰茹 | 15678 |
| 李冰冰 | 18760 |
| 谢吉娜 | 18978 |
| 舒淇格 | 16788 |
| 章嘉怡 | 15099 |
+--------+--------+
7 rows in set (0.00 sec)
查询薪资正好是9000的员工姓名和薪资
sql
select ename,salary from t_employee where salary = 9000;
select ename,salary from t_employee where salary == 9000;#错误,不支持== #注意Java中判断用==,mysql判断用=
mysql> select ename,salary from t_employee where salary == 9000;
ERROR 1064 (42000): You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near '== 9000' at line 1
查询籍贯native_place不是北京的
sql
select * from t_employee where native_place != '北京';
select * from t_employee where native_place <> '北京';
查询员工表中部门编号不是1
sql
select * from t_employee where did != 1;
select * from t_employee where did <> 1;
查询奖金比例是NULL
sql
select * from t_employee where commission_pct = null;
mysql> select * from t_employee where commission_pct = null; #无法用=null判断
Empty set (0.00 sec)
查询奖金比例是NULL
sql
select * from t_employee where commission_pct <=> null;
select * from t_employee where commission_pct is null;
查询"李冰冰"、"周旭飞"、"李易峰"这几个员工的信息
sql
select * from t_employee where ename in ('李冰冰','周旭飞','李易峰');
查询部门编号为2、3的员工信息
sql
select * from t_employee where did in(2,3);
查询部门编号不是2、3的员工信息
sql
select * from t_employee where did not in(2,3);
查询薪资在10000,15000之间
sql
select * from t_employee where salary between 10000 and 15000;
查询姓名中第二个字是'冰'的员工
sql
select * from t_employee where ename like '冰'; #这么写等价于 ename='冰'
select * from t_employee where ename like '_冰%';
#这么写匹配的是第二个字是冰,后面可能没有第三个字,或者有好几个字
update t_employee set ename = '王冰' where ename = '李冰冰';
select * from t_employee where ename like '_冰_';
#这么写匹配的是第二个字是冰,后面有第三个字,且只有三个字
查询员工的姓名、薪资、奖金比例、实发工资
sql
#实发工资 = 薪资 + 薪资 * 奖金比例
select ename as 姓名,
salary as 薪资,
commission_pct as 奖金比例,
salary + salary * commission_pct as 实发工资
from t_employee;
NULL在mysql中比较和计算都有特殊性,所有的计算遇到的null都是null。
sql
#实发工资 = 薪资 + 薪资 * 奖金比例
select ename as 姓名,
salary as 薪资,
commission_pct as 奖金比例,
salary + salary * ifnull(commission_pct,0) as 实发工资
from t_employee;
6.3 区间或集合范围比较运算符(掌握)
区间范围:between x and y [x,y]
not between x and y
集合范围:in (x,x,x)
not in(x,x,x)
#查询薪资在10000,15000
sql
select * from t_employee where salary>=10000 && salary<=15000;
select * from t_employee where salary between 10000 and 15000;
#查询籍贯在这几个地方的
sql
select * from t_employee where native_place in ('北京', '浙江', '江西');
#查询薪资不在10000,15000
sql
select * from t_employee where salary not between 10000 and 15000;
#查询籍贯不在这几个地方的
sql
select * from t_employee where native_place not in ('北京', '浙江', '江西');
6.4 模糊匹配比较运算符(掌握)
%:代表任意个字符
_:代表一个字符,如果两个下划线代表两个字符
#查询名字中包含'冰'字
sql
select * from t_employee where ename like '%冰%';
#查询名字以'雷'结尾的
sql
select * from t_employee where ename like '%雷';
#查询名字以'李'开头
sql
select * from t_employee where ename like '李%';
#查询名字有冰这个字,但是冰的前面只能有1个字
sql
select * from t_employee where ename like '_冰%';
6.5 逻辑运算符(掌握)
逻辑与:&& 或 and
逻辑或:|| 或 or
逻辑非:! 或 not
逻辑异或: xor
#查询薪资高于15000,并且性别是男的员工
sql
select * from t_employee where salary>15000 and gender='男';
select * from t_employee where salary>15000 && gender='男';
select * from t_employee where salary>15000 & gender='男';#错误 &按位与
select * from t_employee where (salary>15000) & (gender='男');
#查询薪资高于15000,或者did为1的员工
sql
select * from t_employee where salary>15000 or did = 1;
select * from t_employee where salary>15000 || did = 1;
#查询薪资不在15000,20000范围的
sql
select * from t_employee where salary not between 15000 and 20000;
select * from t_employee where !(salary between 15000 and 20000);
#查询薪资高于15000,或者did为1的员工,两者只能满足其一
sql
select * from t_employee where salary>15000 xor did = 1;
select * from t_employee where (salary>15000) ^ (did = 1);
6.6 关于null值的问题(掌握)
#(1)判断时
xx is null
xx is not null
xx <=> null
#(2)计算时
ifnull(xx,代替值) 当xx是null时,用代替值计算
#查询奖金比例为null的员工
sql
select * from t_employee where commission_pct = null; #失败
select * from t_employee where commission_pct = NULL; #失败
select * from t_employee where commission_pct = 'NULL'; #失败
select * from t_employee where commission_pct is null; #成功
select * from t_employee where commission_pct <=> null; #成功 <=>安全等于
#查询员工的实发工资,实发工资 = 薪资 + 薪资 * 奖金比例
sql
select ename , salary + salary * commission_pct "实发工资" from t_employee; #失败,当commission_pct为null,结果都为null
select ename ,salary , commission_pct, salary + salary * ifnull(commission_pct,0) "实发工资" from t_employee;
6.7 位运算符(了解)
mysql
左移:<<
右移:>>
按位与:&
按位或:|
按位异或:^
按位取反:~
七. 系统预定义函数
函数:代表一个独立的可复用的功能。
和python中的方法有所不同,不同点在于:MySQL中的函数必须有返回值,参数可以有,可以没有。
MySQL中函数分为:
(1)系统预定义函数:MySQL数据库管理软件给我提供好的函数,直接用就可以,任何数据库都可以用公共的函数。
- 分组函数:或者又称为聚合函数,多行函数,表示会对表中的多行记录一起做一个"运算",得到一个结果。
- 求平均值的avg,求最大值的max,求最小值的min,求总和sum,求个数的count等
- 单行函数:表示会对表中的每一行记录分别计算,有n行得到还是n行结果
- 数学函数、字符串函数、日期时间函数、条件判断函数、窗口函数等

(2)用户自定义函数:由开发人员自己定义的,通过CREATE FUNCTION语句定义,是属于某个数据库的对象。

7.1 分组函数
调用完函数后,结果的行数变少了,可能得到一行,可能得到少数几行。
分组函数有合并计算过程。
常用分组函数类型
-
AVG(x) :求平均值
-
SUM(x):求总和
-
MAX(x) :求最大值
-
MIN(x) :求最小值
-
**COUNT(x) **:统计记录数
演示分组函数,聚合函数,多行函数
#统计t_employee表的员工的数量
sql
SELECT COUNT(*) FROM t_employee;
SELECT COUNT(1) FROM t_employee;
SELECT COUNT(eid) FROM t_employee;
SELECT COUNT(commission_pct) FROM t_employee;
/*
count(*)或count(常量值):都是统计实际的行数。
count(字段/表达式):只统计"字段/表达式"部分非NULL值的行数。
*/
#找出t_employee表中最高的薪资值
sql
SELECT MAX(salary) FROM t_employee;
#找出t_employee表中最低的薪资值
sql
SELECT MIN(salary) FROM t_employee;
#统计t_employee表中平均薪资值
sql
SELECT AVG(salary) FROM t_employee;
#统计所有人的薪资总和,财务想看一下,一个月要准备多少钱发工资
sql
SELECT SUM(salary) FROM t_employee; #没有考虑奖金
SELECT SUM(salary+salary*IFNULL(commission_pct,0)) FROM t_employee;
#找出年龄最小、最大的员工的出生日期
sql
SELECT MAX(birthday),MIN(birthday) FROM t_employee;
#查询最新入职的员工的入职日期
sql
SELECT MAX(hiredate) FROM t_employee;
7.2 单行函数
调用完函数后,记录数不变,一行计算完之后还是一行。
1、数学函数
以下表格中也只是列出了一部分
| 函数 | 用法 |
|---|---|
| ABS(x) | 返回x的绝对值 |
| CEIL(x) | 返回大于x的最小整数值 |
| FLOOR(x) | 返回小于x的最大整数值 |
| MOD(x,y) | 返回x/y的模 |
| RAND() | 返回0~1的随机值 |
| ROUND(x,y) | 返回参数x的四舍五入的有y位的小数的值 |
| TRUNCATE(x,y) | 返回数字x截断为y位小数的结果 |
| FORMAT(x,y) | 强制保留小数点后y位,整数部分超过三位的时候以逗号分割,并且返回的结果是文本类型的 |
| SQRT(x) | 返回x的平方根 |
| POW(x,y) | 返回x的y次方 |
单行函数,演示数学函数
#在"t_employee"表中查询员工无故旷工一天扣多少钱,
#分别用CEIL、FLOOR、ROUND、TRUNCATE函数。
sql
#假设本月工作日总天数是22天,
#旷工一天扣的钱=salary/22。
SELECT ename,salary/22,CEIL(salary/22),
FLOOR(salary/22),ROUND(salary/22,2),
TRUNCATE(salary/22,2) FROM t_employee;
#查询公司平均薪资,并对平均薪资分别
#使用CEIL、FLOOR、ROUND、TRUNCATE函数
sql
SELECT AVG(salary),CEIL(AVG(salary)),
FLOOR(AVG(salary)),ROUND(AVG(salary)),
TRUNCATE(AVG(salary),2) FROM t_employee;
2、字符串函数
下面列出部分字符串函数:
| 函数 | 功能描述 |
|---|---|
| CONCAT(S1,S2,......Sn) | 连接S1,S2,......Sn为一个字符串 |
| CONCAT_WS(s,S1,S2,......Sn) | 同CONCAT(S1,S2,...)函数,但每个字符串之间要加上s |
| CHAR_LENGTH(s) | 返回字符串s的字符数 |
| LENGTH(s) | 返回字符串s的字节数,和字符集有关 |
| LOCATE(str1,str)或 POSITION(str1 in str)或 INSTR(str,str1) | 返回子字符串str1在str中的开始位置 |
| UPPER(s)或UCASE(s) | 将字符串s的所有字母转成大写字母 |
| LOWER(s)或LCASE(s) | 将字符串s的所有字母转成小写字母 |
| LEFT(s,n) | 返回字符串s最左边的n个字符 |
| RIGHT(s,n) | 返回字符串s最右边的n个字符 |
| LPAD(str,len,pad) | 用字符串pad对str最左边进行填充直到str的长度达到len |
| RPAD(str,len,pad) | 用字符串pad对str最右边进行填充直到str的长度达到len |
| LTRIM(s) | 去掉字符串s左侧的空格 |
| RTRIM(s) | 去掉字符串s右侧的空格 |
| TRIM(s) | 去掉字符串s开始与结尾的空格 |
| TRIM(BOTH s1 FROM s) | 去掉字符串s开始与结尾的s1 |
| TRIM(LEADING s1 FROM s) | 去掉字符串s开始处的s1 |
| TRIM(TRAILINGs1 FROM s) | 去掉字符串s结尾处的s1 |
| INSERT(str,index,len,instr) | 将字符串str从index位置开始len个字符的替换为字符串instr |
| REPLACE(str,a,b) | 用字符串b替换字符串str中所有出现的字符串a |
| REPEAT(str,n) | 返回str重复n次的结果 |
| REVERSE(s) | 将字符串反转 |
| STRCMP(s1,s2) | 比较字符串s1,s2 |
| SUBSTRING(s,index,len) | 返回从字符串s的index位置截取len个字符 |
| SUBSTRING_INDEX(str, 分隔符,count) | 如果count是正数,那么从左往右数,第n个分隔符的左边的全部内容。例如,substring_index("www.atguigu.com",".",1)是"www"。如果count是负数,那么从右边开始数,第n个分隔符右边的所有内容。例如,substring_index("www.atguigu.com",".",-1)是"com"。 |
字符串函数
mysql中不支持 + 拼接字符串,需要调用函数来拼接
(1)在"t_employee"表中查询员工姓名ename和电话tel,
并使用CONCAT函数,CONCAT_WS函数。
sql
SELECT CONCAT(ename,tel),CONCAT_WS('-',ename,tel) FROM t_employee;
(2)在"t_employee"表中查询薪资高于15000的男员工姓名,
sql
#并把姓名处理成"张xx"的样式。
#LEFT(s,n)函数表示取字符串s最左边的n个字符,
#而RPAD(s,len,p)函数表示在字符串s的右边填充p使得字符串长度达到len。
SELECT RPAD(LEFT(ename,1),3,'x'),salary
FROM t_employee
WHERE salary>15000 AND gender ='男';
(3)在"t_employee"表中查询薪资高于10000的男员工姓名、
sql
#姓名包含的字符数和占用的字节数。
SELECT ename,CHAR_LENGTH(ename) AS 占用字符数,LENGTH(ename) AS 占用字节数量
FROM t_employee
WHERE salary>10000 AND gender ='男'
;
(4)在"t_employee"表中查询薪资高于10000的男员工姓名和邮箱email,
并把邮箱名"@"字符之前的字符串截取出来。
sql
SELECT ename,email,
SUBSTRING(email,1, POSITION('@' IN email)-1)
FROM t_employee
WHERE salary > 10000 AND gender ='男';
mysql中 SUBSTRING截取字符串位置,下标从1开始,不是和Java一样从0开始。
mysql中 position等指定字符串中某个字符,子串的位置也不是从0开始,都是从1开始。
sql
SELECT TRIM(' hello world '); #默认是去掉前后空白符
SELECT CONCAT('[',TRIM(' hello world '),']'); #默认是去掉前后空白符
SELECT TRIM(BOTH '&' FROM '&&&&hello world&&&&'); #去掉前后的&符号
SELECT TRIM(LEADING '&' FROM '&&&&hello world&&&&'); #去掉开头的&符号
SELECT TRIM(TRAILING '&' FROM '&&&&hello world&&&&'); #去掉结尾的&符号
3、日期时间函数
| 函数 | 功能描述 |
|---|---|
| CURDATE()或CURRENT_DATE() | 返回当前系统日期 |
| CURTIME()或CURRENT_TIME() | 返回当前系统时间 |
| NOW()/SYSDATE()/CURRENT_TIMESTAMP()/ LOCALTIME()/LOCALTIMESTAMP() | 返回当前系统日期时间 |
| UTC_DATE()/UTC_TIME() | 返回当前UTC日期值/时间值UTC(协调世界时)是全球统一时间的标准。它是基于原子钟生成的时间,被认为是"最精确的时间"。 |
| UNIX_TIMESTAMP(date) | 返回一个UNIX时间戳 |
| YEAR(date)/MONTH(date)/DAY(date)/ HOUR(time)/MINUTE(time)/SECOND(time) | 返回具体的时间值 |
| EXTRACT(type FROM date) | 从日期中提取一部分值 |
| DAYOFMONTH(date)/DAYOFYEAR(date) | 返回一月/年中第几天 |
| WEEK(date)/WEEKOFYEAR(date) | 返回一年中的第几周 |
| DAYOFWEEK() | 返回周几,注意,周日是1,周一是2,...周六是7 |
| WEEKDAY(date) | 返回周几,注意,周一是0,周二是1,...周日是6 |
| DAYNAME(date) | 返回星期,MONDAY,TUESDAY,...SUNDAY |
| MONTHNAME(date) | 返回月份,January,... |
| DATEDIFF(date1,date2)/TIMEDIFF(time1,time2) | 返回date1-date2的日期间隔/返回time1-time2的时间间隔 |
| DATE_ADD(date,INTERVAL expr type)或ADDDATE/DATE_SUB/SUBDATE | 返回与给定日期相差INTERVAL时间段的日期 |
| ADDTIME(time,expr)/SUBTIME(time,expr) | 返回给定时间加上/减去expr的时间值 |
| DATE_FORMAT(datetime,fmt)/ TIME_FORMAT(time,fmt) | 按照字符串fmt格式化日期datetime值/时间time值 |
| STR_TO_DATE(str,fmt) | 按照字符串fmt对str进行解析,解析为一个日期 |
| GET_FORMAT(val_type,format_type) | 返回日期时间字符串的显示格式 |
函数中日期时间类型说明
| 参数类型 | 描述 | 参数类型 | 描述 |
|---|---|---|---|
| YEAR | 年 | YEAR_MONTH | 年月 |
| MONTH | 月 | DAY_HOUR | 日时 |
| DAY | 日 | DAY_MINUTE | 日时分 |
| HOUR | 时 | DAY_SECOND | 日时分秒 |
| MINUTE | 分 | HOUR_MINUTE | 时分 |
| SECOND | 秒 | HOUR_SECOND | 时分秒 |
| WEEK | 星期 | MINUTE_SECOND | 分秒 |
| QUARTER | 季度信息 |
函数中format参数说明
| 格式符 | 说明 | 格式符 | 说明 |
|---|---|---|---|
| %Y | 4位数字表示年份 | %y | 两位数字表示年份 |
| %M | 月名表示月份(January,...) | %m | 两位数字表示月份(01,02,03,...) |
| %b | 缩写的月名(Jan.,Feb.,...) | %c | 数字表示月份(1,2,3...) |
| %D | 英文后缀表示月中的天数(1st,2nd,3rd,...) | %d | 两位数字表示表示月中的天数(01,02,...) |
| %e | 数字形式表示月中的天数(1,2,3,...) | %p | AM或PM |
| %H | 两位数字表示小数,24小时制(01,02,03,...) | %h和%I | 两位数字表示小时,12小时制(01,02,03,...) |
| %k | 数字形式的小时,24小时制(1,2,3,...) | %l | 数字表示小时,12小时制(1,2,3,...) |
| %i | 两位数字表示分钟(00,01,02,...) | %S和%s | 两位数字表示秒(00,01,02,...) |
| %T | 时间,24小时制(hh:mm:ss) | %r | 时间,12小时制(hh:mm:ss)后加AM或PM |
| %W | 一周中的星期名称(Sunday,...) | %a | 一周中的星期缩写(Sun.,Mon.,Tues.,...) |
| %w | 以数字表示周中的天数(0=Sunday,1=Monday,...) | %j | 以3位数字表示年中的天数(001,002,...) |
| %U | 以数字表示的的第几周(1,2,3,...) 其中Sunday为周中的第一天 | %u | 以数字表示年中的年份(1,2,3,...) 其中Monday为周中第一天 |
| %V | 一年中第几周(01~53),周日为每周的第一天,和%X同时使用 | %X | 4位数形式表示该周的年份,周日为每周第一天,和%V同时使用 |
| %v | 一年中第几周(01~53),周一为每周的第一天,和%x同时使用 | %x | 4位数形式表示该周的年份,周一为每周第一天,和%v同时使用 |
| %% | 表示% |
GET_FORMAT函数中val_type 和format_type参数说明
| 值类型 | 格式化类型 | 显示格式字符串 |
|---|---|---|
| DATE | EUR | %d.%m.%Y |
| DATE | INTERVAL | %Y%m%d |
| DATE | ISO | %Y-%m-%d |
| DATE | JIS | %Y-%m-%d |
| DATE | USA | %m.%d.%Y |
| TIME | EUR | %H.%i.%s |
| TIME | INTERVAL | %H%i%s |
| TIME | ISO | %H:%i:%s |
| TIME | JIS | %H:%i:%s |
| TIME | USA | %h:%i:%s %p |
| DATETIME | EUR | %Y-%m-%d %H.%i.%s |
| DATETIME | INTERVAL | %Y%m%d %H%i%s |
| DATETIME | ISO | %Y-%m-%d %H:%i:%s |
| DATETIME | JIS | %Y-%m-%d %H:%i:%s |
| DATETIME | USA | %Y-%m-%d %H.%i.%s |
日期时间函数
获取系统日期时间值
获取某个日期或时间中的具体的年、月等值
获取星期、月份值,可以是当天的星期、当月的月份
获取一年中的第几个星期,一年的第几天
计算两个日期时间的间隔
获取一个日期或时间间隔一定时间后的另个日期或时间
和字符串之间的转换
(1)获取系统日期。
CURDATE()和CURRENT_DATE()函数都可以获取当前系统日期。将日期值"+0"会怎么样?
sql
SELECT CURDATE(),CURRENT_DATE();
(2)获取系统时间。
CURTIME()和CURRENT_TIME()函数都可以获取当前系统时间。将时间值"+0"会怎么样?
sql
SELECT CURTIME(),CURRENT_TIME();
(3)获取系统日期时间值。
CURRENT_TIMESTAMP()、LOCALTIME()、SYSDATE()和NOW()
sql
SELECT CURRENT_TIMESTAMP(),LOCALTIME(),SYSDATE(),NOW();
(4)获取当前UTC(世界标准时间)日期或时间值。
本地时间是根据地球上不同时区所处的位置调整 UTC 得来的,
例如,北京时间比UTC时间晚8个小时。
sql
#UTC_DATE(),CURDATE(),UTC_TIME(), CURTIME()
SELECT UTC_DATE(),CURDATE(),UTC_TIME(), CURTIME();
(5)获取UNIX时间戳。
sql
SELECT UNIX_TIMESTAMP(),UNIX_TIMESTAMP('2022-1-1');
(6)获取具体的时间值,比如年、月、日、时、分、秒。
分别是YEAR(date)、MONTH(date)、DAY(date)、HOUR(time)、MINUTE(time)、SECOND(time)。
sql
SELECT YEAR(CURDATE()),MONTH(CURDATE()),DAY(CURDATE());
SELECT HOUR(CURTIME()),MINUTE(CURTIME()),SECOND(CURTIME());
(7)获取日期时间的指定值。
EXTRACT(type FROM date/time)函数
sql
SELECT EXTRACT(YEAR_MONTH FROM CURDATE());
(8)获取两个日期或时间之间的间隔。
sql
#DATEDIFF(date1,date2)函数表示返回两个日期之间间隔的天数。
#TIMEDIFF(time1,time2)函数表示返回两个时间之间间隔的时分秒
#查询今天距离员工入职的日期间隔天数
SELECT ename,DATEDIFF(CURDATE(),hiredate) FROM t_employee;
#查询现在距离中午放学还有多少时间
SELECT TIMEDIFF(CURTIME(),'12:0:0');
(9)在"t_employee"表中查询本月生日的员工姓名、生日。
sql
SELECT ename,birthday
FROM t_employee
WHERE MONTH(CURDATE()) = MONTH(birthday);
(10)#查询入职时间超过5年的
sql
SELECT ename,hiredate,DATEDIFF(CURDATE(),hiredate)
FROM t_employee
WHERE DATEDIFF(CURDATE(),hiredate) > 365*5;
SELECT STR_TO_DATE('1992-01-01',"%Y-%m-%d");
4、加密函数
列出了部分的加密函数。
| 函数 | 用法 |
|---|---|
| password(str) | 返回字符串str的加密版本,41位长的字符串(mysql8不再支持) |
| md5(str) | 返回字符串str的md5值,也是一种加密方式(Message-Digest Algorithm 5,信息摘要算法第五版) |
| SHA(str) | 返回字符串str的sha算法加密字符串,40位十六进制值的密码字符串 (Secure Hash Algorithm) |
| SHA2(str,hash_length) | 返回字符串str的sha算法加密字符串,密码字符串的长度是hash_length/4。hash_length可以是224、256、384、512、0,其中0等同于256。 |
加密函数
当用户需要对数据进行加密时,
比如做登录功能时,给用户的密码加密等。
mysql
#password函数在mysql8已经移除了
SELECT PASSWORD('123456');
#使用md5加密
SELECT MD5('123456'),SHA('123456'),sha2('123456',0);
SELECT CHAR_LENGTH(MD5('123456')),SHA('123456'),sha2('123456',0);
CREATE TABLE t_user(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20),
PASSWORD VARCHAR(100)
);
INSERT INTO t_user VALUES(NULL,'chai',MD5('123456'));
SELECT * FROM t_user
WHERE username='chai' AND PASSWORD =MD5('123456');
SELECT * FROM t_user
WHERE username='chai' AND PASSWORD ='123456';
5、系统信息函数
| 函数 | 用法 |
|---|---|
| database() | 返回当前数据库名 |
| version() | 返回当前数据库版本 |
| user() | 返回当前登录用户名 |
mysql
#其他函数
SELECT USER();
SELECT VERSION();
SELECT DATABASE();
6、条件判断函数
if(X,Y,Z): X:真 Y
假 Z
ifnull(v1,v2): v1不为null 返回v1 否则返回v2
类似与(if elif else) case when 条件 then 结果
....
[else 值] end
类似于(match case) case 表达式 when 常量值 then 结果
....
[else 值] end
| 函数 | 功能 |
|---|---|
| IF(value,t,f) | 如果value是真,返回t,否则返回f |
| IFNULL(value1,value2) | 如果value1不为空,返回value1,否则返回value2 |
| CASE WHEN 条件1 THEN result1 WHEN 条件2 THEN result2 ... ELSE resultn END | 依次判断条件,哪个条件满足了,就返回对应的result,所有条件都不满足就返回ELSE的result。如果没有单独的ELSE子句,当所有WHEN后面的条件都不满足时则返回NULL值结果。等价于pythn中if...elif... else. |
| CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值2 THEN 值2 ... ELSE 值n END | 判断表达式expr与哪个常量值匹配,找到匹配的就返回对应值,都不匹配就返回ELSE的值。如果没有单独的ELSE子句,当所有WHEN后面的常量值都不匹配时则返回NULL值结果。等价于Java中switch...case |
mysql
#条件判断函数
/*
这个函数不是筛选记录的函数,
而是根据条件不同显示不同的结果的函数。
*/
#如果薪资大于20000,显示高薪,否则显示正常
SELECT ename,salary,IF(salary>20000,'高薪','正常')
FROM t_employee;
#计算实发工资
#实发工资 = 薪资 + 薪资 * 奖金比例
SELECT ename,salary,commission_pct,
salary + salary * commission_pct
FROM t_employee;
#如果commission_pct是,计算完结果是NULL
SELECT ename,salary,commission_pct,
salary + salary * IFNULL(commission_pct,0) AS 实发工资
FROM t_employee;
SELECT ename,salary,commission_pct,
ROUND(salary + salary * IFNULL(commission_pct,0),2) AS 实发工资
FROM t_employee;
#查询员工编号,姓名,薪资,等级,等级根据薪资判断,
#如果薪资大于20000,显示"羡慕级别",
#如果薪资15000-20000,显示"努力级别",
#如果薪资10000-15000,显示"平均级别"
#如果薪资10000以下,显示"保底级别"
/*mysql中没有if...elseif函数,有case 函数。
等价于if...elseif
*/
SELECT eid,ename,salary,
CASE WHEN salary>20000 THEN '羡慕级别'
WHEN salary>15000 THEN '努力级别'
WHEN salary>10000 THEN '平均级别'
ELSE '保底级别'
END AS "等级"
FROM t_employee;
#在"t_employee"表中查询入职7年以上的
#员工姓名、工作地点、轮岗的工作地点数量情况。
/*
计算工作地点的数量,转换为求 work_place中逗号的数量+1。
work_place中逗号的数量 = work_place的总字符数 - work_place去掉,的字符数
work_place去掉, ,使用replace函数
*/
SELECT work_place,
CHAR_LENGTH(work_place)-CHAR_LENGTH(REPLACE(work_place,',',''))
FROM t_employee;
#类似于Java中switch...case
SELECT ename,work_place,
CASE (CHAR_LENGTH(work_place)-CHAR_LENGTH(REPLACE(work_place,',',''))+1)
WHEN 1 THEN '只在一个地方工作'
WHEN 2 THEN '在两个地方来回奔波'
WHEN 3 THEN '在三个地方流动'
ELSE '频繁出差'
END AS "工作地点数量情况"
FROM t_employee
WHERE DATEDIFF(CURDATE(),hiredate) > 365*7;
7、其他函数
从5.7.8版本之后开始支持JSON数据类型,并提供了操作JSON类型的数据的相关函数。
MySQL提供了非常丰富的空间函数以支持各种空间数据的查询和处理。
这两类函数基础阶段不讲,如果项目中有用到查询API使用。
7.3 窗口函数
函数名([参数列表]) OVER ()
函数名([参数列表]) OVER (子句)
函数名(参数列表) over(
[partition by column]
[order by column]
[rows between <start> and <end>]
)
序号函数:
row_number(): 每一条记录添加编号
rank(): 并列排序 会跳过
dense_rank():并列排序 不会跳过
其他:
lag() 上n个 lead() 下n个
first_value() 第一个
last_value() 最后一个 ORDER BY salary ROWS BETWEEN unbounded preceding AND unbounded following 整张表
注意:
1.over()没有写子句 则将整个结果集看成是一个窗口
窗口函数也叫OLAP函数(Online Anallytical Processing,联机分析处理),可以对数据进行实时分析处理。窗口函数是每条记录都会分析,有几条记录执行完还是几条,因此也属于单行函数。
| 窗口函数 | 说明 |
|---|---|
| row_number() | 顺序排序,每行按照不同的分组逐行编号,例如:1,2,3,4 |
| rank() | 并列排序,每行按照不同的分组进行编号,同一个分组中排序字段值出现重复值时,并列排序并跳过重复序号,例如:1,1,3 |
| dense_rank() | 并列稠密排序,每行按照不同的分组进行编号,同一个分组中排序字段值出现重复值时,并列排序不跳过重复序号,例如:1,1,2 |
| lag()/lead() | 访问窗口中当前行前/后一定偏移量的值 |
| first_value()/last_value() | 访问窗口中第一个或最后一个值 |
窗口函数的语法格式如下
mysql
函数名([参数列表]) OVER ()
函数名([参数列表]) OVER (子句)
函数名(参数列表) over(
[partition by column]
[order by column]
[rows between <start> and <end>]
)
over关键字用来指定窗口函数的窗口范围。如果OVER后面是空(),则表示SELECT语句筛选的所有行是一个窗口。OVER后面的()中支持以下3种语法来设置窗口范围。
-
window:给窗口指定一个别名
-
partition by:一个窗口范围还可以分为多个区域。按照哪些字段进行分区/分组,窗口函数在不同的分组上分别处理分析
-
order by:按照哪些字段进行排序,窗口函数将按照排序后结果进行分析处理
-
rows/range between and :在计算窗口函数时,指定哪些行/值将被包含在计算范围内,和用于定义窗口范围:
Ø unbounded preceding:窗口从分区的第一行开始
Ø n preceding:当前行之前的n行
Ø current row:当前行
Ø n following: 当前行之后的n行
Ø unbounded following:窗口到分区的最后一行
mysql
use atguigu;
-- 在t_employee表中查询薪资在[8000,10000]之间的员工姓名和薪资并给每一行记录编序号
select row_number() over() as rn,ename,salary
from t_employee
where salary between 8000 and 10000;
-- 计算每一个部门的平均薪资与全公司的平均薪资的差值
select distinct
did,
avg(salary) over(partition by did),
avg(salary) over(),
round(avg(salary) over(partition by did)-avg(salary) over(),2) as deviation
from t_employee;
-- 在t_employee表中查询女员工姓名,部门编号,薪资
-- 查询结果按照部门编号分组后在按薪资升序排列
-- 并分别使用row_number()、rank()、dense_rank()三个序号函数给每一行记录编序号
select ename,did,salary,gender,
row_number() over(partition by did order by salary) as "row_num",
rank() over(partition by did order by salary) as "rank_num",
dense_rank() over(partition by did order by salary) as "ds_rank_num"
from t_employee where gender='女';
-- 或使用window给窗口指定别名
select ename,did,salary,
row_number() over w as "row_num",
rank() over w as "rank_num" ,
dense_rank() over w as "ds_rank_num"
from t_employee where gender='女'
window w as(partition by did order by salary);
-- 在t_employee表中查询每个部门最低3个薪资值的女员工姓名,部门编号,薪资值
select row_number() over() as rn,temp.*
from(select ename,did,salary,
row_number() over w as "row_num",
rank() over w as "rank_num" ,
dense_rank() over w as "ds_rank_num"
from t_employee where gender='女'
window w as(partition by did order by salary))temp
where temp.rank_num<=3;
-- 在t_employee表中查询每个部门薪资排名前3的员工姓名,部门编号,薪资值
select temp.*
from(select ename,did,salary,
dense_rank() over w as "ds_rank_num"
from t_employee
window w as(partition by did order by salary desc))temp
where temp.ds_rank_num<=3;
-- 在t_employee表中查询全公司薪资排名前3的员工姓名,部门编号,薪资值
select temp.*
from(select ename,did,salary,
dense_rank() over w as "ds_rank_num"
from t_employee
window w as(order by salary desc))temp
where temp.ds_rank_num<=3;
-- 查找薪资排名的上一位、下一位、首位、末位
select
ename,
salary,
lag(ename,1,'-') over(order by salary) as '上一位姓名',
lag(salary,1,0) over(order by salary) as '上一位薪资',
lead(ename) over(order by salary) as '下一位姓名',
lead(salary) over(order by salary) as '下一位薪资',
first_value(salary) over(order by salary) as '首位薪资',
last_value(ename) over(order by salary rows between unbounded preceding and unbounded following) as '末位姓名'
from t_employee;