# 进阶5:分组查询/*
引入:求出各部门的平均工资
语法:
select column,group_function(column)
from 表名
[where 条件]
[group by 表达式]
[having 条件]
[order by column]
*/# 案例1:查询每个工种的最高工资SELECTMAX(salary),job_id
FROM
employees
GROUPBY
job_id;# 案例2:查询每个位置上的部门个数SELECTCOUNT(*),location_id
FROM
departments
GROUPBY location_id;# 添加筛选条件# 案例3:查询邮箱中包含a字符的,每个部门的平均工资SELECTAVG(salary),department_id
FROM
employees
WHERE
email LIKE'%a%'GROUPBY
department_id
# 案例4. 查询有奖金的每个领导手下的员工的最高工资SELECTMAX(salary),manager_id
FROM
employees
WHERE
commission_pct ISNOTNULLGROUPBY
manager_id;# 复杂的筛选条件# 案例5:查询哪个部门的员工个数>2/*
having 添加分组后的筛选
*/SELECT
department_id 部门,COUNT(*)FROM
employees
GROUPBY
department_id
HAVINGCOUNT(*)>2;# 案例6:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资SELECTMAX(salary),job_id
FROM
employees
WHERE
commission_pct ISNOTNULLGROUPBY
job_id
HAVINGMAX(salary)>12000;# 案例7:查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪一个,以及其最低工资SELECTMIN(salary),manager_id
FROM employees
WHERE manager_id>102GROUPBY manager_id
HAVINGMIN(salary)>5000;# 分组查询按表达式或函数分组# 案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些SELECTCOUNT(*)FROM
employees
GROUPBY
LENGTH(CONCAT(last_name,first_name))HAVINGCOUNT(*)>5;## 按多个字段分组# 案例:查询每个部门每个工种的员工的平均工资SELECTAVG(salary),`department_id`,job_id
FROM employees
GROUPBY`department_id`,job_id;# 添加排序## 案例:查询每个部门每个工种的员工的平均工资,并且按平局工资的高低显示SELECTAVG(salary),department_id,job_id
FROM employees
GROUPBY department_id,job_id
ORDERBYAVG(salary)DESC;
1.6 连接查询
USE myemployees;SELECTDATABASE();## 进阶6: 连接查询(多表查询)/*
用处:当查询来自多个表的时候,就会用到连接查询
笛卡尔乘积现象;表1有m行,表2有n行,结果=m*n行
发生原因:没有有效的连接条件
如何避免:添加有效的连接条件
连接查询分类
按年代分类
sql 192标准:仅仅支持内连接
sql 199标准【推荐】:支持内连接、外连接(左外和右外)、交叉连接
按功能分类
内连接
等值连接
非等值连接
自连接
外连接
左外连接
右外连接
全外连接
交叉连接
*/# 出现笛卡尔乘积SELECT`name`,boyName
FROM beauty,boys;# 添加有效的连接条件/*需要对连接条件中的id值进行表名的限定*/SELECT`name`,boyName
FROM beauty,boys
WHERE beauty.`boyfriend_id`= boys.`id`;# sql92标准# 等值连接/*
①.多表等值连接的结果为多表的交集部分
②.n表连接,至少需要n-1个连接条件
③.多表的顺序没有要求
④.一般需要为表取别名
⑤.可以搭配前面介绍的所有子句使用,比如牌组、分组、筛选
*/# 案例1:查询女生名和对应的男神名SELECT`name`,boyName
FROM beauty,boys
WHERE beauty.boyfriend_id=boys.`id`# 案例2:查询员工名和对应的部门名USE myemployees;SELECT last_name,department_name
FROM departments,employees
WHERE employees.`department_id`= departments.`department_id`;#为表取别名/*如果为表取了别名,则查询的字段就不能使用原来的表名进行限定*/# 案例3:查询员工名、工种名、工种号SELECT e.last_name,e.job_id,j.job_title
FROM employees e,jobs j
WHERE e.`job_id`= j.`job_id`;# 添加筛选条件# 案例4:查询有奖金的员工名、部门名SELECT last_name,department_name,commission_pct
FROM employees,departments
WHERE employees.`department_id`=departments.`department_id`AND employees.`commission_pct`ISNOTNULL;# 案例5:查询城市名中第二个字符为o的部门名和城市名SELECT departments.`department_name`,locations.`city`FROM departments,locations
WHERE departments.`location_id`=locations.`location_id`AND locations.`city`LIKE'_o%';# 添加分组#案例6: 查询每个城市的部门个数SELECTCOUNT(*) 部门个数,city
FROM departments d,locations l
WHERE d.`location_id`= l.`location_id`GROUPBY l.`city`;# 添加排序# 案例7:查询每个工种的工种名和员工的个数,并且按员工个数降序SELECT job_title,COUNT(*) 员工个数
FROM employees e, jobs j
WHERE j.`job_id`=e.`job_id`GROUPBY j.`job_title`ORDERBYCOUNT(*)DESC;# 实现三表连接# 案例8:查询员工名、部门名和所在城市SELECT last_name,department_name,city
FROM departments d,employees e,locations l
WHERE e.`department_id`=d.`department_id`AND d.`location_id`= l.`location_id`;/*
不等值查询
*/CREATETABLE job_grades
(grade_level VARCHAR(3),
lowest_sal INT,
highest_sal INT);INSERTINTO job_grades
VALUES('A',1000,2999);INSERTINTO job_grades
VALUES('B',3000,5999);INSERTINTO job_grades
VALUES('C',6000,9999);INSERTINTO job_grades
VALUES('D',10000,14999);INSERTINTO job_grades
VALUES('E',15000,24999);INSERTINTO job_grades
VALUES('F',25000,40000);## 案例1:查询员工工资和工资级别SELECT salary,grade_level
FROM employees e,job_grades g
WHERE e.`salary`BETWEEN g.`lowest_sal`AND g.`highest_sal`AND g.`grade_level`='A';/*
自连接
*/# 案例1:查询员工名和上级的名称SELECT e1.last_name 员工名称,e2.`last_name` 上级名称
FROM employees e1, employees e2
WHERE e1.`manager_id`= e2.`employee_id`;/*sql 199语法
语法:
select 查询列表
from 表1 别名 【连接类型】
join 表2 别名
on 连接条件
where 筛选条件
[group by ]
[having]
[order by]
分类
内连接:(⭐)inner
外连接
左外:(⭐)left [outer]
右外:(⭐)right [outer]
全外:full [outer]
交叉连接:cross
*//*
内连接
select 查询列表
from 表1 别名
inner join 表2 别名
on 连接条件;
*/# 等值连接/*
特点
1)添加排序、分组、筛选
2)inner可以省略
3)筛选条件放在where后面,连接条件放在on后面,提高 分离性
*/# 案例1: 查询员工名、部门名SELECT last_name,department_name
FROM employees e
INNERJOIN departments d
ON d.`department_id`= e.`department_id`;# 案例2:查询名字中包含e的员工名和工种名SELECT last_name,job_title
FROM employees e
INNERJOIN jobs j
ON e.`job_id`= j.`job_id`WHERE last_name LIKE'%e%';# 案例3:查询部门个数>3的城市名和部门个数SELECT city,COUNT(*)FROM departments d
INNERJOIN locations l
ON l.`location_id`= d.`location_id`GROUPBY l.`city`HAVINGCOUNT(*)>3;# 案例4:查询部门的部门员工个数>3的部门名和员工个数,并按个数降序SELECT department_name,COUNT(*)FROM departments d
INNERJOIN employees e
ON e.`department_id`= d.`department_id`GROUPBY d.`department_name`HAVINGCOUNT(*)>3ORDERBYCOUNT(*)DESC;# 案例5:查询员工名、部门名、工种名、并按照部门名降序SELECT last_name,department_name,job_title
FROM employees e
INNERJOIN departments d
ON e.`department_id`= d.`department_id`INNERJOIN jobs j
ON e.`job_id`= e.`job_id`ORDERBY d.`department_name`DESC;# sql 199 非等值连接# 案例:查询员工的工资级别SELECT last_name,salary,grade_level
FROM employees e
JOIN job_grades j
ON e.`salary`BETWEEN j.`lowest_sal`AND j.`highest_sal`;# 自连接# 案例:查询员工的名字、上级的名字SELECT e.`last_name` 员工的名称,m.`last_name` 管理者名称
FROM employees e
JOIN employees m
ON e.`manager_id`= m.`employee_id`、
## ⭐外连接/*特点:
1.外连接的查询结果为主表中多有的记录
如果从表中有和它匹配的,则显示匹配的值
如果从表中没有和它匹配的,则显示null
外连接查询结果=内连接结果+主表中有而从表中没有的记录
2. 左外连接,left join 左边的是主表
右外连接,right join右边的是主表
3. 左外和右外交换两个表的顺序,可以实现同样的效果
*/# 引入:查询男朋友不在男生表的女生名SELECT`name`,boyName
FROM beauty g
LEFTOUTERJOIN boys b
ON g.`boyfriend_id`= b.`id`WHERE boyName ISNULL;# 查询哪个部门没有员工USE myemployees;SELECT department_name,last_name
FROM employees e
RIGHTOUTERJOIN departments d
ON e.`department_id`= d.`department_id`WHERE e.`employee_id`ISNULL;# 全外连接:mysql不支持# 以下仅仅作展示USE girls;SELECT b.*,bo.*FROM beauty b
FULLOUTERJOIN boys bo
ON b.boyfriend_id = bo.id;# 交叉连接(笛卡尔乘积)SELECT b.*,bo.*FROM beauty b
CROSSJOIN boys bo;
1.7 子查询
/*
进阶7:子查询
含义:出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句称为主查询或外查询
示例:
select firt_name from employees where
department_id in (
select department_id from departments
where location_id = 1700
)
分类:
按子查询出现的位置
1. select后面(仅仅支持标量子查询)
2. from后面(支持表子查询)
3. where或having后面※(支持标量子查询※,列子查询※,行子查询)
4. exists后面(相关子查询,表子查询)
按结果集的行列数不同:
1. 标量子查询(结果集只有一行一列)
2. 列子查询(结果集只有一列多行)
3. 行子查询(结果集有一行多列)
4. 表子查询(结果集一般为多行多列)
*/# 一、where或having后面/*
1. 标量子查询(单行子查询)
2. 列子查询(多行子查询)
3. 行子查询(多列多行)
特点:
1). 子查询放在小括号内
2). 子查询一般放在条件的右侧
3). 标量子查询,一般搭配这单行操作符使用(> < >= <= <>)
列子查询,一般搭配这多行操作符使用
IN、ANY/SOME、ALL
*/# 1. 标量子查询# 案例1:谁的工资比Abel高SELECT last_name,salary
FROM employees
WHERE salary>(SELECT salary FROM employees WHERE last_name='Abel');# 案例2:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资SELECT last_name,job_id,salary
FROM employees e
WHERE job_id =(SELECT job_id FROM employees WHERE employee_id ='141')AND salary >(SELECT salary FROM employees WHERE employee_id ='143')# 2.列子查询(多行子查询)/*
多行操作符
in / not in 等于列表中的任意一个
any / some 和子查询返回的某一个值比较
all 和子查询返回的所有值比较
*/# 案例1 :返回location_id是1400或1700的部门中的所有员工姓名SELECT*FROM departments;SELECT last_name
FROM employees
WHERE department_id IN(SELECT department_id FROM departments WHERE location_id IN(1400,1700))# 案例2:返回其它部门中比job_id为‘IT_PROG’部门任一工资低的员工的:工号,姓名,job_id以工资SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary <ANY((SELECT salary FROM employees WHERE job_id='IT_PROG'))AND job_id <>'IT_PROG';# 行子查询(结果集一行多列)# 案例1:查询员工编号最小并且工资最高的员工信息SELECT*FROM employees
WHERE(employee_id,salary)=(SELECTMIN(employee_id),MAX(salary)FROM employees
)# select后面的子查询 # 案例1:查询每个部门的员工个数SELECT d.*,(SELECTCOUNT(*)FROM employees e
WHERE e.`department_id`= d.department_id
) 员工个数
FROM departments d
# 案例2 :查询员工号=102的部门名SELECT(SELECT department_name
FROM departments d
INNERJOIN employees e
ON e.department_id = d.department_id
WHERE employee_id ='102');# 三、from 后面的子查询使用# 查询每个部门的平均工资的工资等级SELECT grade_level,s.avg
FROM(SELECTAVG(salary)`avg`FROM employees
GROUPBY department_id
) s
INNERJOIN job_grades g
ON s.avg BETWEEN g.`lowest_sal`AND g.`highest_sal`;# 四、exists后面(相关子查询)/*
语法:
exists(完整的查询语句)
结果
1或0
1 :存在
0 :不存在
*/SELECTEXISTS(SELECT employee_id FROM employees WHERE salary =30000);# 存在结果,1# 案例1:查询有员工的部门名SELECT department_name
FROM departments d
WHEREEXISTS(SELECT*FROM employees e
WHERE d.`department_id`= e.`department_id`);# 查询没有女朋友的男生信息SELECT bo.*FROM boys bo
WHERENOTEXISTS(SELECT boyfriend_id
FROM beauty b
WHERE bo.`id`= b.`boyfriend_id`)
# 进阶9 :联合查询/*
union:联合 合并:将多条查询语句的结果合并成一个结果
语法:
查询语句1
union
查询语句2
union
...
特点:
要求多条查询语句的列数是一致的
要求多条查询语句的查询的每一列的类型和顺序最好一致
union关键字默认去重,如果使用union all 可以包含重复项
*/# 引入案例:查询部门编号》90或者邮箱包含a的员工信息\# 常规操作SELECT*FROM employees WHERE email LIKE'%a%'OR department_id >90;# 使用unionSELECT*FROM employees WHERE email LIKE'%a%'UNIONSELECT*FROM employees WHERE department_id >90;
二、 DML(Data Manipulation Language)语言的学习
2.1 插入语句
# DML语言/*
数据操作语言
插入:insert
修改:update
删除:delete
*/# 插入语句/*
语法:
方式一:
insert into 表名(列名,...) values(值1,...)
方式二:
语法:
inser into 表名
set 列名=值,列名=值,...
要求:
1. 插入的值的类型要与列的类型一致或兼容
*/USE girls;INSERTINTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)VALUES(13,'唐艺昕','女','1990-4-23','1156465454',NULL,2)SELECT*FROM beauty;# 为空的内容可以不写,即列名和值都不写,要么都写,值为空null# 列的顺序可以颠倒# 可以省略列名,默认所有列,而且列的顺序和表中列的顺序一致INSERTINTO beauty
VALUES(18,'张飞','男',NULL,'1922626',NULL,NULL)# 方式二插入INSERTINTO beauty
SET id=19,NAME='刘涛',sex='女',phone='999';/*
两种方式区别:
1. 方式一支持插入多行,方式二不支持
insert into 表名(列名,...) values(值1,...),(值1,...)
2. 方式一支持子查询,方式二不支持
*/# insert into 使用子查询INSERTINTO beauty(id,NAME,sex,borndate,phone)SELECT26,'宋茜','女','1994-08-07','11878327';
2.2 修改语句
# # 二、修改语句/*
1. 修改单表的记录※
语法:
update 表名 set 列=新值,列=新值,... where 筛选条件;
2. 修改多表的记录【补充】
语法:
sql 192语法:
update 表1 别名,表2 别名
set 列=值,...
where 连接条件
and 筛选条件
sql 199语法:
update 表1 别名
inner|left|right join 表2 别名
on 连接条件
set 列=值,...
where 筛选条件;
*/# (一)、修改单表的记录# 案例1:修改beauty中姓唐的女神的电话为16161555UPDATE beauty SET phone='16161555'WHERE`name`LIKE'唐%';SELECT*FROM beauty;# (二)、修改多表的记录# 案例1:修改张无忌女朋友的手机号为114UPDATE beauty b
INNERJOIN boys bo
ON bo.`id`= b.`boyfriend_id`SET b.`phone`='116'WHERE bo.`boyName`='张无忌'# 案例2:修改没有男朋友的女神的男朋友编号为2UPDATE beauty b
LEFTOUTERJOIN boys bo
ON bo.`id`= b.`boyfriend_id`SET b.`boyfriend_id`=2WHERE bo.`id`ISNULL
2.3 删除语句
#三、删除语句/*
方式一:delete
语法:
1.单表的删除※
delete from 表名 where 筛选条件
2.多表的删除
sql 192语法:
delete 表1的别名,表2的别名
from 表1 别名,表2 别名
where 连接条件
and 筛选条件
sql 199语法:
delete 表1的别名,表2的别名
from 表1 别名
inner|left|right join 表2 别名
on 连接条件
where 筛选条件
【注意】: 这里表1的别名和表2的别名代表你要删除哪个表中的数据,如果是只删除
表1中的数据,delete后面只写表1的别名,表1的别名和表2的别名同时写代表两个一起级联删除。
方式二:truncate
语法:
truncate table 表名
*/# 方式一 delete# 1.单表的删除# 案例:删除手机号以9结尾的女神信息DELETEFROM beauty WHERE phone LIKE'%9';# 2. 多表的删除# 案例:删除张无忌的女朋友的信息DELETE b,FROM beauty b
INNERJOIN boys bo
ON b.`boyfriend_id`= bo.`id`WHERE bo.`boyName`='张无忌';# 2. 多表的删除# 案例:删除张无忌及其女朋友的信息DELETE b,bo
FROM beauty b
INNERJOIN boys bo
ON b.`boyfriend_id`= bo.`id`WHERE bo.`boyName`='张无忌';# 删除方式二 truncate# truncate 语句不能加where,会直接删除表TRUNCATETABLE boys;DELETEFROM boys;/*
delete 和 truncate区别
1. truncate 效率更高
2. delete能加where条件,truncate 不能
3. 如果表中有自增长列,delete删除后,再插入数据,自增长的值从断点开始,而truncate自增长列的值从1开始。
4. truncate 删除没有返回值,delete删除有返回值
5. truncate删除不能回滚,delete删除可以回滚
*/