MySQL数据库学习笔记3--关联(联合)查询

八.关联查询(联合查询)

复制代码
关联查询: 查询的数据来自于多张表

   关联查询的语法:
     内连接  [inner] join
     外连接
	左外连接: 显示左表所有的数据
		left join
	右外连接: 显示右表所有的数据
		right join
	全外连接: 显示两表所有的数据
	   union
     自连接: 自己连接自己 将一张表看成两张表
     注意:
        1.如果关联查询的表内有同名字段 需要指明此字段来自于那张表
        2.可以使用 表名.字段名  给表起别名的方式来指定
        3.如果不写关联条件 结果是笛卡尔积 
          笛卡尔积  A(A,B) B(1,2,3) 1A 1B 2A 2B 3A 3B
        4.  sql99 关联和筛选分开  sql92 不分开(不推荐)

8.1 什么是关联查询

关联查询:两个或更多个表一起查询。

前提条件:这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,也可能没有建立外键。

比如:员工表和部门表,这两个表依靠"部门编号"进行关联。

8.1 什么是关联查询

关联查询:两个或更多个表一起查询。

前提条件:这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,也可能没有建立外键。

比如:员工表和部门表,这两个表依靠"部门编号"进行关联。

8.2 关联查询结果分为几种情况

8.3 关联查询的SQL有几种情况

1、内连接:inner join ... on

结果:A表 ∩ B表

2、左连接:A left join B on

(2)A表全部

(3)A表- A∩B

3、右连接:A right join B on

(4)B表全部

(5)B表-A∩B

4、全外连接:full outer join ... on,但是mysql不支持这个关键字,mysql使用union(合并)结果的方式代替

(6)A表∪B表: (2) A表结果 union (4)B表的结果

(7)A∪B - A∩B (3)A表- A∩B结果 union (5)B表-A∩B结果

示例:

对于下面两张表:

A∩B

sql 复制代码
SELECT *
FROM t_stu INNER JOIN t_class
ON class_id = cid;

A

sql 复制代码
SELECT *
FROM t_stu LEFT JOIN t_class
ON class_id = cid;

A-A∩B

sql 复制代码
SELECT *
FROM t_stu a LEFT JOIN t_class b
ON a.class_id = b.cid
WHERE a.`class_id` IS NULL;

B

sql 复制代码
SELECT *
FROM t_stu a RIGHT JOIN t_class b
ON a.class_id = b.cid;

B-A∩B

sql 复制代码
SELECT *
FROM t_stu a RIGHT JOIN t_class b
ON a.class_id = b.cid
WHERE a.`class_id` IS NULL;

A∪B

MySQL中用 结果A UNION 结果B (这里演示为MySQL的)

sql 复制代码
SELECT *
FROM t_stu a LEFT JOIN t_class b
ON a.class_id = b.cid

UNION

SELECT *
FROM t_stu a RIGHT JOIN t_class b
ON a.class_id = b.cid;

其他数据库

sql 复制代码
# 大概,没测试
SELECT *
FROM t_stu a FULL JOIN t_class b`在这里插入代码片`
ON a.class_id = b.cid;

A∪B - A∩B

MySQL中用 结果A-A∩B UNION 结果B-A∩B (这里演示为MySQL的)

sql 复制代码
SELECT *
FROM t_stu a LEFT JOIN t_class b
ON a.class_id = b.cid
WHERE a.`class_id` IS NULL

UNION

SELECT *
FROM t_stu a RIGHT JOIN t_class b
ON a.class_id = b.cid
WHERE a.`class_id` IS NULL;

其他数据库

sql 复制代码
# 大概,没测试
SELECT *
FROM t_stu a FULL JOIN t_class b
ON a.class_id = b.cid
WHERE a.`class_id` IS NULL OR B.'cid' IS NULL;

总结

复制代码
(1)凡是联合查询的两个表,必须有"关联字段",
关联字段是逻辑意义一样,数据类型一样,名字可以一样也可以不一样的两个字段。
比如:t_employee (A表)中did和t_department(B表)中的did。

发现关联字段其实就是"可以"建外键的字段。当然联合查询不要求一定建外键。

(2)联合查询必须写关联条件,关联条件的个数 = n - 1.
n是联合查询的表的数量。
如果2个表一起联合查询,关联条件数量是1,
如果3个表一起联合查询,关联条件数量是2,
如果4个表一起联合查询,关联条件数量是3,
。。。。
否则就会出现笛卡尔积现象,这是应该避免的。

(3)关联条件可以用on子句编写,也可以写到where中。
但是建议用on单独编写,这样呢,可读性更好。

每一个join后面都要加on子句
A inner|left|right join  B on 条件
A inner|left|right join  B on 条件 inner|left|right jon C on 条件

1、内连接

sql 复制代码
#演示内连接,结果是A∩B
/*
观察数据:
t_employee  看成A表
t_department 看成B表
此时t_employee (A表)中有 李红和周洲的did是NULL,没有对应部门,
    t_department(B表)中有 测试部,在员工表中找不到对应记录的。
*/

#查询所有员工的姓名,部门编号,部门名称
#如果员工没有部门的,不要
#如果部门没有员工的,不要
/*
员工的姓名在t_employee (A表)中
部门的编号,在t_employee (A表)和t_department(B表)都有
部门名称在t_department(B表)中
所以需要联合两个表一起查询。
*/
SELECT ename,did,dname
FROM t_employee INNER JOIN t_department;
#错误Column 'did' in field list is ambiguous
#因为did在两个表中都有,名字相同,它不知道取哪个表中字段了
#有同学说,它俩都是部门编号,随便取一个不就可以吗?
#mysql不这么认为,有可能存在两个表都有did,但是did的意义不同的情况。
#为了避免这种情况,需要在编写sql的时候,明确指出是用哪个表的did

SELECT ename,t_department.did,dname
FROM t_employee INNER JOIN t_department;
#语法对,结果不太对
#结果出现"笛卡尔积"现象, A表记录 * B表记录
/*
(1)凡是联合查询的两个表,必须有"关联字段",
关联字段是逻辑意义一样,数据类型一样,名字可以一样也可以不一样的两个字段。
比如:t_employee (A表)中did和t_department(B表)中的did。

发现关联字段其实就是可以建外键的字段。当然联合查询不要求一定建外键。

(2)联合查询必须写关联条件,关联条件的个数 = n - 1.
n是联合查询的表的数量。
如果2个表一起联合查询,关联条件数量是1,
如果3个表一起联合查询,关联条件数量是2,
如果4个表一起联合查询,关联条件数量是3,
。。。。
否则就会出现笛卡尔积现象,这是应该避免的。

(3)关联条件可以用on子句编写,也可以写到where中。
但是建议用on单独编写,这样呢,可读性更好。

每一个join后面都要加on子句
A inner|left|right join  B on 条件
A inner|left|right join  B on 条件 inner|left|right jon C on 条件
*/


SELECT ename,t_department.did,dname
FROM t_employee INNER JOIN t_department 
ON t_employee.did = t_department.did;

SELECT *
FROM t_employee INNER JOIN t_department 
ON t_employee.did = t_department.did;


#查询部门编号为1的女员工的姓名、部门编号、部门名称、薪资等情况
SELECT ename,gender,t_department.did,dname,salary
FROM t_employee INNER JOIN t_department 
ON t_employee.did = t_department.did
WHERE t_department.did = 1 AND gender = '女';

#查询部门编号为1的员工姓名、部门编号、部门名称、薪资、职位编号、职位名称等情况
SELECT ename,gender,t_department.did,dname,salary,job_id,jname
FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did
 INNER JOIN t_job ON t_employee.`job_id` = t_job.`jid`
WHERE t_department.did = 1;

2、左连接

sql 复制代码
#演示左连接
/*
(2)A
(3)A-A∩B
*/
/*
观察数据:
t_employee  看成A表
t_department 看成B表
此时t_employee (A表)中有 李红和周洲的did是NULL,没有对应部门,
    t_department(B表)中有 测试部,在员工表中找不到对应记录的。
*/
#查询所有员工,包括没有指定部门的员工,他们的姓名、薪资、部门编号、部门名称
SELECT ename,salary,t_department.did,dname
FROM t_employee LEFT JOIN t_department
ON t_employee.did = t_department.did;
#查询的是A结果  A left join B

#查询没有部门的员工信息
SELECT ename,salary,t_department.did,dname
FROM t_employee LEFT JOIN t_department
ON t_employee.did = t_department.did
WHERE t_employee.did IS NULL;
#查询的结果是A - A∩B
#此时的where条件,建议写子表的关联字段is null,这样更准确一点。
#如果要建外键,它们肯定有子表和父表的角色,写子表的关联字段is null
#因为父表中这个字段一般是主键,不会为null。

3、右连接

sql 复制代码
/*
右连接
(4)B
(5)B - A∩B
*/
#演示右连接
/*
观察数据:
t_employee  看成A表
t_department 看成B表
此时t_employee (A表)中有 李红和周洲的did是NULL,没有对应部门,
    t_department(B表)中有 测试部,在员工表中找不到对应记录的。
*/
#查询所有部门,包括没有对应员工的部门,他们的姓名、薪资、部门编号、部门名称
SELECT ename,salary,t_department.did,dname
FROM t_employee RIGHT JOIN t_department
ON t_employee.did = t_department.did;
#查询的是B结果  A RIGHT join B

#查询没有员工部门的信息
SELECT ename,salary,t_department.did,dname
FROM t_employee RIGHT JOIN t_department
ON t_employee.did = t_department.did
WHERE t_employee.did IS NULL;
#查询的结果是B - A∩B
#此时的where条件,建议写子表的关联字段is null,这样更准确一点。
#如果要建外键,它们肯定有子表和父表的角色,写子表的关联字段is null
#因为父表中这个字段一般是主键,不会为null。



#查询所有员工,包括没有指定部门的员工,他们的姓名、薪资、部门编号、部门名称
SELECT ename,salary,t_department.did,dname
FROM t_department RIGHT JOIN t_employee
ON t_employee.did = t_department.did;
#查询的是B结果  A RIGHT join B

#查询没有部门的员工信息
SELECT ename,salary,t_department.did,dname
FROM t_department RIGHT JOIN t_employee
ON t_employee.did = t_department.did
WHERE t_employee.did IS NULL;
#查询的结果是B - A∩B  A right join B
#此时的where条件,建议写子表的关联字段is null,这样更准确一点。
#如果要建外键,它们肯定有子表和父表的角色,写子表的关联字段is null
#因为父表中这个字段一般是主键,不会为null。

4、union

sql 复制代码
/*
union实现
(6)A∪B
(7)A∪B - A∩B
    A-A∩B  ∪  B-A∩B
*/
#演示用union合并两个查询结果实现A∪B 和A∪B - A∩B
/*
union合并时要注意:
(1)两个表要查询的结果字段是一样的
(2)UNION ALL表示直接合并结果,如果有重复的记录一并显示
   ALL去掉表示合并结果时,如果有重复记录,去掉。
(3)要实现A∪B的结果,那么必须是合并 查询是A表结果和查询是B表结果的select语句。
同样要实现A∪B - A∩B的结果,那么必须是合并查询是A-A∩B结果和查询是B-A∩B的select语句。
*/

#查询所有员工和所有部门,包括没有指定部门的员工和没有分配员工的部门。
SELECT *
FROM t_employee LEFT JOIN t_department
ON t_employee.did = t_department.did

UNION 

SELECT *
FROM t_employee RIGHT JOIN t_department
ON t_employee.did = t_department.did;


#以下union会报错
SELECT * FROM t_employee
UNION
SELECT * FROM t_department;
/*
错误代码: 1222
The used SELECT statements have a different number of columns
两个Select语句的列数是不同的。

column:列,表中的字段。
columns:很多的字段,即字段列表
select 字段列表 from 表名称;
*/


#联合 查询结果是A表的select 和查询结果是A∩B的select语句,是得不到A∪B
SELECT *
FROM t_employee LEFT JOIN t_department
ON t_employee.did = t_department.did

UNION 

SELECT *
FROM t_employee INNER JOIN t_department
ON t_employee.did = t_department.did;

#查询那些没有分配部门的员工和没有指定员工的部门,即A表和B表在对方那里找不到对应记录的数据。
SELECT *
FROM t_employee LEFT JOIN t_department
ON t_employee.did = t_department.did
WHERE t_employee.did IS NULL

UNION 

SELECT *
FROM t_employee RIGHT JOIN t_department
ON t_employee.did = t_department.did
WHERE t_employee.did IS NULL;

8.4 联合查询字段列表问题

sql 复制代码
#查询字段的问题
#查询每一个员工及其所在部门的信息
#要求:显示员工的编号,姓名,部门编号,部门名称
SELECT eid,ename,did,dname
FROM t_employee INNER JOIN t_department
ON t_employee.did = t_department.did;
/*
错误代码: 1052
Column 'did' in field list is ambiguous(模糊不清的;引起歧义的)
*/

SELECT eid,ename,t_employee.did,dname
FROM t_employee INNER JOIN t_department
ON t_employee.did = t_department.did;


#查询每一个员工及其所在部门的信息
#要求,显示员工的编号,姓名,部门表的所有字段
SELECT eid,ename,t_department.*
FROM t_employee INNER JOIN t_department
ON t_employee.did = t_department.did;

8.5 自连接

sql 复制代码
#演示特殊的联合查询/关联查询/多表查询:自连接
#物理上,是一张表
#逻辑上,是两张表
/*
分析表结构:t_employee表
mid:是表示存储员工的领导编号。即该员工归谁管。领导编号其实就是"领导"作为员工身份的员工编号
   例如:eid为3的员工邓超远,他的mid是7,表示他的领导是员工编号为7的员工。
   eid为7的员工是贾宝玉,他的eid是7,贾宝玉作为员工来说,他的编号是7,作为领导来说,他的编号也是7。

mid的取值范围受到eid字段的限制。mid的值选择必须是eid现有值范围。

可以理解为mid和eid是关联字段,如果要建外键,可以在mid字段上建外键。
foreign key(mid) references t_employee(eid)   

此时t_employee既是子表也是父表。
员工表t_employee建立了外键:
CONSTRAINT `t_employee_ibfk_3` FOREIGN KEY (`mid`) REFERENCES `t_employee` (`eid`) ON DELETE SET NULL ON UPDATE CASCADE
*/
#查询每一个员工自己的编号、名字、薪资和他的领导的编号、姓名、薪资。
SELECT emp.eid,emp.ename,emp.salary,  mgr.eid,mgr.ename,mgr.salary
FROM t_employee AS emp INNER JOIN t_employee AS mgr
ON emp.mid = mgr.eid; 
#把t_employee当成两张表,通过取别名的方式
#t_employee AS emp 把员工表 当成员工表
# t_employee AS mgr 把员工表  当成存储领导信息的领导表
#emp.mid = mgr.eid; 员工表的领导编号就是领导表的员工编号
相关推荐
辣知1 小时前
辣知·化智49 黄帝时期至夏朝的一千年
学习
陈皮波比茶1 小时前
计算机二级MySQL笔记
java·数据库
行业研究员1 小时前
腾讯云数据库 PostgreSQL 让相关子查询跑上多核
数据库·postgresql·腾讯云
zzzll11111 小时前
LangChain 1.3 新特性详解与实战指南
java·数据库·langchain
石小千1 小时前
MySQL 8.4设置密码策略
数据库·mysql
神明不懂浪漫2 小时前
【第四章】索引——B+树、回表,加快数据库的查找能力的利器
开发语言·数据结构·数据库·经验分享·笔记·b树
是隼人2 小时前
buuctf-pwn PWN2(整数溢出)题解(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
hui-梦苑2 小时前
[Math]复合函数极限存在定理:单调连续函数反函数连续性定理推论
学习·数学·定理·函数极限·海涅定理