一、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:对象级别权限
库-->表-->字段
每一种操作单独设置权限。
*/
来源:oschina
链接:https://my.oschina.net/u/3730932/blog/3221731