oracle数据库:表连接
Posted 谦谦均
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle数据库:表连接相关的知识,希望对你有一定的参考价值。
表连接介绍
当我们获取的数据不是来自于同一张表,而是来自于多张表时,就需要使用到表连接。表连接就是一个表的行根据指定的条件与另一个表的行连接起来形成新的行的过程。
简单来说,我们将数据存在不同的表中,而不同的表有着它们自身的表结构,不同表之间可以有关联,大部分实际应用中,不会仅仅只需要一张表的信息,比如需要从一个班级表中找出北京地区的学生,再用这个信息去检索成绩表中找他们的数学成绩,如果没有多表连接,那只能手动将第一个表的信息查询出来之后作为第二个表的检索信息去查询最终的结果,可想而知这个过程很繁琐。
连接查询
- 即查询的时候需要多张表(特别是存在外键关系的),这时需要多张表之间的值进行连接;
- 目前
SQL
标准提出过两种连接查询,第一种是较早的SQL92
标准,第二种是目前使用广泛的较新的SQL99
标准 92
形式简单,但是编写较为冗长,99不仅在底层上得到优化,而且形式上看上去更加一目了然,逻辑性更强,一般建议使用99
标准。
92语法
多张表需要全部放在from
之后,所有的连接条件都放在where
当中,因此SQL92中的等值连接、非等值连接、外连接等等其实只是where
条件的筛选
结构: select ... from table1,table2,table3,... where ...
很多时候需要为表取别名(1,简化表名 2,可能存在自连接的情况)
连接的原理:按照from
后面表的出现顺序,前面的表作为内存的for
循环,后出现的表作为外层的for
循环
笛卡尔积
学过线性代数的人就知道,笛卡尔积通俗的说,就是两个集合中的每一个成员,都与对方集合中的任意一个成员有关联。
例如有一个考勤记录表,记录着100个人2020年4月份的考勤信息,理论上这些人每天都有记录的,但是实际上某些人在某些天上面的数据缺少了。要找出缺少的数据,一天一天的查询或者一个一个人的查询,都有些麻烦,这种情况下,可以针对每个人与每一天做一个笛卡尔积处理,然后与实际的表取关联,就很容易查询出结果来了。
select ... from t1,t2
这里先准备一下需要的数据:学生表stu、班级表cla
、
--创建学生表
create table stu(
name varchar(20),
age number(3),
sex varchar(10)
);
--往学生表里面添加数据
insert into stu values('赵丽颖',22,'女');
insert into stu values('迪丽热巴',24,'女');
insert into stu values('杨紫',23,'女');
--创建班级表
create table cla(
cla_num number(2),
cl_name varchar(20)
);
--往班级表里面添加数据
insert into cla values(11,'七年级一班');
insert into cla values(12,'七年级二班');
insert into cla values(21,'八年级一班');
insert into cla values(22,'八年级二班');
数据内容如下图所示:
stu表
cla表
接下来看一下这两个表实现笛卡尔积:
select * from stu,cla;
这里同时查询两个表中的所有数据
可以看到数据是两个表数据的组合,变成了3*4=12
条数据的表格
等值连接
在笛卡尔的基础上取条件列相同的值,就是等值连接。这里对上面的数据进行修改,让他们有一个相同的列:
alter table stu add (cla_num number(2));
update stu set cla_num = 11 where name = '赵丽颖';
update stu set cla_num = 12 where name = '迪丽热巴';
update stu set cla_num = 21 where name = '杨紫';
查询一下stu表
看一下内容:
接下来查询一下每一个学生的信息以及所在班级的信息
- 查询的数据:
学生信息
,班级信息
- 数据来源:
stu表和cla表
- 连接条件:
stu.cla_num = cla.cla_num
。就是两个表里面的这个字段内容一样。【如果没有条件就是笛卡尔积】
--查询一下每一个学生的信息以及所在班级的信息
select * from stu s,cla a where s.cla_num = a.cla_num;
这里顺便将表起了一个别名,分别是s
和a
,后面判断两个表中的字段要一样,来看一下结果:
我们继续往stu
里面添加几条数据:
insert into stu values('周杰伦',24,'男',11);
insert into stu values('彭于晏',23,'男',12);
insert into stu values('胡歌',22,'男',22);
insert into stu values('貂蝉',18,'女',12);
insert into stu values('王昭君',19,'女',21);
这是表中的数据如下图所示:
接下来来做一个小例子:查询出每一个有学生存在【这里都存在】的班级和班级的人数。
- 查询数据:班级信息,对应班级的学生人数
- 数据来源:
stu
,cla
经过计算得到 - 连接条件:班级序号相等
第一步,先查询每个班级号对应的有多少个学生
--查询有学生的班级的学生人数:
select count(*),cla_num from stu group by cla_num;
结果如下:
可以看到每个班级号对应的有多少个学生。接下来使用上面的结果集表来进行查询
select * from cla c,(select count(*),cla_num from stu group by cla_num) b where c.cla_num = b.cla_num;
这里给结果集表取了一个别名为b
,方便后面进行where
条件判断
非等值连接
非等值连接常用运算符:
!=,>,<,<>,between and
为了演示非等值连接的例子,这里需要添加一个字段,以及一个新的表grade
,表示成绩等级
--添加成绩字段
alter table stu add (gra_num number(3));
--添加成绩
update stu set gra_num = 89 where name = '赵丽颖';
update stu set gra_num = 99 where name = '迪丽热巴';
update stu set gra_num = 67 where name = '胡歌';
update stu set gra_num = 58 where name = '周杰伦';
update stu set gra_num = 72 where name = '迪丽热巴';
update stu set gra_num = 100 where name = '王昭君';
update stu set gra_num = 69 where name = '彭于晏';
update stu set gra_num = 70 where name = '貂蝉';
update stu set gra_num = 86 where name = '杨紫';
--创建成绩等级表
create table grade(
grade varchar(20),
lowgra number(3),
higra number(3)
);
--添加成绩等级表的内容
insert into grade values('完美',100,100);
insert into grade values('优秀',80,99);
insert into grade values('良好',70,79);
insert into grade values('及格',60,69);
insert into grade values('不及格',0,59);
接下来看看两张表的内容:
stu表
grade
表
成绩分为5个等级,如上图所示。
例1:查询学生信息以及成绩的等级,等级来源于等级表
- 查询数据:
name,sex,gra_num,grade
- 数据来源:
stu表和grade表
- 链接条件:
gra_num 在grade表中字段lowgra和higra之间
。
select name,sex,gra_num,grade from stu s,grade g where s.gra_num between lowgra and higra;
这里也用了起别名的方式,后面条件判断分数在哪个等级,就获取等级数,结果如下图所示
外连接
内连接使用比较运算符根据每个表共有的列的值匹配两个表中的行。外连接可以是左向外连接、右向外连接或者完整外部连接。
- 左向外连接的结果集包括left outer子句中指定的左表的所有行,而不仅仅是连接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集中,右表的所有选择列表列均为空值
- 右外连接是左向外连接的反向链接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
这里往班级表里面添加一个数据:
insert into cla values(31,'九年级一班');
这时候我们知道九年级一班是没有学生的。
例:查看每一个学生的信息和班级信息:
select * from cla c,(select count(*),cla_num from stu group by cla_num) b where c.cla_num=b.cla_num;
使用的是内连接的方法,这里因为九年级一班没有人,所以不显示,如下图所示。
有的时候,就算这个班级没有人,但是查询的时候也希望把这个班级显示出来,有班级但是没有人和没有这个班级是两回事,这时需要用到外连接。
外连接有个主表的概念,只要在主表中出现的结果,就必须出现在结果集中。【看+号,带+号的表为从表,对立面的表为主表
】
例:查看每一个班级的信息,对应的学生数
- 查询的数据:
班级信息,班级人数
- 数据来源:
cla,结果集表
- 连接条件:
cla_num相等
- 主表:
班级表
,从表:学生表
select * from cla c,(select count(*),cla_num from stu group by cla_num) b where c.cla_num = b.cla_num(+);
这里在结果集表后面加了(+)
,表示这个是从表
,主表是cla表
这里可以看到,所有班级都显示出来了,没有学生的班级里自动为空。
如果想给空值设置为0
,可以使用nvl函数
select c.cla_num,cl_name,nvl(cc,0) cou from cla c,(select count(*) cc,cla_num from stu group by cla_num) b where c.cla_num = b.cla_num(+);
这里给count(*)
起别名为cc,然后使用nvl函数,如果count(*)
的返回值是空,就用0替换,然后给这个列起别名为cou。
可以看到原本是空的值变成了0,更方便我们阅读结果。
扩展练习:在stu表添加一个数据,但是没有班级信息,然后查询所有学生信息和他所在的班级信息,没有班级的用‘没有班级’代替空值。这里不演示了,跟上面的例子很像。
自连接
特殊的等值交换,数据来源于同一张表。
为了演示这个自连接效果,给stu
表里面添加两个字段,一个是学生编号
,一个是组长编号
,分别为stu_num,group_num
,每个学生都有学生编号,但是并不是每个人都有组长。
--添加学生id字段
alter table stu add(stu_num number(2));
--给学生添加学生id
update stu set stu_num = 1 where name = '赵丽颖';
update stu set stu_num = 2 where name = '迪丽热巴';
update stu set stu_num = 3 where name = '杨紫';
update stu set stu_num = 4 where name = '周杰伦';
update stu set stu_num = 5 where name = '彭于晏';
update stu set stu_num = 6 where name = '胡歌';
update stu set stu_num = 7 where name = '貂蝉';
update stu set stu_num = 8 where name = '王昭君';
--添加组长字段
alter table stu add(group_num number(2));
update stu set group_num = 1 where name = '周杰伦';
update stu set group_num = 2 where name = '彭于晏';
update stu set group_num = 3 where name = '胡歌';
update stu set group_num = 8 where name = '貂蝉';
添加完之后查看一下stu表
的内容:
分别是学生编号与各自组长的编号,当然组长自己没有组长。
现在数据有了,来做一个例子:查询出每一个学生【有组长存在的学生】自己的信息,以及他组长的信息。
- 查询的数据:
学生自己的信息,组长的信息
- 数据来源:
stu表 s1
,stu表 s2
- 连接条件:
s1.stu_num = s2.group_num
select * from stu s1,stu s2 where s1.stu_num = s2.group_num;
这里必须起别名,不然会报错。来看一下结果:
自连接一般用来处理同一张表里面拥有不同身份的人之间的查询处理。
99语法
cross join
交叉连接,实现笛卡尔积。natural join
自然连接,做等值连接(需要有同名列,主外键)join using
等值连接【同名列】join on on
连接,可做等值连接,非等值连接,自连接,可以解决一切连接,关系列必须要区分outer join
外连接,有主从表的区别full join on | using
全连接,满足则直接匹配,不满足的相互补充null
,确保所有的表记录都至少出现一次
例1:99标准
实现笛卡尔积
这里为了让结果少一点,使用的是cla表
和grade表
--99标准实现笛卡尔积
select * from cla cross join grade;
结果如下图:
例2,99标准实现等值连接:查看所有学生的姓名,年龄,性别,所属班级,班级名称
- 要查询的数据:查看所有学生的姓名,年龄,性别,所属班级,班级名称
- 数据来源:
stu表
和cla表
- 连接条件:
stu.cla_num = cla.cla_num
99标准
可以使用自然连接实现natural join
select name,age,sex,cla_num,cl_name from stu natural join cla;
这里不需要使用连接条件,因为99标准
使用了natural join
后会自动找同名的列或者主外键
例:join using
也能做等值连接,这时需要有同名列。
select name,age,sex,cla_num,cl_name from stu join cla using (cla_num);
这里主要注意语法格式,using
后面接同名列,表示通过哪个列来进行连接。
99标准小结:
corss join
交叉连接【这个没啥好说的,就是笛卡尔积】natural join
必须有同名列,存在主外键关系(就一个同名列):可以做等值连接join using
必须有同名列,不需要主外键,可以有多个同名列,使用using指定使用的同名列:等值连接
例:查询班级号是12
的所有学生姓名,班级编号,班级名称
1,自然连接实现:
--自然连接实现
select name,cla_num,cl_name from stu natural join cla where cla_num = 12;
2,suing
连接实现:
--using连接实现
select name,cla_num,cl_name from stu join cla using(cla_num) where cla_num = 12;
结果都一样,如下图所示:
例:jion on
实现非等值连接:
查询所有学生的姓名,学号,所属班级编号,班级名称
- 查询的数据:学生的姓名,学号,所属班级编号,班级名称
- 数据来源:
stu表
和cla表
- 连接条件:
stu.cla_num = cla.cla_num
--jion on 实现非等值连接:
select name,stu_num,s.cla_num,cl_name from stu s join cla c on s.cla_num = c.cla_num;
这里使用的是join on
来实现等值连接
这里有个小知识点,如果使用的是自然连接或者using
连接,同名列不需要加限定词,因为会自动找同名列。如果使用的是join on
,则需要加限定词。
例:jion on
实现非等值连接
查看每一个学生的姓名,成绩,年龄,成绩等级
select name,age,gra_num,grade from stu join grade on gra_num between lowgra and higra;
看一下结果:
例:查询12
班级学生姓名,年龄,班级编号,成绩等级,班级名称
- 查询的数据:
学生姓名
,年龄
,班级编号
,成绩等级
,班级名称
- 数据来源:
stu,cla,grade
- 连接条件:
gra_num between lowgra and higra, stu.cla_num = cla.cla_num
.
--查询12班级学生姓名,年龄,班级编号,成绩等级,班级名称
select name,age,s.cla_num,grade,cl_name from stu s
join cla c on s.cla_num = c.cla_num
join grade g on s.gra_num
between g.lowgra and g.higra;
这里每个第二个join
前面可以当成一张结果表,跟join
后面的表进行连接
可以正确查询所需要的数据。
例:查看每一个学生编号,学生名称,组长编号,组长名称【outer join
】
- 查询数据:
学生编号
,学生名称
,组长编号
,组长名称
- 数据来源:
stu s1
,stu s2
- 连接条件:
s1.stu_num = s2.group_num
on
连接实现 外连接
select s1.stu_num,s1.name,s1.group_num,s2.stu_num from stu s1 left outer join stu s2 on s1.group_num = s2.stu_num;
这里因为主表是第一个stu表
,在join
的左边,所以要指定left
,外连接可以省略outer
,但是这里不省略。
右外连接就是关键字left
换成了个right
,这里不演示。
表连接总结:
- 表连接:当查询的数据来自于多张表时
- 1,笛卡尔积
- 2,等值连接
- 3,非等值连接
- 4,自连接
- 5,外连接(主表)
--92标准:
select ... from table1,table2 where table1.xx1 = table2.xx2 and table1.xx = cc;
select ... from table1,table2 where table1.xx1 = table2.xx2(+);
-- 99标准:
select ... from table1 cross join table2 where ...
select ... from table1 natural join table2 where ...
select ... from table1 join table2 using(同名字段) where ...
select ... from table1 join table2 on 连接条件 where ...
select ... from table1 left/right outer join table2 on 连接条件 where ...
`--全连接`
select ... from table1 full join table2 on 连接条件 where ...
全连接就是两张表都是主表,每个表里面的内容都要出现,没有的用null代替。
以上是关于oracle数据库:表连接的主要内容,如果未能解决你的问题,请参考以下文章