Mysql查询高级

与世无争的帅哥 提交于 2020-04-06 21:43:34

一、SELECT的子句

/*
基本查询:
select * from 表名称 【where 条件】;
select 字段列表 from 表名称 【where 条件】;

扩展查询,select语句的5个子句:
(1)where
     where 条件   用于从表中筛选出符合条件的记录(行)
(2)group by
(3)having
(4)order by
(5)limit

这5个子句可以同时出现,也可以只出现其中的一部分,其中如果有having前面得有group by,但是有group by不一定有having
如果5个子句有多个同时出现的,那么必须按照(1)-(5)的顺序
例如:要分组统计之前,需要把满足条件的行先筛选出来,或者说把不满足条件的行排除掉才能统计
*/
#查询所有的女员工
SELECT * FROM t_employee WHERE gender = '女';

#查询所有女员工的姓名和薪资
SELECT ename,salary FROM t_employee WHERE gender = '女';

1、分组函数

/*
分组函数
(1)sum
(2)count
(3)avg
(4)max
(5)min
*/
#查询全公司本月要发多少钱,暂时不考虑奖金和扣除的钱
#即查询全公司所有员工的工资总数
SELECT SUM(salary) AS "工资总数" FROM t_employee;

#查询全公司的员工总数
SELECT COUNT(eid) AS "总人数" FROM t_employee;  #如果count(字段名)那么会排除该字段是null值的行
SELECT COUNT(1) AS "总人数" FROM t_employee;    #如果count(常量值)或count(*)那么统计的是行数
SELECT COUNT(*) AS "总人数" FROM t_employee;

#查询全公司的平均工资
SELECT AVG(salary) AS "全公司的平均工资" FROM t_employee;

#查询全公司的最高工资
SELECT MAX(salary) AS "全公司的最高工资" FROM t_employee;

#查询全公司的最低工资
SELECT MIN(salary) AS "全公司的最低工资" FROM t_employee;

#查询全公司的女员工的平均工资和最高工资、总工资
SELECT AVG(salary),MAX(salary),SUM(salary) FROM t_employee WHERE gender = '女';

#查询did=5部门的女员工的平均工资和最高工资、总工资
SELECT AVG(salary),MAX(salary),SUM(salary) FROM t_employee WHERE gender = '女' AND did = 5;

2、分组统计:GROUP BY

/*
group by:分组统计
*/

#查询每个部门的平均工资
SELECT did,AVG(salary) FROM t_employee GROUP BY did;

#查询每个部门的平均工资,排除没有部门的员工
SELECT did,AVG(salary) FROM t_employee WHERE did IS NOT NULL GROUP BY did ;

#查询每个部门编号,部门名称,和平均工资,排除没有部门的员工
#需要联合查询
#用SELECT did,AVG(salary) FROM t_employee WHERE did IS NOT NULL GROUP BY did ;结果和部门表联合查询

#查询每个部门的女员工的最高工资
SELECT did,MAX(salary) FROM t_employee WHERE gender = '女' GROUP BY did;
SELECT did,MAX(salary) FROM t_employee WHERE gender = '女' AND did IS NOT NULL GROUP BY did;

#查询男、女员工的平均工资
SELECT gender,AVG(salary) FROM t_employee GROUP BY gender;

#查询每个部门的男、女员工的平均工资分别是多少
#先按部门再按男女
SELECT did, gender, AVG(salary) FROM t_employee GROUP BY did,gender;
SELECT did, gender, AVG(salary) FROM t_employee WHERE did IS NOT NULL GROUP BY did,gender;

#查询每个部门的工资总数
SELECT did,SUM(salary) FROM t_employee GROUP BY did;

#查询每个部门的男、女员工的人数
SELECT did, gender, COUNT(*) FROM t_employee WHERE did IS NOT NULL GROUP BY did,gender;

3、GROUP BY 的好搭档,分组过滤:HAVING

/*
having:写条件

where和having的区别:
(1)where后面是不允许使用分组函数,having后面可以加分组函数
(2)where是用于“原”表中的记录的筛选,而having是用于“统计结果”的筛选

*/

#查询每个部门的平均工资,只显示平均工资在12000以上的
SELECT did,AVG(salary) FROM t_employee  GROUP BY did HAVING AVG(salary) > 12000

#查询每个部门的最高工资,要求显示最高工资低于12000
SELECT did,MAX(salary) FROM t_employee GROUP BY did HAVING MAX(salary) < 12000
SELECT did,MAX(salary) AS "m" FROM t_employee GROUP BY did HAVING m < 12000

4、结果太乱,排序找他:ORDER BY

/*
order by:排序
   order by 字段名/统计结果 【DESC/ASC】, 字段名/统计结果 【DESC/ASC】 ...
*/

#查询员工的姓名和薪资,按照薪资的从高到低排序
SELECT ename,salary FROM t_employee ORDER BY salary DESC;

#查询员工的编号,姓名和薪资,按照薪资的从高到低排序,如果薪资相同,再按照编号升序排列
SELECT eid,ename,salary FROM t_employee ORDER BY salary DESC,eid ASC;

#查询每个部门的平均工资,按照平均工资的升序排序
SELECT did,AVG(salary) FROM t_employee GROUP BY did ORDER BY AVG(salary) ASC;

#查询每个部门的女员工的平均工资,按照平均工资的升序排序,并且只显示平均工资高于12000的
SELECT did,AVG(salary) 
FROM t_employee 
WHERE gender = '女' 
GROUP BY did 
HAVING AVG(salary) > 12000
ORDER BY AVG(salary) ASC;

5、结果太多,限制能手:LIMIT

/*
limit m,n

从第m条开始,输出n条;应用到分页场景中
m = (page - 1)*每页的记录数
n = 每页的记录数
*/

#查询员工信息,每页显示10条,显示第一页
SELECT * FROM t_employee LIMIT 0,10

#查询员工信息,每页显示10条,显示第二页
SELECT * FROM t_employee LIMIT 10,10

#查询员工信息,每页显示5条,显示第三页
SELECT * FROM t_employee LIMIT 10,5

#查询每个部门的女员工的平均工资,按照平均工资的升序排序,并且只显示平均工资高于12000的,
#每页显示1条,显示第二页
SELECT did,AVG(salary) 
FROM t_employee 
WHERE gender = '女' 
GROUP BY did 
HAVING AVG(salary) > 12000
ORDER BY AVG(salary) ASC
LIMIT 1,1;

二、子查询

/*
某些情况下,当进行一个查询时,需要的条件或数据要用另外一个 select 语句的结果,
这个时候,就要用到子查询。

先于当前查询执行的,并且是嵌套在当前查询中的查询叫做子查询。
子查询分为:
(1)where型
子查询嵌套在where里面
 条件的运算符分为两类:
	=,>,>=,<,<=,!=  后面接子查询的结果必须是“单值”
	in, = any, >all,>= ,<all.....  后面接子查询的结果可以是“多值”
(2)from型
子查询嵌套在from后面

(3)exists型
*/

1、WHERE 型

/*
where型
*/
#查询全公司最高工资的员工的信息
#(1)查询最高工资
SELECT MAX(salary) FROM t_employee;

#(2)查询最高工资的员工的信息
SELECT * FROM t_employee WHERE salary = 130990

#(3)合起来
SELECT * FROM t_employee WHERE salary = (SELECT MAX(salary) FROM t_employee)

#查询和孙红雷,刘烨,范冰冰三个人中任意一个工资一样的员工
#查询孙红雷,刘烨,范冰冰三个人工资
SELECT salary FROM t_employee WHERE ename IN ('孙红雷','刘烨','范冰冰');

#查询和孙红雷,刘烨,范冰冰三个人中任意一个工资一样的员工
SELECT * FROM t_employee WHERE salary IN (SELECT salary FROM t_employee WHERE ename IN ('孙红雷','刘烨','范冰冰'))
SELECT * FROM t_employee WHERE salary = ANY (SELECT salary FROM t_employee WHERE ename IN ('孙红雷','刘烨','范冰冰'))

#查询比李冰冰工资高的女员工
SELECT * FROM t_employee WHERE gender = '女' AND salary > (SELECT salary FROM t_employee WHERE ename = '李冰冰');


#查询全公司最高工资的员工的信息
SELECT * FROM t_employee WHERE salary >= ALL(SELECT salary FROM t_employee)

2、FROM 型

/*
from型
*/
#查询每个部门编号,部门名称,和平均工资,排除没有部门的员工,包括那些没有员工的部门
#第一步,查询每个部门的平均工资,排除没有部门的员工
SELECT did,AVG(salary) FROM t_employee  WHERE did IS NOT NULL GROUP BY did;

#第二步:用刚才的结果和t_department联合查询
SELECT t_department.*, temp.pingjun
FROM t_department LEFT JOIN (SELECT did,AVG(salary) AS pingjun FROM t_employee  WHERE did IS NOT NULL GROUP BY did) AS temp
ON t_department.did = temp.did

3、EXISTS 型

/*
exists型
*/
#查询部门信息,该部门必须有员工
SELECT * FROM t_department
WHERE EXISTS (SELECT * FROM t_employee WHERE t_employee.did = t_department.did)

#把`SELECT * FROM t_department`每一行记录,根据t_employee.did = t_department.did,代入到(SELECT * FROM t_employee)中查,如果可以查到结果,说明该行要留下,否则就排除掉


#查询部门信息,该部门必须有员工
#使用内连接查询,也可以实现
SELECT  DISTINCT t_department.* 
FROM t_department INNER JOIN t_employee
ON t_employee.did = t_department.did

SELECT  t_department.* 
FROM t_department INNER JOIN t_employee
ON t_employee.did = t_department.did
GROUP BY did

三、单行函数

/*
单行函数和分组函数:
只对某一行的记录做运算,
分组函数是多行一起统计/合计运算。

分组函数:sum,count,avg,max,min都是针对多行求一个结果

1、数学函数

数学函数:
 round(x,y):小数点后取y位,并且四舍五入
 truncate(x,y):直接截掉,保留x的小数点后取y位
*/
#查询员工的姓名,薪资,薪资保留小数点后一位
SELECT ename,salary,ROUND(salary,1) FROM t_employee;

#查询员工的姓名,薪资,薪资保留小数点后一位
SELECT ename,salary,TRUNCATE(salary,1) FROM t_employee;

#select ceil(2.2),floor(2,2);
SELECT CEIL(2.2),FLOOR(2.2);

#求每个部门的平均工资
SELECT did, ROUND(AVG(salary),2) FROM t_employee GROUP BY did;

2、字符串函数

/*
字符串函数
*/
#查询每个员工的姓,不考虑复姓
SELECT ename AS "姓名", LEFT(ename,1) AS "姓" FROM t_employee;
/*
java:下标从0开始,
str.substring(index)
str.substring(start,end)
mysql:下标从1开始
substring(str,index)
substring(str,start,len)
*/
SELECT ename AS "姓名", SUBSTRING(ename,1,1) AS "姓" FROM t_employee;

#查询员工的姓名的长度
/*
java中:
str.length()
mysql中:
length(str):求字符串的长度,字节数
char_length(str)
*/
SELECT ename, LENGTH(ename) FROM t_employee;
SELECT ename, CHAR_LENGTH(ename) FROM t_employee;

#查询所有名字是3个字的员工
SELECT * FROM t_employee WHERE CHAR_LENGTH(ename) = 3;

/*
java中字符串拼接:
(1)+
(2)str.concat(xx)
mysql中字符串的拼接:
只能用concat()

在mysql中的+,都是求和,如果不是数字,会尽力而为求和,结果不一定对
*/
#查询员工的姓名和手机号码,结果要显示为:孙红雷:13789098765
SELECT CONCAT(ename,':',tel) FROM t_employee;

/*
在java中trim()表示去掉前后空白格
在mysql中,trim系列的函数
*/
SELECT CONCAT('[',TRIM('     hello world    '),']')
SELECT CONCAT('[',LTRIM('     hello world    '),']')
SELECT CONCAT('[',RTRIM('     hello world    '),']')

SELECT CONCAT('[',TRIM(BOTH '&' FROM '&&&&&hello world&&&&'),']')
SELECT CONCAT('[',TRIM(LEADING '&' FROM '&&&&&hello world&&&&'),']')
SELECT CONCAT('[',TRIM(TRAILING '&' FROM '&&&&&hello world&&&&'),']')

3、日期时间函数

/*
日期时间函数
*/
#获取当前的系统时间
SELECT NOW(),SYSDATE()
SELECT CURRENT_DATE(),CURRENT_TIME()

#查询当前的年份
SELECT YEAR(CURRENT_DATE())

#查询满足40岁的员工
SELECT * FROM t_employee WHERE YEAR(NOW()) - YEAR(birthday) > 40

#查询入职已经满5年的员工
SELECT * FROM t_employee 
WHERE YEAR(NOW()) - YEAR(hiredate) > 5;

SELECT * FROM t_employee WHERE (DATEDIFF(CURRENT_DATE(),hiredate) DIV 365) >=5;


#计算当前日期,再过130天是什么日期
SELECT DATE_ADD(CURRENT_DATE(),INTERVAL  130 DAY)

#计算当前日期,45天前是什么日期
SELECT DATE_ADD(CURRENT_DATE(),INTERVAL  -45 DAY)

/*
除了在JAVA中可以把字符串转日期时间,或者把日期时间转字符串,
在mysql中也可以
*/
SELECT DATE_FORMAT(NOW(),'%y年%c月%e日');

SELECT STR_TO_DATE('19年1月18日','%y年%c月%e日')

4、加密函数

/*
加密函数:
password(x)
md5(x)
*/
INSERT INTO t_user VALUES(2,'lin',PASSWORD('123456'));
INSERT INTO t_user VALUES(3,'yan',MD5('123456'));

SELECT * FROM t_user WHERE username='lin' AND `password` = PASSWORD('123456');

流程控制

/*
在Java中有if..else,switch...case等流程控制语句结构
mysql中有对应的函数
(1)ifnull(x,value):如果x是null,就用value计算,否则还是用x计算
(2)CASE
	WHEN 条件1 THEN result1
	WHEN 条件2 THEN result2
	...
	[ELSE resultn]
     END
*/

#查询员工的姓名,薪资,奖金比例,实发工资
#实发工资 = 薪资 + 薪资 * 奖金比例
SELECT ename,salary,commission_pct, salary + salary * IFNULL(commission_pct,0)  AS "实发工资" FROM t_employee;

/*查询员工的信息,
如果薪资高于20000,显示该员工是“高富帅”,
如果薪资在15000-20000之间,显示“潜力股”
如果薪资在10000-15000之间,显示“有为青年”
如果薪资在10000以下,显示“屌丝"

相当于if...else if...
*/
SELECT	ename, salary,
	CASE
		WHEN salary>=20000 THEN "高富帅"
		WHEN salary>=15000 THEN "潜力股"
		WHEN salary>=10000 THEN "有为青年"
		ELSE "屌丝"
	END AS "标签"
FROM t_employee;

#查询订单表,显示订单编号,和订单状态,如果订单状态是0,显示新订单,是1,显示已付款...
/*
相当于switch...case
*/
SELECT	oid ,price,
	CASE state
		WHEN 0 THEN "新建订单"
		WHEN 1 THEN "已付款"
		WHEN 2 THEN "已发货"
		WHEN 3 THEN "已收货"
	END
FROM t_order;

四、事务

/*
事务:表示一组操作(sql),要么同时成功,要么同时失败,那么这种操作就构成了一个事务。
例如:
	张三  给  李四  转账  500元
	(1)把张三的余额减少500
	...
	(2)把李四的余额增加500
	
	不允许出现:张三的钱减少了500,而李四的钱没有加。
需要在(1)之前开启事务,如果同时成功,那么就提交这个事务,否则就回滚(还原到(1))之前的状态。

涉及到的语句:
(1)开启事务的语句
start transaction;
(2)提交事务/回滚事务
commit;/rollback;

mysql默认情况下是自动提交事务模式,即执行一句,自动提交一句,一旦提交就不能回滚。
如果想要开始手动提交模式,那么可以通过以下语句完成: set autocommit = false;

(1)手动提交模式
如果开始了手动提交模式,那么一组sql语句,直到commit或rollback才算是结束,
从这里commit/rollback到下一个commit或rollback之间算是另一个事务。
每一组操作都要手动提交或回滚。

(2)自动提交模式,然后单独的一组操作,想要开始手动提交模式的话,可以使用
start transaction;  #只能用于命令行,不能用于JDBC的Java代。
commit;/rollback;
*/

#开启手动提交模式,作用范围是一次连接(从登录到退出)
SET autocommit = FALSE;

DELETE FROM t_department WHERE did > 5;

INSERT INTO t_department VALUES(NULL,'yy','yyyy');

ROLLBACK;
#COMMIT;

SET autocommit = TRUE;

DELETE FROM t_department WHERE did > 5;

START TRANSACTION;
INSERT INTO t_department VALUES(NULL,'yy','yyyy');
UPDATE t_department SET dname = '后勤服务部' WHERE did = 5;
COMMIT;

/*
面试题:事务的特点、特性?
ACID:
(1)原子性:事务的sql语句的划分,必须小到不能在小。
             这一组操作是否真的要求:要么同时成功,要么同时失败。
(2)一致性:要保证事务前后数据一致性      
	例如:张三原来余额:500,李四原来余额:2000,张三要给李四转500
	 一致性:
	 	事务之前:张三原来余额:500,李四原来余额:2000
		事务之后:如果失败,张三余额:500,李四原来余额:2000
			  如果成功,张三余额:0,李四原来余额:2500
(3)隔离性:
	两个事务之间是独立。
	例如:	张三给李四转500
		李四给王五转1000
		赵六给李四转800
		这三个事务是独立的,张三给李四转账的成功与失败与  其他两个操作无关。
(4)持久性:一旦提交就确定了。

mysql中只有Innodb引擎才支持事务。
事务只对DML语句有效,对DDL语句无效。
*/
/*
事务的隔离级别:

1、为什么要隔离?
保证事务的独立的。
但是很多时候,事务之间有互相影响的。两个事务对同一个表的同一个记录的修改,这就互相影响了。

在Java中就是线程安全问题。在mysql中这种问题也是线程安全问题。
那么它表现出来的问题现象:
(1)脏读
     一个事务读取了另一个事务还未提交的数据
(2)不可重复读
     一个事务读取了另一个事务“修改”已提交的数据,导致一个事务期间对同一个数据的前后两次读取,结果不一致。
(3)幻读
     一个事务读取了另一个事务新增加并已经提交的数据,导致一个事务期间记录数不一样。
     一个事务读取了另一个事务删除并已经提交的数据,导致一个事务期间记录数不一样。

mysql的默认隔离级别是:(3)
(1)READ-UNCOMMITTED:读取未提交的数据
(2)READ-COMMITTED:读取已提交的数据
(3)REPEATABLE-READ:可重复读取
(4)SERIALIZABLE:序列化
serializable

查看当前连接的隔离级别:select @@tx_isolation;
修改当前连接的隔离级别:set tx_isolation = 'READ-UNCOMMITTED';

如果当前连接的隔离级别是READ-UNCOMMITTED,你会读取到别人未提交的数据,这个现象称为脏读。
如果避免“脏读”,就是提高隔离级别,提高为READ-COMMITTED或它以上。

如果当前连接的隔离级别是READ-UNCOMMITTED和READ-COMMITTED,都会出现不可重复的的现象,
如果要避免“不可重复读”,还是提高隔离级别,提高为REPEATABLE-READ或它以上。

(3)REPEATABLE-READ和(4)SERIALIZABLE都能避免脏读、不可重复读、幻读,那么有什么区别呢?
REPEATABLE-READ:行
SERIALIZABLE:表

*/

五、权限管理

/*
mysql:权限验证分两个阶段
(1)是否能够连接
mysql的用户的认证是通过  主机地址 + 用户名 + 密码
如果主机地址写%,就表示任意IP都可以访问
如果主机地址写localhost,那么说明只能本机并且用localhost/127.0.0.1 才能访问
(2)验证权限
A:全局权限,针对所有库,所有表,所有字段的权限
   如果某个操作有全局权限,那么就不判断 对象级别权限了
B:对象级别权限
   库-->表-->字段   
   每一种操作单独设置权限。
*/
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!