MySQL学习笔记5 多表操作

一、多表关系

多表关系

1.一对一关系

一对一关系很少见,遇到一对一关系最好是合并表

在任意表中添加唯一外键,指向另一张表的主键

2.一对多/多对一关系

原则 在多的一方建立外键,指向另一个的主键

3.多对多关系

多对多关系的实现需要借助中间表,中间表包含两个字段

将多对多关系拆成一对多关系

中间表至少有两个外键,这两个外键分别指向原来两张表的主键

外键约束

1.简介

  • 外键约束常与主键约束一起使用
  • 对于两个关联关系的表而言,相关联字段中主键所在表为主表,外键为子表
  • 外键用来建立主从表的关联关系,建立链接,约束两个表中数据的一致性和完整性

2.规则

  • 主表必须存在
  • 主表必须有主键
  • 主键不能包含空值,但允许在外键中出现空值
  • 主表表名后指定列名(组合).必须为主键的主表/候选键
  • 外键中列的数目必须和主键中列的数目相同
  • 外键中列的数据类型必须和主表中对应列的数据类型相同

二、多表操作

1.设置外键约束

-- 例1.创建表时设置外键约束
-- 创建部门表
create table if not exists
dept(
    deptno varchar(20) primary key , -- 部门号
    name varchar(20) -- 部门名字
);



-- 创建员工表
create table if not exists emp(
    eid varchar(20) primary key  key , -- 员工编号
    ename varchar(20), -- 员工名字
    age int, -- 员工年龄
    dept_id varchar(20), -- 员工部门
    constraint enp_fk foreign key (dept_id) references dept (deptno) -- 外键约束
);

-- 例2.创建表后设置外键约束
create table if not exists dept2(
    deptno varchar(20) primary key , -- 部门号
    name varchar(20) -- 部门名字
);

-- 创建员工表
create table if not exists emp2(
    eid varchar(20) primary key  key , -- 员工编号
    ename varchar(20), -- 员工名字
    age int, -- 员工年龄
    dept_id varchar(20) -- 员工部门
);

-- 创建外键约束
alter table emp2
add constraint dept_id_fk
foreign key (dept_id)
references dept2(deptno);

2.数据添加

/*
1.必须先给主表添加数据
2.给从表添加数据时,外键列的值必须依赖主表的主键列
*/
-- 给主表添加数据
insert into dept values('1001','研发部');
insert into dept values('1002','销售部');
insert into dept values('1003','财务部');
insert into dept values('1004','人事部');

-- 添加从表数据
insert into emp values('1','张三丰',20,'1001');
insert into emp values('2','马保国',21,'1001');
insert into emp values('3','蔡徐坤',26,'1001');
insert into emp values('4','李毅',44,'1002');
insert into emp values('5','田三川',20,'1002');
insert into emp values('6','张志硕',19,'1004');

3.数据删除

/*注意
  1.主表数据被从表依赖时,不能删除
  2.从表的数据可以随便删除
*/

delete
from dept
where deptno = '1004';
-- [23000][1451] Cannot delete or update a parent row: a foreign key constraint fails (`mydb3`.`emp`, CONSTRAINT `enp_fk` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`deptno`))

delete
from dept
where deptno = '1003'; -- 删除成功

delete
from emp
where eid = '6'; -- 删除成功

4.删除外键约束

/*用于删除外键约束
  alter table <表名> drop foreign key <外键名>;
*/

-- 实现
alter table emp drop foreign key dept_id_fk;

5.多对多关系

/*
多对多关系需要建立中间表
*必须先建立两侧主表
*/
-- 操作
-- |学生表|中间表|课程表|
-- 1.创建学生表
create table if not exists student(
    sid int primary key auto_increment,
    name varchar(20),
    age int,
    gender varchar(20)
);

-- 2.创建课程表course(右侧主表)
create table course(
    cid int primary key auto_increment,
    cidname varchar(20)
);

-- 3.创建中间表student_course/score(从表)
create table score(
    sid int,
    cid int,
    score double,
    constraint enp_fks foreign key (sid) references student(sid),
    constraint enp_fkc foreign key (cid) references course(cid)
);

drop table score;

三、多表联合查询

用于同时查询多个表

  • 交叉连接查询

  • 内连接查询

  • 外连接查询

  • 子查询

  • 表自关联

交叉连接查询

  • 交叉连接查询返回被连接的两个表所有数据行的笛卡尔积

  • A表m行 B表n行 返回m*n条查询 根据需要自行筛选

格式

select * from 表1,表2,表3…

select *
from dept3,emp3;
# 可用 where deptno = dept_id #筛选出部门匹配的数据

内连接查询

内连接查询求多张表的交集

隐式内连接查询

select * from A,B where 条件;

显示内连接查询

select * from A inner join B on 条件;

-- 例,查询每个部门的所属员工
-- 隐式
select *
from dept3,emp3
where dept3.deptno = emp3.dept_id;

-- 显式
select *
from dept3
inner join emp3
on dept3.deptno= emp3.dept_id;

-- 查询每个部门的所属员工
-- 隐式
select *
from dept3 a,emp3 b
where b.dept_id=a.deptno; #别名用法 也可不用
-- 显式 将','替换为 inner join (inner可省略)
select *
from dept3 a inner join emp3 b
where b.dept_id=a.deptno;
-- 查询研发部以及销售部的所属员工
select *
from dept3 a inner join emp3 b
on a.deptno = b.dept_id;
-- 查询每个部门的员工数,并升序排序
select a.name,a.deptno,count(*)
from dept3 a join emp3 b
on a.deptno = b.dept_id
group by a.deptno;
-- 查询人数大于等于三的部门,并按照人数降序排序
select
       a.deptno,
       a.name,
       count(*) as total_cnt
from dept3 a join emp3 b on a.deptno = b.dept_id
group by  a.deptno,a.name
having total_cnt >= 3;

外连接查询

外连接查询分为左外,右外,满外查询

分别输出左,右,全的内容

两表相交的部分输出,不相交的部分输出NULL

– MySQL对满外查询的支持不好,故常使用Union关键词

左外连接

select * from A left outer join B on 条件

右外连接

select * from A right outer join B on 条件

满外连接

select * from A full outer join B on 条件

-- 查询哪些部门有员工,哪些部门没有

select *
from dept3
left join emp3
on dept3.deptno = emp3.dept_id;

-- 查询哪些员工有对应的部门
select *
from dept3
right join emp3
on dept3.deptno = emp3.dept_id;

-- Union关键词的使用

select *
from dept3
left join emp3
on dept3.deptno = emp3.dept_id
union
select *
from dept3
right join emp3
on dept3.deptno = emp3.dept_id;

四、子查询

简介

即select功能的嵌套

– 查询年龄最大的员工信息,显示细节

/* 即为下面两个查询的嵌套
1,查询最大年龄
select max(age)
from emp3;

2.查询年龄为最大年龄的员工信息
select *
from emp3
where age = ();
*/

–>

select *
from emp3
where age = (
    select max(age)
    from emp3
);
-- 查询研发部和销售部的员工信息
-- 方式1,关联查询
select *
from dept3 a join emp3 b
on a.deptno = b.dept_id and (name = '销售部' or name = '研发部');

-- 方式2,子查询
-- 1. 查询研发部和销售部的部门号
select deptno
from dept3
where name = '销售部' or name = '研发部';
-- 2. 查询哪个员工部门号为~
select *
from emp3
where dept_id in (
    select deptno
from dept3
where name = '销售部' or name = '研发部'
    );

-- 查询人事部20岁以下的员工信息
-- 1.关联查询
select *
from dept3 a join emp3 b
on a.deptno = b.dept_id
and (name = '人事部' and age<20);
-- 2.子查询

select *
from emp3
where age <= 20
and dept_id = (
    select deptno
    from dept3
    where name = '人事部'
    );

子查询关键字

  1. ALL

  2. ANY

  3. SOME

  4. IN

  5. EXISTS

-- 关键词ALL
/*格式
  select ... from ... where c > all(查询语句)
  等价于
  select ... from ... where c > result1 and c > result2 and ...
*/

/*介绍
  表示比较对于每个元素都成立
*/

select *
from dept3;
-- 1. 查询年龄大于'1001'部门所有年龄的员工信息
select *
from emp3
where age >= all (select age from emp3 where dept_id = 1001);
-- 2.查询不属于任何一个部门的员工信息

select *
from emp3
where dept_id != all (select deptno from dept3);



-- 关键词ANY和SOME
/*格式
sel ... from ...  where c > any(查询语句)
*/

/*特点
  SOME与ANY效果等同
  与查询语句中的每一个元素作比较,只要有一个成立就会返回True
*/

-- 操作 查询年龄大于1001 部门任意一个员工年龄的员工信息
select *
from emp3
where age > any (select age from emp3 where dept_id = 1001);



-- 关键词IN
/*格式
sel ... from ... where c in (...)
*/

-- 介绍
/*
判断某个值是否在指定的集合内
*/

-- 操作 查询研发部和销售部的员工信息
select eid,ename
from emp3 where dept_id in (select deptno from dept3 where name = '研发部' or name = '销售部');

-- 关键词 EXISTS
/*格式
select ... from ... where exists(...)
*/

/*特点
至少有一行数据返回True
没有则返回False
* EXISTS关键字比IN关键字运算效率高,尽量使用
*/

-- 查询公司是否有大于60岁的员工,有则输出
select *
from emp3 a
where exists(
    select * from emp3 b where a.age > 30
    );

-- 查询有所属部门的员工信息

select *
from emp3 a
where exists(
    select * from dept3 b where a.dept_id = b.deptno
          );

五、自关联查询

将一个表当作多个表使用

自己与自己相关联,叫做自关联查询

格式

 select 字段列表 from 表1 a, 表1 b where 条件

操作

-- 创建表,并且建立自关连约束
create table t_sanguo(
    eid int primary key ,
    ename varchar(20) ,
    manager_id int,
    foreign key (manager_id) references t_sanguo (eid)
);

-- 操作
insert into t_sanguo values(1,'刘协',NULL);
insert into t_sanguo values(2,'刘备',1);
insert into t_sanguo values(3,'关于',2);
insert into t_sanguo values(4,'张飞',2);
insert into t_sanguo values(5,'曹操',1);
insert into t_sanguo values(6,'虚竹',5);
insert into t_sanguo values(7,'典韦',5);
insert into t_sanguo values(8,'孙权',1);
insert into t_sanguo values(9,'周瑜',8);
insert into t_sanguo values(10,'鲁肃',8);

select *
from t_sanguo;

-- 进行关联查询
-- 1.查询每个人物及其上级信息
select a.ename,b.ename
from t_sanguo a, t_sanguo b
where a.manager_id = b.eid;

-- 2.查询上级以及上级的上级
select a.ename,b.ename,c.ename
from t_sanguo a
left join t_sanguo b on a.manager_id = b.eid
left join t_sanguo c on b.manager_id = c.eid;

一、多表关系

多表关系

1.一对一关系

一对一关系很少见,遇到一对一关系最好是合并表

在任意表中添加唯一外键,指向另一张表的主键

2.一对多/多对一关系

原则 在多的一方建立外键,指向另一个的主键

3.多对多关系

多对多关系的实现需要借助中间表,中间表包含两个字段

将多对多关系拆成一对多关系

中间表至少有两个外键,这两个外键分别指向原来两张表的主键

外键约束

1.简介

  • 外键约束常与主键约束一起使用
  • 对于两个关联关系的表而言,相关联字段中主键所在表为主表,外键为子表
  • 外键用来建立主从表的关联关系,建立链接,约束两个表中数据的一致性和完整性

2.规则

  • 主表必须存在
  • 主表必须有主键
  • 主键不能包含空值,但允许在外键中出现空值
  • 主表表名后指定列名(组合).必须为主键的主表/候选键
  • 外键中列的数目必须和主键中列的数目相同
  • 外键中列的数据类型必须和主表中对应列的数据类型相同

二、多表操作

1.设置外键约束

-- 例1.创建表时设置外键约束
-- 创建部门表
create table if not exists
dept(
    deptno varchar(20) primary key , -- 部门号
    name varchar(20) -- 部门名字
);



-- 创建员工表
create table if not exists emp(
    eid varchar(20) primary key  key , -- 员工编号
    ename varchar(20), -- 员工名字
    age int, -- 员工年龄
    dept_id varchar(20), -- 员工部门
    constraint enp_fk foreign key (dept_id) references dept (deptno) -- 外键约束
);

-- 例2.创建表后设置外键约束
create table if not exists dept2(
    deptno varchar(20) primary key , -- 部门号
    name varchar(20) -- 部门名字
);

-- 创建员工表
create table if not exists emp2(
    eid varchar(20) primary key  key , -- 员工编号
    ename varchar(20), -- 员工名字
    age int, -- 员工年龄
    dept_id varchar(20) -- 员工部门
);

-- 创建外键约束
alter table emp2
add constraint dept_id_fk
foreign key (dept_id)
references dept2(deptno);

2.数据添加

/*
1.必须先给主表添加数据
2.给从表添加数据时,外键列的值必须依赖主表的主键列
*/
-- 给主表添加数据
insert into dept values('1001','研发部');
insert into dept values('1002','销售部');
insert into dept values('1003','财务部');
insert into dept values('1004','人事部');

-- 添加从表数据
insert into emp values('1','张三丰',20,'1001');
insert into emp values('2','马保国',21,'1001');
insert into emp values('3','蔡徐坤',26,'1001');
insert into emp values('4','李毅',44,'1002');
insert into emp values('5','田三川',20,'1002');
insert into emp values('6','张志硕',19,'1004');

3.数据删除

/*注意
  1.主表数据被从表依赖时,不能删除
  2.从表的数据可以随便删除
*/

delete
from dept
where deptno = '1004';
-- [23000][1451] Cannot delete or update a parent row: a foreign key constraint fails (`mydb3`.`emp`, CONSTRAINT `enp_fk` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`deptno`))

delete
from dept
where deptno = '1003'; -- 删除成功

delete
from emp
where eid = '6'; -- 删除成功

4.删除外键约束

/*用于删除外键约束
  alter table <表名> drop foreign key <外键名>;
*/

-- 实现
alter table emp drop foreign key dept_id_fk;

5.多对多关系

/*
多对多关系需要建立中间表
*必须先建立两侧主表
*/
-- 操作
-- |学生表|中间表|课程表|
-- 1.创建学生表
create table if not exists student(
    sid int primary key auto_increment,
    name varchar(20),
    age int,
    gender varchar(20)
);

-- 2.创建课程表course(右侧主表)
create table course(
    cid int primary key auto_increment,
    cidname varchar(20)
);

-- 3.创建中间表student_course/score(从表)
create table score(
    sid int,
    cid int,
    score double,
    constraint enp_fks foreign key (sid) references student(sid),
    constraint enp_fkc foreign key (cid) references course(cid)
);

drop table score;

三、多表联合查询

用于同时查询多个表

  • 交叉连接查询

  • 内连接查询

  • 外连接查询

  • 子查询

  • 表自关联

交叉连接查询

  • 交叉连接查询返回被连接的两个表所有数据行的笛卡尔积

  • A表m行 B表n行 返回m*n条查询 根据需要自行筛选

格式

select * from 表1,表2,表3…

select *
from dept3,emp3;
# 可用 where deptno = dept_id #筛选出部门匹配的数据

内连接查询

内连接查询求多张表的交集

隐式内连接查询

select * from A,B where 条件;

显示内连接查询

select * from A inner join B on 条件;

-- 例,查询每个部门的所属员工
-- 隐式
select *
from dept3,emp3
where dept3.deptno = emp3.dept_id;

-- 显式
select *
from dept3
inner join emp3
on dept3.deptno= emp3.dept_id;

-- 查询每个部门的所属员工
-- 隐式
select *
from dept3 a,emp3 b
where b.dept_id=a.deptno; #别名用法 也可不用
-- 显式 将','替换为 inner join (inner可省略)
select *
from dept3 a inner join emp3 b
where b.dept_id=a.deptno;
-- 查询研发部以及销售部的所属员工
select *
from dept3 a inner join emp3 b
on a.deptno = b.dept_id;
-- 查询每个部门的员工数,并升序排序
select a.name,a.deptno,count(*)
from dept3 a join emp3 b
on a.deptno = b.dept_id
group by a.deptno;
-- 查询人数大于等于三的部门,并按照人数降序排序
select
       a.deptno,
       a.name,
       count(*) as total_cnt
from dept3 a join emp3 b on a.deptno = b.dept_id
group by  a.deptno,a.name
having total_cnt >= 3;

外连接查询

外连接查询分为左外,右外,满外查询

分别输出左,右,全的内容

两表相交的部分输出,不相交的部分输出NULL

– MySQL对满外查询的支持不好,故常使用Union关键词

左外连接

select * from A left outer join B on 条件

右外连接

select * from A right outer join B on 条件

满外连接

select * from A full outer join B on 条件

-- 查询哪些部门有员工,哪些部门没有

select *
from dept3
left join emp3
on dept3.deptno = emp3.dept_id;

-- 查询哪些员工有对应的部门
select *
from dept3
right join emp3
on dept3.deptno = emp3.dept_id;

-- Union关键词的使用

select *
from dept3
left join emp3
on dept3.deptno = emp3.dept_id
union
select *
from dept3
right join emp3
on dept3.deptno = emp3.dept_id;

四、子查询

简介

即select功能的嵌套

– 查询年龄最大的员工信息,显示细节

/* 即为下面两个查询的嵌套
1,查询最大年龄
select max(age)
from emp3;

2.查询年龄为最大年龄的员工信息
select *
from emp3
where age = ();
*/

–>

select *
from emp3
where age = (
    select max(age)
    from emp3
);
-- 查询研发部和销售部的员工信息
-- 方式1,关联查询
select *
from dept3 a join emp3 b
on a.deptno = b.dept_id and (name = '销售部' or name = '研发部');

-- 方式2,子查询
-- 1. 查询研发部和销售部的部门号
select deptno
from dept3
where name = '销售部' or name = '研发部';
-- 2. 查询哪个员工部门号为~
select *
from emp3
where dept_id in (
    select deptno
from dept3
where name = '销售部' or name = '研发部'
    );

-- 查询人事部20岁以下的员工信息
-- 1.关联查询
select *
from dept3 a join emp3 b
on a.deptno = b.dept_id
and (name = '人事部' and age<20);
-- 2.子查询

select *
from emp3
where age <= 20
and dept_id = (
    select deptno
    from dept3
    where name = '人事部'
    );

子查询关键字

  1. ALL

  2. ANY

  3. SOME

  4. IN

  5. EXISTS

-- 关键词ALL
/*格式
  select ... from ... where c > all(查询语句)
  等价于
  select ... from ... where c > result1 and c > result2 and ...
*/

/*介绍
  表示比较对于每个元素都成立
*/

select *
from dept3;
-- 1. 查询年龄大于'1001'部门所有年龄的员工信息
select *
from emp3
where age >= all (select age from emp3 where dept_id = 1001);
-- 2.查询不属于任何一个部门的员工信息

select *
from emp3
where dept_id != all (select deptno from dept3);



-- 关键词ANY和SOME
/*格式
sel ... from ...  where c > any(查询语句)
*/

/*特点
  SOME与ANY效果等同
  与查询语句中的每一个元素作比较,只要有一个成立就会返回True
*/

-- 操作 查询年龄大于1001 部门任意一个员工年龄的员工信息
select *
from emp3
where age > any (select age from emp3 where dept_id = 1001);



-- 关键词IN
/*格式
sel ... from ... where c in (...)
*/

-- 介绍
/*
判断某个值是否在指定的集合内
*/

-- 操作 查询研发部和销售部的员工信息
select eid,ename
from emp3 where dept_id in (select deptno from dept3 where name = '研发部' or name = '销售部');

-- 关键词 EXISTS
/*格式
select ... from ... where exists(...)
*/

/*特点
至少有一行数据返回True
没有则返回False
* EXISTS关键字比IN关键字运算效率高,尽量使用
*/

-- 查询公司是否有大于60岁的员工,有则输出
select *
from emp3 a
where exists(
    select * from emp3 b where a.age > 30
    );

-- 查询有所属部门的员工信息

select *
from emp3 a
where exists(
    select * from dept3 b where a.dept_id = b.deptno
          );

五、自关联查询

将一个表当作多个表使用

自己与自己相关联,叫做自关联查询

格式

 select 字段列表 from 表1 a, 表1 b where 条件

操作

-- 创建表,并且建立自关连约束
create table t_sanguo(
    eid int primary key ,
    ename varchar(20) ,
    manager_id int,
    foreign key (manager_id) references t_sanguo (eid)
);

-- 操作
insert into t_sanguo values(1,'刘协',NULL);
insert into t_sanguo values(2,'刘备',1);
insert into t_sanguo values(3,'关于',2);
insert into t_sanguo values(4,'张飞',2);
insert into t_sanguo values(5,'曹操',1);
insert into t_sanguo values(6,'虚竹',5);
insert into t_sanguo values(7,'典韦',5);
insert into t_sanguo values(8,'孙权',1);
insert into t_sanguo values(9,'周瑜',8);
insert into t_sanguo values(10,'鲁肃',8);

select *
from t_sanguo;

-- 进行关联查询
-- 1.查询每个人物及其上级信息
select a.ename,b.ename
from t_sanguo a, t_sanguo b
where a.manager_id = b.eid;

-- 2.查询上级以及上级的上级
select a.ename,b.ename,c.ename
from t_sanguo a
left join t_sanguo b on a.manager_id = b.eid
left join t_sanguo c on b.manager_id = c.eid;
  • 29
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值