一、简介
MySQL 中的函数特别的多,本文主要讲解 MySQL 中一些常见的函数:
- 字符串函数
- 数字函数
- 日期函数
- 高级函数
本文就用这个员工信息表进行演示
CREATE TABLE `tb_employee` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`emp_code` int unsigned DEFAULT NULL COMMENT '员工编码',
`emp_name` varchar(20) DEFAULT NULL COMMENT '员工姓名',
`gender` char(1) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '性别',
`dep_code` int DEFAULT NULL COMMENT '部门',
`job` varchar(20) DEFAULT '' COMMENT '工作',
`age` tinyint DEFAULT NULL COMMENT '年龄',
`salary` double(8,2) DEFAULT NULL COMMENT '工资',
`hire_date` date DEFAULT NULL COMMENT '入职时间',
`manage_code` int DEFAULT NULL COMMENT '所属领导',
PRIMARY KEY (`id`),
KEY `idx_emp_code` (`emp_code`),
KEY `idx_manage_code` (`manage_code`)
) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci comment '员工信息表';
二、字符串函数
2.1、字符串长度
使用 char_length(str) 或者 character_length(str) 都是可以的,这里的 str 是一个字符串。
获取指定字符串的长度
#获取指定字符串的长度示例
SELECT CHAR_LENGTH("Alian") AS '字符串长度';
+-----------------+
| 字符串长度 |
+-----------------+
| 5 |
+-----------------+
获取字段的长度
#获取字段的长度(比如获取员工编号为8000的名字的长度)
SELECT emp_name AS '姓名', char_length(emp_name) AS '姓名的长度' FROM tb_employee WHERE emp_code='8000';
#或者
SELECT emp_name AS '姓名', character_length(emp_name) AS '姓名的长度' FROM tb_employee WHERE emp_code='8000';
+-----------+-----------------+
| 姓名 | 姓名的长度 |
+-----------+-----------------+
| 赖晓畅 | 3 |
+-----------+-----------------+
2.2、字符串合并
使用 CONCAT(s1,s2…sn) 这里的 s1,s2…sn 是多个字符串,用逗号隔开。
常规字符串合并
#合并常规字符串
SELECT concat('Alian',' lover',' java') as '字符串合并';
+------------------+
| 字符串合并 |
+------------------+
| Alian lover java |
+------------------+
字符串和字段值合并
#给前面4个员工名字后面都拼一个 lover mysql
SELECT concat(emp_name,' lover',' mysql') as '字符串合并' from tb_employee limit 4;
+-----------------------+
| 字符串合并 |
+-----------------------+
| 赖晓畅 lover mysql |
| 谢又蓝 lover mysql |
| 吕芸溪 lover mysql |
| 谭淑慧 lover mysql |
+-----------------------+
转义符使用
有时我们需要拼接单引号,反斜杠等,就需要用到转义符
#比如把前4个员工的名字用单引号拼起来
SELECT concat('\'',emp_name,'\'') as '字符串合并' from tb_employee limit 4;
#上面只是为了演示,实际你也可以使用下面的语句,但是一般建议写sql还是用单引号
SELECT concat("'",emp_name,"'") as '字符串合并' from tb_employee limit 4;
+-----------------+
| 字符串合并 |
+-----------------+
| '赖晓畅' |
| '谢又蓝' |
| '吕芸溪' |
| '谭淑慧' |
+-----------------+
有时如果想用一个特定符合分隔(比如下划线,短横线等)所有的结果值,则使用 CONCAT_WS(x, s1,s2…sn) 其中这里的 x 是就是分隔字符串, s1,s2…sn 是多个字符串,用逗号隔开。
使用分隔符合并常规字符串
#比如把Alian lover java用下划线分隔
SELECT concat_ws('_','Alian','lover','java') as '分隔符合并字符串';
+--------------------------+
| 分隔符合并字符串 |
+--------------------------+
| Alian_lover_java |
+--------------------------+
2.3、数字格式化
将数字进行格式化,格式使用 FORMAT(x,n) 这里的 x 是要格式化的数字, n 就是将 x 保留到小数点后 n 位,最后一位四舍五入。
#将12345.6789格式化,保留2位小数
SELECT format(12345.6789,2) as '格式化字符串';
+--------------------+
| 格式化字符串 |
+--------------------+
| 12,345.68 |
+--------------------+
2.4、英文大小写
转为小写
转小写方法 | 功能 |
---|---|
LCASE(s) | 把 s 中的字母转为小写 |
LOWER(s) | 把 s 中的字母转为小写 |
使用 LCASE(s) 或 LOWER(s) 可以将字符串里的字母转换为小写,其中括号里的 s 是要转换的字符串。
#我们这里使用这两个方法来把ALIAN转换为小写
SELECT lcase('ALIAN') as '转为小写方式一',lower('ALIAN') as '转为小写方式二';
+-----------------------+-----------------------+
| 转为写方式一 | 转为小写方式二 |
+-----------------------+-----------------------+
| alian | alian |
+-----------------------+-----------------------+
转为大写
转大写方法 | 功能 |
---|---|
UCASE(s) | 把 s 中的字母转为大写 |
UPPER(s) | 把 s 中的字母转为大写 |
使用 UCASE(s) 或 UPPER(s) 可以将字符串里的字母转换为大写,其中括号里的 s 是要转换的字符串。
#我们这里使用这两个方法来把alian转换为大写
SELECT ucase('alian') as '转为大写方式一',upper('alian') as '转为大写方式二';
+-----------------------+-----------------------+
| 转为大写方式一 | 转为大写方式二 |
+-----------------------+-----------------------+
| ALIAN | ALIAN |
+-----------------------+-----------------------+
不要因为我没有举数据库字段的就不会写了啊,就把 s 换成你要操作的字段的列名就行了,不要加引号!!!,比如:
#把名字转为大写或者小写(指含有英文字母的)
SELECT lcase(emp_name),lower(emp_name),ucase(emp_name),upper(emp_name) from tb_employee;
2.5、去空格
去空格方法 | 功能 |
---|---|
LTRIM(s) | 去掉字符串 s 开始处的空格 |
RTRIM(s) | 去掉字符串 s 结尾处的空格 |
TRIM(s) | 去掉字符串 s 开始和结尾处的空格 |
使用 LTRIM(s) 、 RTRIM(s) 或 TRIM(s) 分别可以将字符串 s 左边,右边以及两边的空格去掉,其中括号里的 s 是要去除空格的字符串。
去除左边空格
#去除左边空格
SELECT ' 左边空格去除' as '原字符串', ltrim(' 左边空格去除') as '去除左边的空格';
+------------------------------+-----------------------+
| 原字符串 | 去除左边的空格 |
+------------------------------+-----------------------+
| 左边空格去除 | 左边空格去除 |
+------------------------------+-----------------------+
去除右边空格
#去除右边空格
SELECT '右边边空格去除 ' as '原字符串', rtrim('右边边空格去除 ') as '去除右边的空格';
+---------------------------------+-----------------------+
| 原字符串 | 去除右边的空格 |
+---------------------------------+-----------------------+
| 右边边空格去除 | 右边边空格去除 |
+---------------------------------+-----------------------+
去除两边空格
#去除两边空格
SELECT ' 两边空格去除 ' as '原字符串', trim(' 两边空格去除 ') as '去除两边的空格';
+----------------------------------------+-----------------------+
| 原字符串 | 去除两边的空格 |
+----------------------------------------+-----------------------+
| 两边空格去除 | 两边空格去除 |
+----------------------------------------+-----------------------+
其实有可能你对右边的空格感官不明显,其实结合前面的合并字符串函数 CONCAT(s1,s2…sn) 得到更明显的效果(其实还可以使用后面要讲的RPAD函数)
SELECT
concat('右边边空格去除 ','#####') as '未去除空格',
concat(rtrim('右边边空格去除 '),'#####') as '去除右边的空格';
+--------------------------------------+----------------------------+
| 未去除空格 | 去除右边的空格 |
+--------------------------------------+----------------------------+
| 右边边空格去除 ##### | 右边边空格去除##### |
+--------------------------------------+----------------------------+
同样的如果是数据库字段就把 s 换成你要操作的字段的列名就行了,不要加引号!!!,比如:
#去除名字里的空格演示
SELECT ltrim(emp_name),rtrim(emp_name),trim(emp_name) from tb_employee;
2.6、替换字符串
替换字符串可以使用 REPLACE(s,s1,s2) 这里的 s 是原字符串, s1 就是要被替换的字符串, s2 就是用来替换 s1 的字符串,简单来说就是:把字符串 s 中的 s1 字符串替换为 s2 。
替换字符串
#把字符串aaabbbccc中b替换为x
SELECT REPLACE('aaabbbccc','b','x') as '替换后字符串';
+--------------------+
| 替换后字符串 |
+--------------------+
| aaaxxxccc |
+--------------------+
2.7、填充字符串
填充字符串方法 | 功能 |
---|---|
LPAD(s1,len,s2) | 在字符串 s1 的开始处填充字符串 s2,使字符串长度达到 len |
RPAD(s1,len,s2) | 在字符串 s1 的结尾处添加字符串 s2,使字符串的长度达到 len |
使用 LPAD(s1,len,s2) 或 RPAD(s1,len,s2) 可以分别在字符串里 s1 的左边或者右边添加字符串 s2 直到添加后的字符串的长度达到 len 。(其中 s1 是原字符串, s2 是要添加的字符串, len 是字符串规定的长度)
左边添加"#"号
#比如在前4个员工名字前面添加#符号,直到长度为10
SELECT lpad(emp_name,10,'#') from tb_employee limit 4;
+-----------------------+
| lpad(emp_name,10,'#') |
+-----------------------+
| #######赖晓畅 |
| #######谢又蓝 |
| #######吕芸溪 |
| #######谭淑慧 |
+-----------------------+
右边添加"#"号
#比如在前4个员工名字后面添加#符号,直到长度为10
SELECT rpad(emp_name,10,'#') from tb_employee limit 4;
+-----------------------+
| rpad(emp_name,10,'#') |
+-----------------------+
| 赖晓畅####### |
| 谢又蓝####### |
| 吕芸溪####### |
| 谭淑慧####### |
+-----------------------+
这两个函数在定长的字段上会使用到,比如数据位为10位,不足的补零。
2.8、截取字符串
截取字符串方法 | 功能 |
---|---|
SUBSTR(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串 |
SUBSTRING(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串 |
MID(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串 |
使用 SUBSTR(s, start, length) 或 SUBSTRING(s, start, length) 或 MID(s,start,len) 可以从字符串里 s 的指定位置截取指定长度的字符串。(其中 s 是原字符串, start 是开始截取的位置(从1开始), length 是截取的字符串的长度,长度不够或没有指定长度则是从指定截取到最后)
左边添加"#"号
#比如截取4个员工名字,从第2位开始
SELECT emp_name as '全名',substr(emp_name,2) as '简称' from tb_employee limit 4;
+-----------+--------+
| 全名 | 简称 |
+-----------+--------+
| 赖晓畅 | 晓畅 |
| 谢又蓝 | 又蓝 |
| 吕芸溪 | 芸溪 |
| 谭淑慧 | 淑慧 |
+-----------+--------+
三个函数差不多,一样的效果和使用,就不一一演示了
2.9、比较
使用 STRCMP(s1,s2) 可以比较两个字符串的大小,如果 s1 与 s2 相等返回 0 ,如果 s1>s2 返回 1,如果 s1<s2 返回 -1
SELECT STRCMP("Alian", "Alian") as '相等',
STRCMP("JavaScript", "Java") as '大于',
STRCMP("a", "b") as '小于',
STRCMP("alian", "Alian") as '不区分大小写';
+------------------+----------------------+----------+--------------------+
| Alian等于Alian | JavaScript大于Java | a小于b | 不区分大小写 |
+------------------+----------------------+----------+--------------------+
| 0 | 1 | -1 | 0 |
+------------------+----------------------+----------+--------------------+
三、数字函数
3.1、统计,求和,求平均值
方法 | 功能 |
---|---|
COUNT(expression) | 返回查询的记录总数,expression 参数是一个字段 或者 * 号 |
SUM(expression) | 返回指定字段的总和 |
AVG(expression) | 返回一个表达式的平均值,expression 是一个字段 |
统计
我们统计下部门编号为14员工的总数
#统计部门编号为14员工的总数
SELECT count(*) as '员工总数' from tb_employee where dep_code=14;
#或者
SELECT count(emp_code) as '员工总数' from tb_employee where dep_code=14;
+--------------+
| 员工总数 |
+--------------+
| 20 |
+--------------+
求和
我们算下部门编号为14的员工的总工资
#部门编号为14的员工的平均工资
SELECT sum(salary) as '总工资' from tb_employee where dep_code=14;
+-----------+
| 总工资 |
+-----------+
| 298000.00 |
+-----------+
求平均值
我们算下部门编号为14的员工的平均工资
#部门编号为14的员工的平均工资
SELECT avg(salary) as '平均工资' from tb_employee where dep_code=14;
+--------------+
| 平均工资 |
+--------------+
| 14900.000000 |
+--------------+
3.2、最值
我们说的最值就是最大值和最小值,最大值使用 MAX(expression) ,最小值使用 MIN(expression) ,expression 参数是一个 字段
方法 | 功能 |
---|---|
MAX(expression) | 返回字段 expression 中的最大值 |
MIN(expression) | 返回字段 expression 中的最小值 |
GREATEST(expr1, expr2, expr3, …) | 返回列表中的最大值 |
LEAST(expr1, expr2, expr3, …) | 返回列表中的最小值 |
字段最大值(纵向)
查询员工表中部门编号为14的员工最高工资
#查询员工表中部门编号为14的员工最高工资
SELECT max(salary) as '最高工资' from tb_employee where dep_code=14;
+--------------+
| 最高工资 |
+--------------+
| 34000.00 |
+--------------+
列表最大值(横向)
#获取列表最大值
SELECT greatest(10,33,88,20) as '列表最大值';
+-----------------+
| 列表最大值 |
+-----------------+
| 88 |
+-----------------+
#我们演示下greatest的使用
select dep_code,age,greatest(dep_code*3,age) as '列表中最大值' from tb_employee where emp_code in(8000,8003);
+----------+------+--------------------+
| dep_code | age | 列表中最大值 |
+----------+------+--------------------+
| 11 | 45 | 45 |
| 12 | 32 | 36 |
+----------+------+--------------------+
- 第一条记录当部门编号11乘以3后等于33,还是比年龄45小,所以取值是45
- 第二条记录部门编号12乘以3后等于36,它比年龄32大,所以取值是36
- 取值是横向的,并不是固定某一列
字段最小值(纵向)
查询员工表中部门编号为14的员工最低工资
#查询员工表中部门编号为14的员工最低工资
SELECT min(salary) as '最低工资' from tb_employee where dep_code=14;
+--------------+
| 最低工资 |
+--------------+
| 3000.00 |
+--------------+
列表最小值(横向)
#获取列表最小值
SELECT LEAST(10,33,88,20) as '列表最小值';
+-----------------+
| 列表最小值 |
+-----------------+
| 10 |
+-----------------+
那如何查询部门编号为14最高工资的员工信息呢?用子查询就可以查到了
#查询部门编号为14的最高工资的员工的员工编号,姓名及工资
SELECT emp_code,emp_name,salary
from tb_employee
where salary=(SELECT max(salary) as '最高工资' from tb_employee where dep_code=14)
and dep_code=14;
+----------+-----------+----------+
| emp_code | emp_name | salary |
+----------+-----------+----------+
| 8081 | 韩隽雅 | 34000.00 |
+----------+-----------+----------+
需要注意的是指定了部门编号,子查询外面的条件( and dep_code=14)不能少,不然查的就是全员工工资等于部门编号为14员工的最高工资的所有员工了。
3.3、取整
取整的方法 | 功能 |
---|---|
CEIL(x) 或 CEILING(x) | 返回大于或等于 x 的最小整数, 向上取整 |
FLOOR(x) | 返回小于或等于 x 的最大整数, 向下取整 |
ROUND(x) | 返回离 x 最近的整数,也就是 四舍五入 |
向上取整
#比如分别对1.0,1.2,1.5,1.8向上取整
SELECT ceil(1.0),ceil(1.2), ceil(1.5), ceil(1.8);
+-----------+-----------+-----------+-----------+
| ceil(1.0) | ceil(1.2) | ceil(1.5) | ceil(1.8) |
+-----------+-----------+-----------+-----------+
| 1 | 2 | 2 | 2 |
+-----------+-----------+-----------+-----------+
向下取整
#比如分别对1.0,1.2,1.5,1.8向上取整
SELECT floor(1.0),floor(1.2), floor(1.5), floor(1.8);
+------------+------------+------------+------------+
| floor(1.0) | floor(1.2) | floor(1.5) | floor(1.8) |
+------------+------------+------------+------------+
| 1 | 1 | 1 | 1 |
+------------+------------+------------+------------+
四舍五入
#比如分别对1.0,1.2,1.5,1.8四舍五入
SELECT round(1.0),(1.2), round(1.5), round(1.8);
+------------+-----+------------+------------+
| round(1.0) | 1.2 | round(1.5) | round(1.8) |
+------------+-----+------------+------------+
| 1 | 1.2 | 2 | 2 |
+------------+-----+------------+------------+
从上面三组结果大家就可以区分它们的作用了,最终都是得到整数,实际中根据需要选择即可。
3.4、随机数
使用 RAND() 可以返回 0 到 1 的随机数。
#得到一个随机数
SELECT rand();
+---------------------+
| rand() |
+---------------------+
| 0.05654980061254446 |
+---------------------+
那怎么得到从m到n的随机数呢?比如5到1000的随机数
#获取从5到1000的随机数
SELECT round(rand()*(1000-5)+5) as '随机数';
+-----------+
| 随机数 |
+-----------+
| 549 |
+-----------+
3.5、数学函数
方法 | 功能 |
---|---|
ABS(x) | 返回 x 的绝对值 |
MOD(x,y) | 返回 x 除以 y 以后的余数 |
POW(x,y) 或 POWER(x,y) | 返回 x 的 y 次方 |
SQRT(x) | 返回x的平方根 |
PI() | 返回圆周率(3.141593) |
这个没什么好说的
SELECT abs(-1) as '-1的绝对值',
mod(5,3) as '5模3',
pow(2,3) as '2的3次方',
sqrt(-1) as '16的平方根',
pi() as '圆周率';
+----------------+-------+-------------+----------------+-----------+
| -1的绝对值 | 5模3 | 2的3次方 | 16的平方根 | 圆周率 |
+----------------+-------+-------------+----------------+-----------+
| 1 | 2 | 8 | NULL | 3.141593 |
+----------------+-------+-------------+----------------+-----------+
3.6、三角函数
三角函数方法 | 功能 | 功能 |
---|---|---|
SIN(x) | sin A = 对边 / 斜边 | 求正弦值(参数是弧度) |
COS(x) | cos A = 邻边 / 斜边 | 求余弦值(参数是弧度) |
TAN(x) | tan A =对边 / 邻边 | 求正切值(参数是弧度) |
COT(x) | cot A= 邻边 / 对边 | 求余切值(参数是弧度) |
上面的A是角度,对边指的是角A的对边的长度,邻边指角A的邻边的长度,斜边
SELECT sin(30) as '正弦值',
cos(30) as '余弦值',
tan(30) as '正切值',
cot(30) as '余切值';
+---------------------+---------------------+--------------------+----------------------+
| 正弦值 | 余弦值 | 正切值 | 余切值 |
+---------------------+---------------------+--------------------+----------------------+
| -0.9880316240928618 | 0.15425144988758405 | -6.405331196646276 | -0.15611995216165922 |
+---------------------+---------------------+--------------------+----------------------+
四、日期函数
4.1、获取当前日期或当前时间
方法 | 功能 |
---|---|
LOCALTIME() 或 LOCALTIMESTAMP() 或 SYSDATE() | 返回本地日期和时间 |
CURRENT_TIMESTAMP() 或 NOW() | 返回当前日期和时间 |
CURRENT_DATE() 或 CURDATE() | 返回当前日期 |
CURRENT_TIME() 或 CURTIME() | 返回当前时间 |
获取当前时间+日期,当前日期,当前时间
#获取当前时间+日期,当前日期,当前时间
SELECT now(),curdate(),curtime();
+---------------------+------------+-----------+
| now() | curdate() | curtime() |
+---------------------+------------+-----------+
| 2022-03-08 08:54:59 | 2022-03-08 | 08:54:59 |
+---------------------+------------+-----------+
4.2、获取年月日时分秒
方法 | 功能 |
---|---|
YEAR(d) | 返回年份值,d是日期部分 |
MONTH(d) | 返回月份值,d是日期部分 |
DAY(d) | 返回日期值,d 的日期部分 |
HOUR(d) | 返回小时值,d 的日期部分 |
MINUTE(d) | 返回分钟值,d 的日期部分 |
SECOND(d) | 返回秒钟值,d 的日期部分 |
WEEK(d) 或 WEEKOFYEAR(d) | 计算日期 d 是本年的第几个星期,范围是 0 到 53 |
获取年月日时分秒
SELECT
year('2022-03-08 17:30:05') as '年',
month('2022-03-08 17:30:05') as '月',
day('2022-03-08 17:30:05') as '日',
hour('2022-03-08 17:30:05') as '时',
minute('2022-03-08 17:30:05') as '分',
second('2022-03-08 17:30:05') as '秒';
+------+------+------+------+------+------+
| 年 | 月 | 日 | 时 | 分 | 秒 |
+------+------+------+------+------+------+
| 2022 | 3 | 8 | 17 | 30 | 5 |
+------+------+------+------+------+------+
学以致用,实际中使用举例:
#获取员工编号为8000的入职的出生年月日
SELECT
year(hire_date) as '年',
month(hire_date) as '月',
day(hire_date) as '日'
from tb_employee where emp_code=8000;
+------+------+------+
| 年 | 月 | 日 |
+------+------+------+
| 2022 | 3 | 5 |
+------+------+------+
4.3、获取天和周
方法 | 功能 |
---|---|
DAYOFWEEK(d) | 计算日期d是一周中的第几天 |
DAYOFMONTH(d) | 计算日期d是一月中的第几天 |
DAYOFYEAR(d) | 计算日期d是一年中的第几天 |
LAST_DAY(d) | 返回给定日期的那一月份的最后一天 |
WEEK(d) 或 WEEKOFYEAR(d) | 计算日期d 是本年的第几个星期,范围是 0 到 53 |
WEEKDAY(d) | 日期 d 是星期几,0 表示星期一,1 表示星期二 |
YEARWEEK(date, mode) | 返回年份及第几周(0到53) |
SELECT
dayofweek('2022-03-08 17:30:05') as '一周中第几天',
dayofmonth('2022-03-08 17:30:05') as '一月中第几天',
dayofyear('2022-03-08 17:30:05') as '一年中第几天',
last_day('2022-03-08 17:30:05') as '月的最后一天',
week('2022-03-08 17:30:05') as '一年中第几周',
weekday('2022-03-08 17:30:05') as '星期几',
yearweek('2022-03-08 17:30:05') as '年周';
+--------------------+--------------------+--------------------+--------------------+--------------------+-----------+--------+
| 一周中第几天 | 一月中第几天 | 一年中第几天 | 月的最后一天 | 一年中第几周 | 星期几 | 年周 |
+--------------------+--------------------+--------------------+--------------------+--------------------+-----------+--------+
| 3 | 8 | 67 | 2022-03-31 | 10 | 1 | 202210 |
+--------------------+--------------------+--------------------+--------------------+--------------------+-----------+--------+
4.4、日期和时间的加减
方法 | 功能 |
---|---|
ADDDATE(d,n) | 计算起始日期 d 加上 n 天的日期 |
ADDTIME(t,n) | n 是一个时间表达式,时间 t 加上时间表达式 n |
SUBDATE(d,n) | 日期 d 减去 n 天后的日期 |
SUBTIME(t,n) | n 是一个时间表达式,时间 t 减去时间表达式 n |
DATE_ADD(d,INTERVAL expr type) | 计算起始日期d 加上一个时间段后的日期 |
DATE_SUB(d,INTERVAL expr type) | 计算起始日期d 减去一个时间段后的日期 |
加减日期
#当前日期加一天和减一天
SELECT
now() as '当前时间',
adddate(now(),1) as '当前时间加一天',
subdate(now(),1) as '当前时间减一天';
+---------------------+-----------------------+-----------------------+
| 当前时间 | 当前时间加一天 | 当前时间减一天 |
+---------------------+-----------------------+-----------------------+
| 2022-03-08 10:11:10 | 2022-03-09 10:11:10 | 2022-03-07 10:11:10 |
+---------------------+-----------------------+-----------------------+
加减时间
#当前时间加10秒和减10秒
SELECT
now() as '当前时间',
addtime(now(),10) as '当前时间加10秒',
subtime(now(),10) as '当前时间减10秒';
+---------------------+----------------------+----------------------+
| 当前时间 | 当前时间加10秒 | 当前时间减10秒 |
+---------------------+----------------------+----------------------+
| 2022-03-08 10:13:35 | 2022-03-08 10:13:45 | 2022-03-08 10:13:25 |
+---------------------+----------------------+----------------------+
加减时间还能使用表达式,注意表达式的格式,使用引号包裹
#当前时间加1小时2分3秒 和 当前时间减1小时2分3秒
SELECT
now() as '当前时间',
addtime(now(),'1:2:3') as '当前时间加1小时2分3秒',
subtime(now(),'1:2:3') as '当前时间减1小时2分3秒';
+---------------------+--------------------------------+--------------------------------+
| 当前时间 | 当前时间加1小时2分3秒 | 当前时间减1小时2分3秒 |
+---------------------+--------------------------------+--------------------------------+
| 2022-03-08 10:16:10 | 2022-03-08 11:18:13 | 2022-03-08 09:14:07 |
+---------------------+--------------------------------+--------------------------------+
#计算一个日期加上一个时间段后的时间
SELECT
now() as '当前时间',
DATE_ADD(now(), INTERVAL 1 year) as '加1年',
DATE_ADD(now(), INTERVAL 2 month) as '加2月',
DATE_ADD(now(), INTERVAL 3 day) as '加3天',
DATE_ADD(now(), INTERVAL 4 hour) as '加4小时',
DATE_ADD(now(), INTERVAL 5 minute) as '加5分钟',
DATE_ADD(now(), INTERVAL 6 second) as '加6秒钟';
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
| 当前时间 | 加1年 | 加2月 | 加3天 | 加4小时 | 加5分钟 | 加6秒钟 |
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
| 2022-03-08 12:16:47 | 2023-03-08 12:16:47 | 2022-05-08 12:16:47 | 2022-03-11 12:16:47 | 2022-03-08 16:16:47 | 2022-03-08 12:21:47 | 2022-03-08 12:16:53 |
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
#计算一个日期减去一个时间段后的时间
SELECT
now() as '当前时间',
DATE_SUB(now(), INTERVAL 1 year) as '减1年',
DATE_SUB(now(), INTERVAL 2 month) as '减2月',
DATE_SUB(now(), INTERVAL 3 day) as '减3天',
DATE_SUB(now(), INTERVAL 4 hour) as '减4小时',
DATE_SUB(now(), INTERVAL 5 minute) as '减5分钟',
DATE_SUB(now(), INTERVAL 6 second) as '减6秒钟';
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
| 当前时间 | 减1年 | 减2月 | 减3天 | 减4小时 | 减5分钟 | 减6秒钟 |
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
| 2022-03-08 12:20:42 | 2021-03-08 12:20:42 | 2022-01-08 12:20:42 | 2022-03-05 12:20:42 | 2022-03-08 08:20:42 | 2022-03-08 12:15:42 | 2022-03-08 12:20:36 |
+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
4.5、时间间隔
方法 | 功能 |
---|---|
TIMEDIFF(time1, time2) | 计算时间差值,time1-time2 |
DATEDIFF(d1,d2) | 计算日期 d1->d2 之间相隔的天数 |
PERIOD_DIFF(period1, period2) | 返回两个时段之间的月份差值,period1-period2 |
TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) | 计算时间差,返回 datetime_expr2 − datetime_expr1 的时间差 |
#两个时间的差值
SELECT
timediff('2022-03-10 18:30:10','2022-02-08 17:30:05') as '时分秒差值',
datediff('2022-03-10 18:30:10','2022-02-08 17:30:05') as '天数差值',
period_diff('202209','202203') as '月份差值';
+-----------------+--------------+--------------+
| 时分秒差值 | 天数差值 | 月份差值 |
+-----------------+--------------+--------------+
| 721:00:05 | 30 | 6 |
+-----------------+--------------+--------------+
- TIMEDIFF(time1, time2) 得到的结果只会有:时分秒,参数可以是年月日时分秒
- DATEDIFF(d1,d2) 得到的结果只有整数天,参数可以是年月日时分秒
- PERIOD_DIFF(period1, period2) 得到的结果只有整数月,注意格式有年月即可,不然你会得到你意想不到的结果
一个更强大的方法
#计算时间差值
SELECT
timestampdiff(year,'2020-03-10','2022-02-08') as '年数差',
timestampdiff(month,'2020-03-10','2022-02-08') as '月份差',
timestampdiff(day,'2022-03-10 18:30:10','2022-03-11 17:30:05') as '天数差',
timestampdiff(hour,'2022-03-10 18:30:10','2022-03-11 17:30:05') as '小时差',
timestampdiff(minute,'2022-03-10 18:30:10','2022-03-11 17:30:05') as '分钟差',
timestampdiff(second,'2022-03-10 18:30:10','2022-03-11 17:30:05') as '秒钟差';
+-----------+-----------+-----------+-----------+-----------+-----------+
| 年数差 | 月份差 | 天数差 | 小时差 | 分钟差 | 秒钟差 |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1 | 22 | 0 | 22 | 1379 | 82795 |
+-----------+-----------+-----------+-----------+-----------+-----------+
4.6、时间转化
方法 | 功能 |
---|---|
SEC_TO_TIME(s) | 将以秒为单位的时间 s 转换为时分秒的格式 |
TIME_TO_SEC(t) | 将以秒为单位的时间 s 转换为时分秒的格式 |
FROM_DAYS(n) | 计算从 0000 年 1 月 1 日开始 n 天后的日期 |
TO_DAYS(d) | 计算日期 d 距离 0000 年 1 月 1 日的天数 |
时间和秒之间的互转
#时间和秒之间的互转
SELECT
SEC_TO_TIME(3600) '3600秒转时间',
TIME_TO_SEC('1:00:00') as '时间(1:00:00)转秒';
+------------------+-----------------------+
| 3600秒转时间 | 时间(1:00:00)转秒 |
+------------------+-----------------------+
| 01:00:00 | 3600 |
+------------------+-----------------------+
0000 年 1 月 1 日开始后的日期与天进行互转
SELECT
FROM_DAYS(4383) as '4383天转特定日期',
TO_DAYS('0012-01-01') '特定日期转天';
+------------------------+--------------------+
| 4383天转特定日期 | 特定日期转天 |
+------------------------+--------------------+
| 0012-01-01 | 4383 |
+------------------------+--------------------+
然后你是不是觉得这个没有啥用啊?来来来,搞个实用的,假设我们知道员工是2008年6月6日出生的,那么他多少岁了呢?首先要要用到我们之前的知识: DATEDIFF(d1,d2)
#可以得他出生了多少天
SELECT datediff(now(), '2008-06-06'));
接下里,就可以用到刚刚学的知识了: FROM_DAYS(n)
#转为特殊的日期
SELECT FROM_DAYS(datediff(now(), '2008-06-06')));
然后就可以用之前的: YEAR(d)
#从日期得到年龄
SELECT year(FROM_DAYS(datediff(now(), '2008-06-06'))) as '年龄';
+--------+
| 年龄 |
+--------+
| 13 |
+--------+
本文写的时候是2022年3月,所以2008年6月6日出生的就是13岁,没错吧。你看是不是组合起来很强大?当然还有其他更简单的方式:
#得到年龄
SELECT TIMESTAMPDIFF(YEAR, '2008-06-06', CURDATE()) AS age
4.7、时间格式化
方法 | 功能 |
---|---|
STR_TO_DATE(string, format_mask) | 计算从 0000 年 1 月 1 日开始 n 天后的日期 |
DATE_FORMAT(d,f) | 按表达式 f的要求显示日期 d |
TIME_FORMAT(t,f) | 返回 |
#时间字符串转时间
select
str_to_date('03/01/2022','%m/%d/%Y') as '格式一',
str_to_date('20220308221006','%Y%m%d%H%i%s') as '格式二',
str_to_date('2022-03-12 15:47:08','%Y-%m-%d%H:%i:%s') as '格式三';
+------------+---------------------+---------------------+
| 格式一 | 格式二 | 格式三 |
+------------+---------------------+---------------------+
| 2022-03-01 | 2022-03-08 22:10:06 | 2022-03-12 15:47:08 |
+------------+---------------------+---------------------+
#时间格式化
SELECT DATE_FORMAT('2022-02-22 22:22:22','%Y-%m-%d %H:%i:%s') as '标准转化',
DATE_FORMAT('2022-02-22 22:22:22','%Y年%m月%d日%H时%i分%s秒') as '自定义转化';
+---------------------+----------------------------------+
| 标准转化 | 自定义转化 |
+---------------------+----------------------------------+
| 2022-02-22 22:22:22 | 2022年02月22日22时22分22秒 |
+---------------------+----------------------------------+
4.8、提取时间元素
使用 EXTRACT(type FROM d) 从日期 d 中获取指定的值,type 指定返回的值。
比如想获取’2022-03-08 22:00:08’的年月日时分秒
select
EXTRACT(year from '2022-03-08 22:00:08') as '年',
EXTRACT(month from '2022-03-08 22:00:08') as '月',
EXTRACT(day from '2022-03-08 22:00:08') as '日',
EXTRACT(hour from '2022-03-08 22:00:08') as '时',
EXTRACT(minute from '2022-03-08 22:00:08') as '分',
EXTRACT(second from '2022-03-08 22:00:08') as '秒';
+------+------+------+------+------+------+
| 年 | 月 | 日 | 时 | 分 | 秒 |
+------+------+------+------+------+------+
| 2022 | 3 | 8 | 22 | 0 | 8 |
+------+------+------+------+------+------+
还有很多的类型可以去提取的,可以去官网查看就不一一列举了。
五、高级函数
5.1、IF(expr,v1,v2)
使用 IF(expr,v1,v2) 当表达式expr的值为true时,返回v1,否则返回v2。比如你数据库性别字段男女存的是1和0,1表示男,0表示女,现在查询出结果显示男女。
SELECT emp_name as '姓名',if(gender='1','男','女') as '性别' FROM tb_employee limit 4;
+-----------+--------+
| 姓名 | 性别 |
+-----------+--------+
| 赖晓畅 | 男 |
| 谢又蓝 | 男 |
| 吕芸溪 | 女 |
| 谭淑慧 | 女 |
+-----------+--------+
5.2、IFNULL(v1,v2)
使用 IFNULL(v1,v2) 如果 v1 的值不为 NULL,则返回 v1,否则返回 v2。就相当于没有值就设置默认值一样的。
#查询员工的岗位信息,没有则显示未分配
SELECT
emp_name as '员工姓名',
ifnull(job,'未分配') as '岗位信息'
FROM tb_employee
where emp_code in(8000,8001);
+--------------+--------------+
| 员工姓名 | 岗位信息 |
+--------------+--------------+
| 赖晓畅 | 未分配 |
| 谢又蓝 | 技术总监 |
+--------------+--------------+
5.3、COALESCE(expr1, expr2, …, expr_n)
使用 COALESCE(expr1, expr2, …, expr_n) 可以返回参数中的第一个非空表达式(从左向右)
select COALESCE(null,2);
你感觉看起来没有啥用对不?实际上会有很多的场景,假设数据设置了一个int型的字段,但是没有设置默认值,那么就是null了,这个时候如果用sum时,那么结果也就是null,就会需要做很多的数据处理,甚至业务异常了。但是这个时候如果给一个0的默认值,问题自然就没有了。简单使用如下:
#工资如果
select COALESCE(sum(salary),0) as tt from tb_employee;