进阶 六:连接查询
含义:多表查询,当查询的字段来自与多个表
笛卡尔乘积现象: 表1 有M行,表2有N行,结果 = m*n
-发生原因:没有有效的连接条件
-如何避免,添加有效的连接条件
连接的分类:
按年代分类:
sql 92标准、99标准【推荐】:支持内连接+外连接(左外和右外) +交叉连接
按功能分类:
内连接:
1)等值连接
2)非等值
3)自连接
外连接:
1)左外连接
2)右外连接
3)全外连接
交叉连接:
一、sql 92
1、92-等值连接
select name,boyName
from boys,beayty
where boys.id = beauty.boyfriend_id; 匹配、筛选
结论:
1、多表等值连接的查询结果是多表的交集
*/
SELECT NAME,boyName
FROM boys AS b1,beauty AS b2 # 可以为表起别名,提高语句简洁度,区分重名的字段
#注意:如果为表取了别名,则查询的字段不能使用原来的表名限定,只能使用别名
WHERE b1.id = b2.boyfriend_id;
#查询每个城市的部门个数 ,
#添加分组、筛选
SELECT COUNT(*),`department_id`,`city`
FROM `departments` d,`locations` l
WHERE d.`location_id` = l.`location_id`
GROUP BY `city`;
#2、92-非等值连接
SELECT salary,`grade_level`
fro
m `job_grades` j,`employees` e
WHERE salary BETWEEN `lowest_sal` AND `highest_sal`; #表的等值连接是前小后大,但在用于筛选时是前大后小,一个表对应另一个表的区间
SELECT `salary`,COUNT(`salary`)
FROM `employees`
GROUP BY `salary`;
#3、92-自连接
#自己连接自己 一个表当多个表使用
#二、sql 99 语法
内连接(*)inner join
外连接
左外(*):left outer join
右外(*):right 【outer】join
全外:
交叉连接:cross
语法:
select 查询列表
from 表1 别名 【连接类型】
join 表2 别名
on 连接条件
where 筛选条件
group by 分组条件
having 筛选条件
order by 排序连接
1)内连接
1)等值连接:inner join……on
查询员工名、部门名
SELECT `department_name`,`first_name`
FROM `employees` e INNER
JOIN `departments` d
ON e.`department_id` = d.`department_id`;
查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序
特点:
①inner 可以省略
②筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读
③inner join 连接和SQL 92语法中的等值连接效果一样的,都是查询多表的
2)非等值连接
SELECT salary,`grade_level`
from `job_grades` j
join `employees` e
on salary BETWEEN `lowest_sal` AND `highest_sal`; #表的等值连接是前小后
3)自连接
SELECT e.`last_name`, m.`last_name`
from `employees` e
join `employees` m
on e.`manager_id` = m.`employee_id`; #表的等值连接是前小后
2)外连接
应用场景:用于查询一个表中有,另外一个表中没有的
特点:
1、外连接的查询结果为主表的所有记录
如果从表中有和它匹配的,则显示null
外连接查询结果 = 内连接查询结果+主表中有 而从表没有的记录
2、左外连接:left左边的是主表
右外连接:right join 右边的是主表
3、左外和右外交换2个表的顺序,可以实现同样的效果
SELECT d.s`department_name`,COUNT(*) 员工个数
FROM `departments` d
INNER JOIN `employees` e
ON d.`department_id`= e.`department_id`
GROUP BY d.`department_name` DESC
HAVING COUNT(*) > 3;
SELECT `job_id`,COUNT(*) 员工个数 #内部等值连接
FROM `departments` d
INNER JOIN `employees` e
ON d.`department_id`= e.`department_id`
GROUP BY e.`job_id` DESC;
SELECT be.`name`,bo.*
FROM `beauty` be
LEFT OUTER JOIN `boys` bo #左外连接
ON be.`boyfriend_id` = bo.`id`;
#七、子查询
#一、where或having后面
/
出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询
分类:
(1)按子查询出现的位置:
select后面:
(支持标量子查询)
from后面:
(支持表子查询)
where或者having后面:***
(支持标量子查询,单行)√
(列子查询,多行) √
(行子查询)
exist后面(相关子查询)
表子查询
(2)按结果集的行列数不同
标量子查询(结果集只有一行一列)
列子查询(结果集只有一列多行)
行子查询(结果集有一行多列)
表子查询(结果集,一般为多行多列)
*1、子查询放在小括号内
2、子查询一般放在条件的右侧
3、标量子查询一般搭配单行操作符使用
4、子查询执行结果先与使用主查询
< > =
*/
#返回`job_id`与141号员工相同,`salary`比143号员工多的员工的姓名、`job_id`、`salary`
#(1)标量子查询---141号员工的`job_id`、`salary` ---标量子查询
SELECT `job_id`,`salary`
FROM`employees`
WHERE `employee_id` = 141;
#(2)返回`job_id`与141号员工相同,`salary`比143号员工多的员工的姓名、`job_id`、`salary`
SELECT `job_id`,`salary`,`last_name`
FROM `employees`
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 和子查询返回的所有值比较
*/
#返回`location_id`是1400或1700的部门中所有员工的姓名
SELECT em.`first_name`,`last_name`,de.`location_id`
FROM `employees` em
INNER JOIN `departments` de
ON em.`department_id` = de.`department_id`
WHERE de.`location_id` = 1400 OR 1700;
SELECT `first_name`,`last_name`
FROM `employees`
WHERE `department_id` IN (
SELECT `department_id`
FROM `departments`
WHERE `location_id` = 1400 OR 1700 #单列多行
);
#二、select 后面---仅仅支持标量子查询
#获得每个部门的员工个数
#获取所有的部门
SELECT DISTINCT `department_id`
FROM `employees`;
#获取每个部门的员工个数
SELECT COUNT(`employee_id`),`department_id`
FROM `employees`
GROUP BY `department_id`;
#三、from后面
#(1)将查询结果作为一张表
#查询每个部门的平均工资的工资等级
#1、各个部门的平均工资
SELECT 表1.*,jg.`grade_level`
FROM (
SELECT AVG(salary) avg_salary,`department_id` #子查询,获得各个部门的平均工资
FROM `employees`
GROUP BY `department_id`
) 表1
INNER JOIN `job_grades` jg
ON avg_salary BETWEEN `lowest_sal` AND `highest_sal`
#四、exists 后面(相关子查询)
#exist(完整的查询语句),有查询结果返回1,没有返回0
#查询有员工的部门名
SELECT DISTINCT `department_name`
FROM `departments` de
LEFT OUTER JOIN `employees` em
ON de.`department_id` = em.`department_id`
WHERE em.`employee_id` IS NOT NULL;
SELECT `department_name`
FROM `departments` de
WHERE EXISTS(
SELECT *
FROM employees em
WHERE em.`department_id` = de.`department_id`
);
#exist的解析:
(1)查询顺序,先执行from,然后where,进入exist,通过判断exist为真或者为假决定select是否执行,判断过程会传入外部查询的每一行分别执行一次子查询
#内联结
SELECT `openbid_state`,`profession`
FROM`open_bid_section` INNER JOIN `open_bid`
ON `open_bid`.`bid_section_id` = `open_bid_section`.`bid_section_id`;
#外联结,需要指明方向,right/left/full outer join
SELECT `openbid_state`,`profession`
FROM`open_bid_section` LEFT OUTER JOIN `open_bid`
ON `open_bid`.`bid_section_id` = `open_bid_section`.`bid_section_id`#;--不能检索右边的null
UNION
SELECT `openbid_state`,`profession``Timestamp`
FROM`open_bid_section` RIGHT OUTER JOIN `open_bid`
ON `open_bid`.`bid_section_id` = `open_bid_section`.`bid_section_id`;
SELECT `openbid_state`,`profession`
FROM`open_bid_section` FULL OUTER JOIN `open_bid`
ON `open_bid`.`bid_section_id` = `open_bid_section`.`bid_section_id`; --MYSQL不支持full
#查询8:分页查询 **
/*
应用场景:当要显示的数据一页显示不全,需要分页提交sql请求
语法:
select 查询列表
from 表
【join type 表2
on 链接条件
where 筛选条件
group by 分组字段
having 分组后的筛选
order by 排序的字段】
limit 起始索引offset,size; -----起始索引从0开始可以省略
查询第11-25条
limit 10,15
offset 要显示条目的起始索引(这里索引从0开始)
size 要显示的条目个数
特点:
①limit 放在查询语句的最后
②公式
select
from
limit (page -1)*size,size
*/
#进阶9 联合查询
/*
union 联合 合并:将多条查询语句的结果合并成为一个结果
语法:
查询语句1
union
查询语句2
应用场景:
要查询的结果来源于多个表,且多个表没有直接的链接关系,但查询的信息一致
特点:
(1)查询的字段数量相同
(2)要求查询的字段的顺序和类型一致
(3)使用union关键字,结果会自动去重
使用union all 就不会去重
*/