MySQL基础篇--多表操作
一、多表关系
1. 一对一关系
一个学生只有一张身份证;一张身份证只能对应一学生。
在任一表中添加唯一外键,指向另一方主键,确保一对一关系。
一般一对一关系很少见,遇到一对一关系的表最好是合并表。
2. 一对多关系
部门和员工
分析:一个部门有多个员工,一个员工只能对应一个部门
实现原则:在多的一方建立外键,指向一的一方的主键
3. 多对多关系
学生和课程
分析:一个学生可以选择很多门课程,一个课程也可以被很多学生选择。
原则:多对多关系实现需要借助第三张中间表。中间表至少包含两个字段,将多对多的关系,拆成一对多的关系,中间表至少要有两个外键,这两个外键分别指向原来的那两张表的主键。
4. 外键约束
概念:
MySQL 外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表(父表),外键所在的表就是从表(子表)。
外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。比如,一个水果摊,只有苹果、桃子、李子、西瓜等 4 种水果,那么,你来到水果摊要买水果就只能选择苹果、桃子、李子和西瓜,其它的水果都是不能购买的。
①定义外键规则:
- 主表必须已经存在于数据库中,或者是当前正在创建的表。
- 必须为主表定义主键。
- 主键不能包含空值,但允许在外键中出现空值。也就是说,只要外键的每个非空值出现在指定的主键中,这 个外键的内容就是正确的。
- 在主表的表名后面指定列名或列名的组合。这个列或列的组合必须是主表的主键或候选键。
- 外键中列的数目必须和主表的主键中列的数目相同。
- 外键中列的数据类型必须和主表主键中对应列的数据类型相同。
②创建方式:
1)在创建表时设置外键约束
1 [constraint <外键名>] foreign key 字段名 [,字段名2,…] references <主表名> 主键列1 [,主键列2,…]
-- 方式1 create table if not exists emp( eid varchar(20) primary key , -- 员工编号 ename varchar(20), -- 员工名字 age int, -- 员工年龄 dept_id varchar(20), -- 员工所属部门 constraint emp_fk foreign key (dept_id) references dept (deptno) –- 外键约束 );
2)在创建表后设置外键约束
注意:外键约束也可以在修改表时添加,但是添加外键约束的前提是:从表中外键列中的数据必须与主表中主键列中的数据一致或者是没有数据。
1 alter table <数据表名> add constraint <外键名> foreign key(<列名>) references 2 <主表名> (<列名>);
1 -- 方式2 2 -- 创建部门表 3 create table if not exists dept2( 4 deptno varchar(20) primary key , -- 部门号 5 name varchar(20) -- 部门名字 6 ); 7 -- 创建员工表 8 create table if not exists emp2( 9 eid varchar(20) primary key , -- 员工编号 10 ename varchar(20), -- 员工名字 11 age int, -- 员工年龄 12 dept_id varchar(20) -- 员工所属部门 13 14 ); 15 -- 创建外键约束 16 alter table emp2 add constraint dept_id_fk foreign key(dept_id) references dept2 (deptno);
③删除数据:
1 -- 3、删除数据 2 /* 3 注意: 4 1:主表的数据被从表依赖时,不能删除,否则可以删除 5 2: 从表的数据可以随便删除 6 */ 7 delete from dept where deptno = '1001'; -- 不可以删除 8 delete from dept where deptno = '1004'; -- 可以删除 9 delete from emp where eid = '7'; -- 可以删除
④删除外键约束:
当一个表中不需要外键约束时,就需要从表中将其删除。外键一旦删除,就会解除主表和从表间的关联关系
格式:
1 alter table <表名> drop foreign key <外键约束名>;
实现:
1 alter table emp2 drop foreign key dept_id_fk;
⑤外键约束-多对多关系
在多对多关系中,A表的一行对应B的多行,B表的一行对应A表的多行,我们要新增加一个中间表,来建立多对多关系。
1 -- 学生表和课程表(多对多) 2 -- 1 创建学生表student(左侧主表) 3 create table if not exists student( 4 sid int primary key auto_increment, 5 name varchar(20), 6 age int, 7 gender varchar(20) 8 ); 9 -- 2 创建课程表course(右侧主表) 10 create table course( 11 cid int primary key auto_increment, 12 cidname varchar(20) 13 ); 14 15 -- 3创建中间表student_course/score(从表) 16 create table score( 17 sid int, 18 cid int, 19 score double 20 ); 21 22 -- 4建立外键约束(2次) 23 24 alter table score add foreign key(sid) references student(sid); 25 alter table score add foreign key(cid) references course(cid); 26 27 -- 5给学生表添加数据 28 insert into student values(1,'小龙女',18,'女'),(2,'阿紫',19,'女'),(3,'周芷若',20,'男'); 29 -- 6给课程表添加数据 30 insert into course values(1,'语文'),(2,'数学'),(3,'英语'); 31 -- 7给中间表添加数据 32 insert into score values(1,1),(1,2),(2,1),(2,3),(3,2),(3,3);
二、多表查询
数据准备:
1 -- 创建部门表 2 create table if not exists dept3( 3 deptno varchar(20) primary key , 4 name varchar(20) 5 ); 6 7 -- 创建员工表 8 create table if not exists emp3( 9 eid varchar(20) primary key , 10 ename varchar(20), 11 age int, 12 dept_id varchar(20) 13 ); 14 15 insert into dept3 values('1001','研发部'); 16 insert into dept3 values('1002','销售部'); 17 insert into dept3 values('1003','财务部'); 18 insert into dept3 values('1004','人事部'); 19 20 insert into emp3 values('1','乔峰',20, '1001'); 21 insert into emp3 values('2','段誉',21, '1001'); 22 insert into emp3 values('3','虚竹',23, '1001'); 23 insert into emp3 values('4','阿紫',18, '1001'); 24 insert into emp3 values('5','扫地僧',85, '1002'); 25 insert into emp3 values('6','李秋水',33, '1002'); 26 insert into emp3 values('7','鸠摩智',50, '1002'); 27 insert into emp3 values('8','天山童姥',60, '1003'); 28 insert into emp3 values('9','慕容博',58, '1003'); 29 insert into emp3 values('10','丁春秋',71, '1005');
1. 分类
①交叉连接查询 [产生笛卡尔积,了解]
语法:select * from A,B;
②内连接查询(使用的关键字 inner join -- inner可以省略)
隐式内连接(SQL92标准):select * from A,B where 条件;
显示内连接(SQL99标准):select * from A inner join B on 条件;
1 -- 查询每个部门的所属员工 2 select * from dept3,emp3 where dept3.deptno = emp3.dept_id; 3 select * from dept3 inner join emp3 on dept3.deptno = emp3.dept_id; 4 5 -- 查询研发部和销售部的所属员工 6 select * from dept3,emp3 where dept3.deptno = emp3.dept_id and name in( '研发部','销售部'); 7 select * from dept3 join emp3 on dept3.deptno = emp3.dept_id and name in( '研发部','销售部'); 8 9 -- 查询每个部门的员工数,并升序排序 10 select deptno,count(1) as total_cnt from dept3,emp3 where dept3.deptno = emp3.dept_id group by deptno order by total_cnt; 11 12 select deptno,count(1) as total_cnt from dept3 join emp3 on dept3.deptno = emp3.dept_id group by deptno order by total_cnt;
③外连接查询(使用的关键字 outer join -- outer可以省略)
左外连接:left outer join
select * from A left outer join B on 条件;
右外连接:right outer join
select * from A right outer join B on 条件;
满外连接: full outer join
select * from A full outer join B on 条件;
1 -- 外连接查询 2 -- 查询哪些部门有员工,哪些部门没有员工 3 use mydb3; 4 select * from dept3 left outer join emp3 on dept3.deptno = emp3.dept_id; 5 6 -- 查询哪些员工有对应的部门,哪些没有 7 select * from dept3 right outer join emp3 on dept3.deptno = emp3.dept_id; 9 10 -- 使用union关键字实现左外连接和右外连接的并集 11 select * from dept3 left outer join emp3 on dept3.deptno = emp3.dept_id 12 union 13 select * from dept3 right outer join emp3 on dept3.deptno = emp3.dept_id;
④子查询
select的嵌套
特点:子查询返回的数据类型一共分为四种
- 单行单列:返回的是一个具体列的内容,可以理解为一个单值数据;
- 单行多列:返回一行数据中多个列的内容;
- 多行单列:返回多行记录之中同一列的内容,相当于给出了一个操作范围;
- 多行多列:查询返回的结果是一张临时表
1 -- 查询年龄最大的员工信息,显示信息包含员工号、员工名字,员工年龄 2 select eid,ename,age from emp3 where age = (select max(age) from emp3); 4 5 -- 查询年研发部和销售部的员工信息,包含员工号、员工名字 6 select eid,ename,t.name from emp3 where dept_id in (select deptno,name from dept3 where name = '研发部' or name = '销售部') ; 7 9 -- 查询研发部20岁以下的员工信息,包括员工号、员工名字,部门名字 10 select eid,age,ename,name from (select * from dept where name = '研发部 ')t1,(select * from emp3 where age <20)t2
子查询关键字
1.ALL关键字
特点:
- ALL: 与子查询返回的所有值比较为true 则返回true
- ALL可以与=、>、>=、<、<=、<>结合是来使用,分别表示等于、大于、大于等于、小于、小于等于、不等于子查询其中的所有数据。
- ALL表示指定列中的值必须要大于子查询集的每一个值,即必须要大于子查询集的最大值;如果是小于号即小于子查询集的最小值。同理可以推出其它的比较运算符的情况。
1 -- 格式 2 select …from …where c > all(查询语句) 3 --等价于: 4 select ...from ... where c > result1 and c > result2 and c > result3 5 6 --实现 7 -- 查询年龄大于‘1003’部门所有年龄的员工信息 8 select * from emp3 where age > all(select age from emp3 where dept_id = '1003'); 9 -- 查询不属于任何一个部门的员工信息 10 select * from emp3 where dept_id != all(select deptno from dept3);
2.ANY/SOME关键字
特点:
- ANY:与子查询返回的任何值比较为true 则返回true
- ANY可以与=、>、>=、<、<=、<>结合是来使用,分别表示等于、大于、大于等于、小于、小于等于、不等于子查询其中的任何一个数据。
- 表示制定列中的值要大于子查询中的任意一个值,即必须要大于子查询集中的最小值。同理可以推出其它的比较运算符的情况。
- SOME和ANY的作用一样,SOME可以理解为ANY的别名
1 -- 格式 2 select …from …where c > any(查询语句) 3 --等价于: 4 select ...from ... where c > result1 or c > result2 or c > result3 5 6 -- 实现 7 select * from emp3 where age > any(select age from emp3 where dept_id = '1003');
3.IN关键字
特点:
- IN关键字,用于判断某个记录的值,是否在指定的集合中
- 在IN关键字前边加上not可以将条件反过来
1 -- 格式 2 select …from …where c in(查询语句) 3 --等价于: 4 select ...from ... where c = result1 or c = result2 or c = result3 5 6 -- 实现 7 -- 查询研发部和销售部的员工信息,包含员工号、员工名字 8 select eid,ename,t.name from emp3 where dept_id in (select deptno from dept3 where name = '研发部' or name = '销售部') ;
4.EXISTS关键字
特点:
该子查询如果“有数据结果”(至少返回一行数据), 则该EXISTS() 的结果为“true”,外层查询执行
该子查询如果“没有数据结果”(没有任何数据返回),则该EXISTS()的结果为“false”,外层查询不执行
EXISTS后面的子查询不返回任何实际数据,只返回真或假,当返回真时 where条件成立
注意,EXISTS关键字,比IN关键字的运算效率高,因此,在实际开发中,特别是大数据量时,推荐使用EXISTS关键字
1 -- 格式 2 select …from …where exists(查询语句) 3 4 -- 方式 5 -- 查询公司是否有大于60岁的员工,有则输出 6 select * from emp3 a where exists(select * from emp3 b where a.age > 60); 7 8 -- 查询有所属部门的员工信息 9 select * from emp3 a where exists(select * from dept3 b where a.dept_id = b.deptno);
表自关联
将一张表当成多张表来用
概念:
MySQL有时在信息查询时需要进行对表自身进行关联查询,即一张表自己和自己关联,一张表当成多张表来用。注意自关联时表必须给表起别名。
1 -- 创建表,并建立自关联约束 2 create table t_sanguo( 3 eid int primary key , 4 ename varchar(20), 5 manager_id int, 6 foreign key (manager_id) references t_sanguo (eid) -- 添加自关联约束 7 ); 8 9 10 -- 格式 11 select 字段列表 from 表1 a , 表1 b where 条件; 12 或者 13 select 字段列表 from 表1 a [left] join 表1 b on 条件; 14 15 -- 实现 16 -- 进行关联查询 17 -- 1.查询每个三国人物及他的上级信息,如: 关羽 刘备 18 select * from t_sanguo a, t_sanguo b where a.manager_id = b.eid;
图解: