多表关系和多表查询
1.0 一对多
表与表之间也存在关系,有一对一,一对多,多对多三种,比如部门表中的一个部门,对应着员工表中的多个员工
,这就是一对多的关系,我们将多的一方称作子表,比如上面的员工表,一的一方称为父表,想要实现这种关联关
系,需要在子表中添加外键字段去关联父表的主键
添加外键的语句:
alter table emp add constraint fk_emp_dept_id foreign key(dept_id) references dept(id);
当我们添加外键关系后,如果想删除主表的字段,必须要先把与其关联的子表的字段完全删除后才能正常删除
我们这里添加的是物理外键,使用物理外键会导致查询效率降低等问题,我们实际一般使用逻辑外键,瑞吉晚间不
加外键约束
实际我们将外键关系的内容写在Java代码中实现,相比直接使用外键约束更优
1.1 一对一
一对一的一个例子就是用户和身份证,一般利用一对一的关系对单表进行切分,在数据库中想要实现这种关系需要
在任意一方加入外键,关联另一方的主键,并将外键字段设置为唯一
1.2 多对多
想要实现多对多的关系,在两张表任意一张加外键都是不可取的,此时需要创建第三张表,来存储这两张表的对应
关系,第三张表中设置外键关系,与另外两张表相关联
1.3 多表查询
一次查询多张表就是多表查询,最简单的多表查询如下
select * from dept,emp;
查出来的表项个数是两个表的数据数量的乘积,第一张的每一条和另一张表的任意一条组成了查询出来的一个表项
如果这两张表是有外键关联关系的,我们这样查出来的表项肯定很多是无效的,我们要做到的就是消除无效的笛卡
尔积
这时候就需要根据外键关系做过滤了
select emp.id ,emp.username from dept,emp where emp.dept_id = dept.id;
注意,我们表明字段的时候需要具体指定是哪个表中的字段
多表查询方式分为连接查询和子查询
1.3.1 连接查询
连接查询分为内连接和外连接
内连接就是通过条件求两个表的交集,
内连接(INNER JOIN)和外连接(OUTER JOIN)的主要区别:
- 返回行的范围
- 内连接:只返回两边都有匹配记录的行(交集)。
- 外连接:保留一方或双方的所有行,未匹配的列用
NULL
填充。分为左外连接(LEFT JOIN
)、右外连接(RIGHT JOIN
)和全外连接(FULLJOIN
)。
- 常见使用场景
- 想要只看匹配关系,使用内连接。
- 想要保留主表所有记录(即使没有匹配),使用左/右外连接;想保留两边所有记录,使用全外连接。
内连接分为隐式内连接和显式内连接,我们上面这种直接加表名接条件的是隐式内连接
我们这里看一下怎么实现显示内连接:
select emp.id ,emp.username from dept inner join emp on emp.dept_id = dept.id;
inner join 后添加内连接的第二个表,on 后面添加条件,inner可以省略
隐式和显示没什么区别两个表的先后顺序也可也替换,但是需要注意,on后面只能跟一个条件,如果还需要加条
件,不能像之前where查询那样直接用and拼接,应该再接where来表明条件,虽然这样比较麻烦,但是on在这里
是必须的,不可省略
接下来看一下外连接,外连接分为左外连接和右外连接,二者可以相互转化,我们一般使用左外连接
select emp.* ,dept.name from emp left join dept on emp.id=dept.id;
此时若是存在没有匹配的emp表项,因为是左外连接也会显示,只不过因为查询不到dept的表项,所以
dept.name会显示null,如果想要再加条件同样也要使用where进行添加
1.3.2 子查询
子查询就是在语句当中做条件判断时出现select查询的查询语句,外层查询是select ,还是其他方式都无所谓,内
部需要进行select查询
下面是一个例子:
select * from emp where entry_data =(select min(entry_data) from emp );
当前查询出的是一个子项,被称作标量子查询
如果我们一次查出来的是一列数据,则被称为列子查询
select * from emp where dept_id in (select id from dept where name ='摸鱼部'or name ='行政部');
这就是一个典型的列子查询,我们通过in 来作为判断条件 只要dept_id在这个括号里面就满足条件
写开就是 dept_id in (2,3)
如果我们查出来的是一行呢,这就是行子查询
select * from emp where (salary,job) =(select salary,job from emp where name='小明');
如果查询出来的数据是一个表,我们利用这个表进行判断,这种查询叫做表子查询
select * from (select * from emp where entry_data >'2000-01-01') t1 ,dept where t1.dept_id=dept.id;
这样写其实是复杂了,简化后为
select * from dept,emp where entry_data>'2000-01-01' and dept_id=dept.id;