学习MySQL的第六天
夫天地者,万物之逆旅也;
光阴者,百代之过客也;
而浮生若梦,为欢几何?
一、日期与时间
1.1获取日期和时间
CURDATE() , CURRENT_DATE():返回当前日期,只包含年、月、日
CURTIME(), CURRENT_TIME() :返回当前时间,只包含时、分、秒
UTC_DATE():返回UTC(世界标准时间)日期
UTC_TIME():返回UTC(世界标准时间)时间
同时 NOW() SYSDATE() CURRENT_TIMESTAMP() LOCALTIME() LOCALTIMESTAMP()同样也是返回当前系统日期和时间,这些并不需要全部都记住
SELECT CURDATE(),CURRENT_DATE(),CURTIME(),NOW(),SYSDATE()
FROM DUAL;
1.2 日期与时间戳的转换
对于这个我们就直接引入代码了
SELECT UNIX_TIMESTAMP(),UNIX_TIMESTAMP('2005-7-15 22:30:30'),
FROM_UNIXTIME(202321456),FROM_UNIXTIME(1121437830)
FROM DUAL;
1.3 获取具体年份、月份、星期、星期数、天数等函数
SELECT CURDATE(),CURTIME(),YEAR(CURDATE()),MONTH(CURDATE()),DAY(CURDATE()),
HOUR(CURTIME()),MINUTE(NOW()),SECOND(SYSDATE())
FROM DUAL;
MONTHNAME('2001-10-26') -- 返回给定日期的月份名称
DAYNAME('2021-10-26') -- 返回给定日期的星期名称
WEEKDAY('2021-10-26') -- 返回给定日期的星期索引(0=周一,6=周日)
QUARTER(CURDATE()) -- 返回当前日期的季度
WEEK(CURDATE()) -- 返回当前日期的周数
DAYOFYEAR(NOW()) -- 返回当前日期在一年中的第几天
SELECT MONTHNAME('2001-10-26'),DAYNAME('2021-10-26'),WEEKDAY('2021-10-26'),
QUARTER(CURDATE()),WEEK(CURDATE()),DAYOFYEAR(NOW())
FROM DUAL;
1.4 日期的操作函数
EXTRACT(unit FROM date): 可以返回指定日期中特定的部分
# 返回当前时间
SELECT EXTRACT(HOUR FROM NOW()),EXTRACT(QUARTER FROM '2005-7-15')
FROM DUAL;
1.5 其它时间类函数补充
# 时间和秒钟
SELECT TIME_TO_SEC(CURTIME()),
SEC_TO_TIME(83355)
FROM DUAL;
# 计算日期和时间函数
SELECT DATE_ADD(NOW(),INTERVAL 1 YEAR),
DATE_ADD(NOW(),INTERVAL -1 YEAR),
DATE_SUB(NOW(),INTERVAL 1 YEAR)
FROM DUAL;
# 修改现在的日期时间
SELECT DATE_ADD(NOW(),INTERVAL 1 DAY) AS coll,DATE_ADD(NOW(),INTERVAL '1_1' YEAR_MONTH)
FROM DUAL;
SELECT ADDTIME(NOW(),2000),SUBTIME(NOW(),300),SUBTIME(NOW(),'1:2:3'),DATEDIFF(NOW(),'2020-7-15'),TIMEDIFF(NOW(),'2021-10-10 22:10:5'),FROM_DAYS(366),MAKEDATE(10,1)
FROM DUAL;


1.6 日期和时间的格式化和解析
格式化:日期--->字符串
SELECT DATE_FORMAT(CURDATE(),'%Y-%M-%D'),
DATE_FORMAT(NOW(),'%Y-%M-%D'),TIME_FORMAT(CURTIME(),'%h:%i:%S'),
DATE_FORMAT(NOW(),'%Y-%M-%D %h:%i:%S %W %w %T %r')
FROM DUAL;
解析:字符串--->日期,也就是格式化的逆过程
SELECT STR_TO_DATE('2021-October-25th 11:34:42 Monday','%Y-%M-%D %h:%i:%S %W')
FROM DUAL;
二、流程控制
2.1 判断语句
IF(expr1,expr2,expr3):符合expr1条件就返回expr2,否则返回expr3
SELECT name,salary,IF(salary>=600,'A','B') '等级',department_id,IF(department_id IS NOT NULL,department_id,0)
FROM employees;
2.2 选择语句
CASE WHEN... THEN ... WHEN ... THEN ...ELSE ...END
SELECT name,salary,
CASE WHEN salary >=900 THEN 'A'
WHEN salary >=600 THEN 'B'
WHEN salary >=300 THEN 'C'
ELSE 'D' END '等级'
FROM employees
ORDER BY salary DESC
SELECT `name`,salary,
CASE salary
WHEN 900 THEN 'A'
WHEN 600 THEN 'B'
WHEN 300 THEN 'C'
END 'A'
FROM employees
WHERE salary>=600
2.3 加密解密函数
PASSWORD(str):返回字符串str的加密版本,41位长的字符串,加密结果不可逆,常用于用户的密码加密
ENCODE(value,password_seed):返回使用password_seed作为加密密码加密value
DECODE(value,password_seed):返回使用password_seed作为加密密码解密value
不过由于MySQL8.0版本对这些语句都不支持,如果想试一试,可以用MySQL5.0
2.4 MySQL信息函数
用来查找与MySQL相关的一些信息
SELECT VERSION(),CONNECTION_ID(),DATABASE(),SCHEMA(),
USER(),CURRENT_USER(),CHARSET('上岸'),COLLATION('一')
2.5 其他函数
# 如果n的值小于或等于0,则只保留整数部分
SELECT FORMAT(123.125,2),FORMAT(123.125,-2),FORMAT(123.125,0)
FROM DUAL;
SELECT CONV(16,10,2),CONV(8888,10,16),CONV(NULL,10,2)
FROM DUAL;
# 将IP地址转化为整数 以及 转为IP地址
SELECT INET_ATON('168.121.1.100'),INET_NTOA(3333322222)
FROM DUAL;
# BENCHMARK(count,expr):用于测试表达式执行count次,所需的时间和效率
SELECT BENCHMARK(10000,MD5('MySQL'))
FROM DUAL; # 在运行时间查看
# CONVERT(expr USING transcoding_name): 实现字符集的转换
SELECT CHARSET('html'),CONVERT('html' USING 'utf8mb4')
FROM DUAL;

三、聚合函数
3.1 常见的几个聚合函数
3.1.1 AVG/SUM
AVG(): 平均工资,不计算null值
SUM(): 求和公式,不计算null值
只适用于数值计算
SELECT AVG(salary),SUM(salary)
FROM employees
3.1.2 MAX/MIN
MAX、MIN:求最大最小值,适用于数值、字符串、日期时间类型的字段
SELECT MAX(salary),MIN(salary),MAX(name),min(name)
FROM employees;
3.1.3 COUNT
COUNT: 计算指定字段在查询结构中出现的个数,需要注意的是计算指定字段出现的个数时,是不计算值为null的条数的
SELECT count(salary),count(name),COUNT(email),count(2*email),count(1)
FROM employees;
3.1.4 小结
1. 计算表中有多少条记录,可以通过三种方法来实现:
(1) COUNT(*)
(2) COUNT(n):n为任意整数
(3) COUNT(具体字段) : 因为不计算null,所以包含 null 时不一定正确
2. AVG = SUM/COUNT:在没有空值的情况下
SELECT AVG(salary),SUM(salary)/COUNT(salary)
FROM employees;
3.2 GROUP BY
通过字段进行分组操作
示例一:
# 查询最高工资,按照top_id进行分组
SELECT AVG(salary),SUM(salary),top_id,count(top_id)
FROM employees
GROUP BY top_id with ROLLUP // 进行排序
示例二:
# 分组之后再分组
SELECT top_id,garden,AVG(salary),SUM(salary),count(top_id)
FROM employees
GROUP BY top_id,garden
ORDER BY top_id ASC
注意:
(1) 如果被依照的列中存在null值,那么该列不能用
(2) SELECT 中出现的非组函数的字段,必须声明在 GROUP BY中
(3) GROUP BY中出现的字段,不必出现在 SELECT中
(4) GROUP BY在 FROM后面,WHERE后面,ORDER BY之前,LIMIT之前
四、HAVING函数
HAVING函数的作用和WHERE相似,都是用来过滤数据,但是两者的作用有所不同
我们通过具体的案例来一步步的学习 HAVING函数
问题:查询各个top_id中最高工资比500高的top_id信息
我们先用传统的 WHERE函数来进行
错误示例:
SELECT top_id,MAX(salary)
FROM employees
WHERE MAX(salary) > 500
GROUP BY top_id

但是很显然这样是错误的,但是这是为什么呢?
原因(结论):
(1)如果过滤条件中使用了聚合函数,则必须使用 HAVING来替换 WHERE,否则会报错
(2)HAVING必须声明在 GROUP BY后面
(3)使用 HAVING的前提是使用了 GROUP BY
正确做法:
SELECT top_id,MAX(salary)
FROM employees
GROUP BY top_id
HAVING MAX(salary) > 500
那么我们进行一个练习:查询top_id为1、2、4的两个部门中最高工资高于400的部门信息
SELECT top_id,MAX(salary)
FROM employees
WHERE top_id IN (1,2,4)
GROUP BY top_id
HAVING MAX(salary) > 400
# 或
SELECT top_id,MAX(salary)
FROM employees
GROUP BY top_id
HAVING MAX(salary) > 400 AND top_id IN (1,2,4)
我们对此进行一个补充:当没有聚合函数时,过滤条件在HAVING 和 WHERE中都可以,当有聚合函数时,只能在 HAVING中,不过在没有聚合函数时, WHERE的效率高,所以,我们一般建议能用 WHERE就不用 HAVING
五、SQL底层执行原理
5.1 SELECT 语句的完整结构
SQL92 语法:{
SELECT ......(存在聚合函数)
FROM .......
WHERE 多表的连接条件 AND 不包含聚合函数的过滤条件
GROUP BY .....
HAVING 包含聚合函数的过滤条件
ORDER BY ....(ASC / DESC)
LIMIT ....
}
SQL99 语法:{
SELECT ......(存在聚合函数)
FROM ...(LEFT / RIGHT )JOIN ...ON 多表的连接条件
JOIN ... ON ...
WHERE 不包含聚合函数的过滤条件
GROUP BY ....
HAVING 包含聚合函数的过滤条件
ORDER BY ....(ASC / DESC)
LIMIT ....
}
5.2 SQL 语句的执行过程
FROM...... ->ON(连接条件) ->(判断是 LEFT还是RIGHT JOIN) -> 过滤数据(WHERE)
-> GROUP BY -> HAVING ( <- 前面是对行数进行限制 ) -> SELECT...(对列数进行限制)
->DISTINCT(去重) -> ORDER BY -> LIMIT(分页 )
须知少日拏云志,曾许人间第一流。我们还年轻,我们还有无限可能!