MySQL基础篇(运算符、排序分页、多表查询、函数)-2
https://developer.aliyun.com/article/1425387
单行函数
不同DBMS函数的差异
DBMS 之间的差异性很大,远大于同一个语言不同版本之间的差异。
比如:大部分DBMS使用(||)或者(+)来做拼接符,而在MySql中的字符拼接函数为concat()。
采用SQL函数的代码可移植性是很差的
MySQL的内置函数及分类
MySQL提供的内置函数从实现的功能角度可以分为:
- 数值函数
- 字符串函数
- 日期和时间函数
- 流程控制 函数
- 加密与解密函数
- 获取MySQL信息函数
- 聚合函数
分为两大类:
- 单行函数
- 操作数据对象
- 接受参数返回一个结果
- 只对一行进行变换
- 每行返回一个结果
- 可以嵌套
- 参数可以是一列或一个值
- 聚合函数(或分组函数)
数值函数、字符串函数、日期和时间函数
CONCAT(s1,s2,…,sn) | 连接s1,s2,…,sn为一个字符串 |
CONCAT_WS(x, s1,s2,…,sn) | 同CONCAT(s1,s2,…)函数,但是每个字符串之间要加上x |
TRUNCATE(x,y) | 返回数值 x 保留到小数点后 y 位的值(与 ROUND 最大的区别是不会进行四舍五入) |
SYSDATE() | 返回当前日期和时间 |
NOW() | 返回当前日期和时间 |
DATEDIFF(d1,d2) | 计算日期 d1->d2 之间相隔的天数 |
DATE_FORMAT(date,format) | date参数是合法的日期。format 规定日期/时间的输出格式 |
https://www.runoob.com/mysql/mysql-functions.html
流程控制函数
流程处理函数可以根据不同的条件,执行不同的处理流程,可以在SQL语句中实现不同的条件选择。 MySQL中的流程处理函数主要包括IF()、IFNULL()和CASE()函数。
函数 | 用法 |
IF(value,value1,value2) | 如果value的值为TRUE,返回value1, 否则返回value2 |
IFNULL(value1, value2) | 如果value1不为NULL,返回value1,否 则返回value2 |
CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 … [ELSE resultn] END | 相当于Java的if…else if…else… |
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 … [ELSE 值n] END相当于Java的switch…case…
示例
Mysql会把函数当成字段,所以我们一般给它起个别名
-- 1、IF(value,value1,value2) -- 如果value的值为TRUE,返回value1, 否则返回value2 SELECT IF(1>0,'data1','data2') -- 2、IFNULL(value1, value2) -- 如果value1不为NULL,返回value1,否 则返回value2 SELECT IF(1>0,'data1','data2') -- 3、CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 .... [ELSE resultn] END -- 相当于Java的if...else if...else... SELECT last_name, salary, CASE WHEN salary >= 15000 THEN '高薪' WHEN salary >= 10000 THEN '底薪' ELSE '半残' END 'details' FROM employees -- 4、CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 .... [ELSE 值n] END -- 相当于Java的switch...case... SELECT last_name, salary, CASE salary >= 15000 WHEN salary >= 15000 THEN '高薪' WHEN salary >= 10000 THEN '底薪' ELSE '半残' END 'details' FROM employees
加密与解密、信息、其他函数
MySQL中内置了一些可以查询MySQL信息的函数,这些函数主要用于帮助数据库开发或运维人员更好地 对数据库进行维护工作。
MySQL中有些函数无法对其进行具体的分类,但是这些函数在MySQL的开发和运维过程中也是不容忽视 的。
**
练习
# 1.显示系统时间(注:日期+时间) SELECT NOW() # 2.查询员工号,姓名,工资,以及工资提高百分之20%后的结果(new salary) SELECT employee_id, last_name, salary * 1.2 'new salary' FROM employees # 3.将员工的姓名按首字母排序,并写出姓名的长度(length) SELECT employee_id, LENGTH( last_name ) last_name FROM employees ORDER BY first_name DESC; # 4.查询员工id,last_name,salary,并作为一个列输出,别名为OUT_PUT SELECT CONCAT( employee_id, last_name, salary ) OUT_PUT FROM employees # 5.查询公司各员工工作的年数、工作的天数,并按工作年数的降序排序 SELECT DATEDIFF(SYSDATE(),hire_date) / 365 worked_years, DATEDIFF(SYSDATE(),hire_date) worked_days FROM employees ORDER BY worked_years DESC # 6.查询员工姓名,hire_date , department_id,满足以下条件:雇用时间在1997年之后,department_id -- 为80 或 90 或110, commission_pct不为空 SELECT last_name, hire_date, department_id FROM employees WHERE DATE_FORMAT(hire_date,'%Y') >= '1997' AND department_id IN (80,90,110) AND commission_pct IS NOT NULL # 7.查询公司中入职超过10000天的员工姓名、入职时间 SELECT last_name, hire_date FROM employees WHERE DATEDIFF(NOW(),hire_date) > 10000 # 8.做一个查询,产生下面的结果 -- -- <last_name> earns `<salary>` monthly but wants <salary*3> -- -- Dream Salary -- -- King earns 24000 monthly but wants 72000 SELECT CONCAT( last_name, ' earns ', TRUNCATE ( salary, 0 ), ' monthly but he wants ', TRUNCATE ( salary * 3, 0 )) 'Dream Salary' FROM employees -- 9.使用CASE-WHEN,按照下面的条件: -- -- job grade -- -- AD_PRES A -- -- ST_MAN B -- -- IT_PROG C -- -- SA_REP D -- -- ST_CLERK E -- -- 产生下面的结果 -- -- Last_name Job_id Grade -- -- king AD_PRES A SELECT last_name Last_name, job_id Job_id, CASE job_id WHEN 'AD_PRES' THEN 'A' WHEN 'ST_MAN' THEN 'B' WHEN 'IT_PROG' THEN 'C' WHEN 'SA_REP' THEN 'D' WHEN 'ST_CLERK' THEN 'E' ELSE 'F' END Grade FROM employees
聚合函数
聚合函数作用于一组数据,并对一组数据返回一个值。
聚合函数类型
- AVG()
- SUM()
- MAX()
- MIN()
- COUNT()
COUNT函数
作用
- 计算指定字段在查询结构中出现的个数
- COUNT(数字)这种情况是属于用数据库中不存在的字段表示,每一条记录它都会当成这个数字来计算个数。用其他数字也是一样
- 如果计算表中有多少条记录,如何实现?
- COUNT(*)
- COUNT(1)
- COUNT(具体字段):不一定对,如果该字段包含NULL值,那么NULL值是不会被包含进记录计算的
能不能使用count(列名)替换count(*)?
不要使用 count(列名)来替代 count() , count() 是 SQL92 定义的标准统计行数的语法,跟数 据库无关,跟 NULL 和非 NULL 无关。
说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
count(列名)和count(*)效率
如果使用的是MyISAM 存储引擎,则三者效率相同,都是o(1)
如果使用的是InnoDB存储引擎,则三者效率:cOUNT(*) =COUNT(1)>COUNT(字段)
聚合函数示例
-- 1、可以对数值型数据使用AVG 和 SUM 函数。 SELECT AVG(salary), MAX(salary), MIN(salary), SUM(salary) FROM employees 6461.682243 24000.00 2100.00 691400.00 -- 2、COUNT(*)返回表中记录总数,适用于任意数据类型。 SELECT COUNT(*) FROM employees; 107
GROUP BY的使用
很形象的图,下次忘了GROUP BY怎么用的话就想想这个图!!!
按照部门分组:
单个部门进行分组: SELECT department_id, AVG(salary), SUM(salary) FROM employees 多个部门进行分组: SELECT department_id, job_id, AVG( salary ) FROM employees GROUP BY department_id, job_id
GROUP BY注意事项
1、SELECT中出现的非组函数的字段必须声明在GPOUP BY中。
以下是错误的示范:
last_name属于普通的字段,所以它必须声明在GROUP BY中
SELECT department_id, job_id, last_name, AVG( salary ) FROM employees GROUP BY department_id, job_id
反之,GROUP BY中声明的字段可以不出现在SELECT中。
SELECT department_id, AVG( salary ) FROM employees GROUP BY department_id, job_id
2、GROUP BY 声明在FROM后面、WHERE后面,ORDER BY前面、LIMIT前
3、使用 WITH ROLLUP 关键字之后,在所有查询出的分组记录之后增加一条记录,该记录计算查询出的所 有记录的总和,即统计记录数量。
SELECT department_id, AVG( salary ) FROM employees GROUP BY department_id, job_id WITH ROLLUP
当使用ROLLUP时,不能同时使用ORDER BY子句进行结果排序,即ROLLUP和ORDER BY是互相排斥 的。
HAVING的使用
HAVING的作用就是过滤分组
但使用有以下条件:
- 行已经被分组
- 使用了聚合函数
- 满足HAVING 子句中条件的分组将被显示
- HAVING 不能单独使用,必须要跟 GROUP BY 一起使用
SELECT department_id, AVG( salary ) FROM employees GROUP BY department_id, job_id HAVING MAX(salary) >10000
如果过滤条件中使用了聚合函数,则必须使用HAVING来替换WHERE。否则,报错。
HAVING 必须声明在GROUP BY 的后面。
WHERE和HAVING的对比
- 区别1:
- WHERE 后面跟筛选条件的时候不能跟聚合函数
- HAVING和GROUP BY配合使用,可以用聚合函数当筛选条件
- 这决定了,在需要对数据进行分组统计的时候,HAVING 可以完成 WHERE 不能完成的任务。这是因为, 在查询语法结构中,WHERE 在 GROUP BY 之前,所以无法对分组结果进行筛选。HAVING 在 GROUP BY 之 后,可以使用分组字段和分组中的计算函数,对分组的结果集进行筛选,这个功能是 WHERE 无法完成 的。另外,WHERE排除的记录不再包括在分组中。
- 区别2:
- 如果需要通过连接从关联表中获取需要的数据,WHERE 是先筛选后连接,而 HAVING 是先连接 后筛选。
- 这一点,就决定了在关联查询中,WHERE 比 HAVING 更高效。因为 WHERE 可以先筛选,用一 个筛选后的较小数据集和关联表进行连接,这样占用的资源比较少,执行效率也比较高。HAVING 则需要 先把结果集准备好,也就是用未被筛选的数据集进行关联,然后对这个大的数据集进行筛选,这样占用 的资源就比较多,执行效率也较低。
WHERE | 先筛选数据在关联,执行效率高 | 不能使用分组中的计算函数进行筛选 |
HAVING | 可以使用分组中的计算函数 | 在最后的结果集中进行筛选,执行效率低 |
开发中的选择:
WHERE和HAVING并不冲突,我们可以同时使用它们,更好的发挥它们的优点
包含分组统计函数条件用HAVING,普通条件用WHERE。
当数据量特别大的时候,运行效率会有很 大的差别。
SELECT的执行原理
SELECT ...,....,... FROM ... JOIN ... ON 多表的连接条件 JOIN ... ON ... WHERE 不包含组函数的过滤条件 AND/OR 不包含组函数的过滤条件 GROUP BY ...,... HAVING 包含组函数的过滤条件 ORDER BY ... ASC/DESC LIMIT ...,... #其中: #(1)from:从哪些表中筛选 #(2)on:关联多表查询时,去除笛卡尔积 #(3)where:从表中筛选的条件 #(4)group by:分组依据 #(5)having:在统计结果中再次筛选 #(6)order by:排序 #(7)limit:分页
SELECT 查询时的两个顺序:
- 关键字的顺序是不能颠倒的
- SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY … LIMIT…
- SELECT 语句的执行顺序(在 MySQL 和 Oracle 中,SELECT 执行顺序基本相同)
- FROM -> WHERE -> GROUP BY -> HAVING -> SELECT 的字段 -> DISTINCT -> ORDER BY -> LIMIT
练习
#1.where子句可否使用组函数进行过滤? 不可以,where后面一般跟非组函数条件进行过滤 HAVING后面一般跟组函数进行过滤 #2.查询公司员工工资的最大值,最小值,平均值,总和 SELECT MAX(salary), MIN(salary), AVG(salary), SUM(salary) FROM employees #3.查询各job_id的员工工资的最大值,最小值,平均值,总和 SELECT job_id, MAX(salary), MIN(salary), AVG(salary), SUM(salary) FROM employees GROUP BY job_id #4.选择具有各个job_id的员工人数 -- COUNT()这里的参数可填*,1,employee_id -- 但是要注意如果填字段名,count不计算空值 SELECT job_id, COUNT(*) FROM employees GROUP BY job_id # 5.查询员工最高工资和最低工资的差距(DIFFERENCE) SELECT MAX( salary ) - MIN( salary ) 'DIFFERENCE' FROM employees # 6.查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内 SELECT manager_id, MIN( salary ) FROM employees WHERE -- salary > 6000 题中说到最低工资,所以应该用聚合函数MIN来求得最低工资然后进行判断 manager_id IS NOT NULL GROUP BY manager_id HAVING MIN(salary) >= 6000 # 7.查询所有部门的名字,location_id,员工数量和平均工资,并按平均工资降序 SELECT d.department_name, d.location_id, COUNT(employee_id), AVG( salary ) '平均工资' FROM departments d LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY department_name,location_id ORDER BY '平均工资' DESC # 8.查询每个工种、每个部门的部门名、工种名和最低工资 -- 这里的每个其实也可看成所有! -- 最后结果出现很多空值是因为部门有很多是没有人的,那么就会出现job_id和salary为空的情况 SELECT d.department_name, e.job_id, MIN( salary ) FROM departments d LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY department_name, job_id
易错点
查询所有部门的名字,location_id,员工数量和平均工资,并按平均工资降序
这里部门表左连接员工表,而部门表有很多空部门,这样员工表和部门表连接时就会出现很多空值。如果我们在用COUNT(*)计算员工数量时,那么它会把NULL的也给算进去,所以这里呢COUNT应该填字段名,让它进行一个排NULL操作
所以
SELECT d.department_name, d.location_id, COUNT(employee_id), AVG( salary ) '平均工资' FROM departments d LEFT JOIN employees e ON d.department_id = e.department_id GROUP BY department_name,location_id ORDER BY '平均工资' DESC
查询每个工种、每个部门的部门名、工种名和最低工资
这里的每个其实也可看成所有!
最后结果出现很多空值是因为部门有很多是没有人的,那么就会出现job_id和salary为空的情况
查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内
这里不能在WHERE后加salary > 6000
题中说到最低工资,所以应该用聚合函数MIN来求得最低工资然后进行判断